Persist applet cookies to /config/saves
The JSObject stand-in kept cookies in memory, so saves were lost when the game restarted. Write them to a file the session manager can sync, with the policy granting only the agent jar access to that directory.
This commit is contained in:
@@ -37,6 +37,6 @@ Selkies restarts the game when it exits (`RESTART_APP`).
|
|||||||
|
|
||||||
`appletviewer` lacks two things applets got from the browser's Java plugin, so
|
`appletviewer` lacks two things applets got from the browser's Java plugin, so
|
||||||
the image adds them: a `netscape.javascript.JSObject` stand-in whose window has
|
the image adds them: a `netscape.javascript.JSObject` stand-in whose window has
|
||||||
a working `document.cookie`, and a policy allowing HTTP requests through the
|
a `document.cookie` that persists to `/config/saves/cookies.txt`, and a policy allowing HTTP requests through the
|
||||||
game server's proxy. The same jar (`applet-support/`) is loaded as a Java agent
|
game server's proxy. The same jar (`applet-support/`) is loaded as a Java agent
|
||||||
that removes appletviewer's menu bar and status line.
|
that removes appletviewer's menu bar and status line.
|
||||||
|
|||||||
@@ -1,25 +1,37 @@
|
|||||||
package netscape.javascript;
|
package netscape.javascript;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/** A document whose cookie member behaves like document.cookie in a browser. */
|
/**
|
||||||
|
* A document whose cookie member behaves like document.cookie in a browser.
|
||||||
|
* Cookies persist to ~/saves/cookies.txt, one name=value pair per line.
|
||||||
|
*/
|
||||||
class Document extends JSObject {
|
class Document extends JSObject {
|
||||||
|
private final File file = AccessController.doPrivileged(
|
||||||
|
(PrivilegedAction<File>) () -> new File(System.getProperty("user.home"), "saves/cookies.txt"));
|
||||||
private final Map<String, String> cookies = new LinkedHashMap<String, String>();
|
private final Map<String, String> cookies = new LinkedHashMap<String, String>();
|
||||||
|
|
||||||
|
Document() {
|
||||||
|
for (String line : AccessController.doPrivileged((PrivilegedAction<List<String>>) this::read)) {
|
||||||
|
put(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getMember(String name) throws JSException {
|
public Object getMember(String name) throws JSException {
|
||||||
if (!name.equals("cookie")) {
|
if (!name.equals("cookie")) {
|
||||||
return super.getMember(name);
|
return super.getMember(name);
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder();
|
return String.join("; ", lines());
|
||||||
for (Map.Entry<String, String> cookie : cookies.entrySet()) {
|
|
||||||
if (sb.length() > 0) {
|
|
||||||
sb.append("; ");
|
|
||||||
}
|
|
||||||
sb.append(cookie.getKey()).append('=').append(cookie.getValue());
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -28,10 +40,44 @@ class Document extends JSObject {
|
|||||||
super.setMember(name, value);
|
super.setMember(name, value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String pair = String.valueOf(value).split(";", 2)[0];
|
if (put(String.valueOf(value).split(";", 2)[0])) {
|
||||||
int eq = pair.indexOf('=');
|
AccessController.doPrivileged((PrivilegedAction<Void>) this::write);
|
||||||
if (eq > 0) {
|
|
||||||
cookies.put(pair.substring(0, eq).trim(), pair.substring(eq + 1).trim());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean put(String pair) {
|
||||||
|
int eq = pair.indexOf('=');
|
||||||
|
if (eq <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cookies.put(pair.substring(0, eq).trim(), pair.substring(eq + 1).trim());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> lines() {
|
||||||
|
List<String> lines = new ArrayList<String>();
|
||||||
|
for (Map.Entry<String, String> cookie : cookies.entrySet()) {
|
||||||
|
lines.add(cookie.getKey() + "=" + cookie.getValue());
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> read() {
|
||||||
|
try {
|
||||||
|
return file.isFile() ? Files.readAllLines(file.toPath(), StandardCharsets.UTF_8) : new ArrayList<String>();
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Failed to read " + file + ": " + e);
|
||||||
|
return new ArrayList<String>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Void write() {
|
||||||
|
try {
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
Files.write(file.toPath(), lines(), StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Failed to write " + file + ": " + e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
grant {
|
grant {
|
||||||
permission java.net.URLPermission "http:*", "*:*";
|
permission java.net.URLPermission "http:*", "*:*";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
grant codeBase "file:/opt/flashpoint/applet-support.jar" {
|
||||||
|
permission java.util.PropertyPermission "user.home", "read";
|
||||||
|
permission java.io.FilePermission "${user.home}${/}saves", "read,write";
|
||||||
|
permission java.io.FilePermission "${user.home}${/}saves${/}-", "read,write";
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user