* "r/w")</li>
* <li>GET_METADATA *: will return the metadata of all the stories in the
* library (array)</li> *
- * <li>GET_METADATA [luid]: will return the metadata of the story of LUID luid</li>
+ * <li>GET_METADATA [luid]: will return the metadata of the story of LUID
+ * luid</li>
* <li>GET_STORY [luid]: will return the given story if it exists (or NULL if
* not)</li>
* <li>SAVE_STORY [luid]: save the story (that must be sent just after the
private Map<Long, String> commands = new HashMap<Long, String>();
private Map<Long, Long> times = new HashMap<Long, Long>();
private Map<Long, Boolean> wls = new HashMap<Long, Boolean>();
+ private Map<Long, Boolean> bls = new HashMap<Long, Boolean>();
private Map<Long, Boolean> rws = new HashMap<Long, Boolean>();
/**
.getInteger(Config.SERVER_PORT),
Instance.getInstance().getConfig()
.getString(Config.SERVER_KEY));
-
+
setTraceHandler(Instance.getInstance().getTraceHandler());
}
// defaults are positive (as previous versions without the feature)
boolean rw = true;
boolean wl = true;
+ boolean bl = true;
String subkey = "";
String command = "";
}
}
- List<String> whitelist = Instance.getInstance().getConfig().getList(Config.SERVER_WHITELIST);
+ List<String> whitelist = Instance.getInstance().getConfig()
+ .getList(Config.SERVER_WHITELIST);
if (whitelist == null) {
whitelist = new ArrayList<String>();
}
+ List<String> blacklist = Instance.getInstance().getConfig()
+ .getList(Config.SERVER_BLACKLIST);
+ if (blacklist == null) {
+ blacklist = new ArrayList<String>();
+ }
if (whitelist.isEmpty()) {
wl = false;
}
- rw = Instance.getInstance().getConfig().getBoolean(Config.SERVER_RW, rw);
+ rw = Instance.getInstance().getConfig().getBoolean(Config.SERVER_RW,
+ rw);
if (!subkey.isEmpty()) {
- List<String> allowed = Instance.getInstance().getConfig().getList(Config.SERVER_ALLOWED_SUBKEYS);
+ List<String> allowed = Instance.getInstance().getConfig()
+ .getList(Config.SERVER_ALLOWED_SUBKEYS);
if (allowed.contains(subkey)) {
if ((subkey + "|").contains("|rw|")) {
rw = true;
wl = false; // |wl| = bypass whitelist
whitelist = new ArrayList<String>();
}
+ if ((subkey + "|").contains("|bl|")) {
+ bl = false; // |bl| = bypass blacklist
+ blacklist = new ArrayList<String>();
+ }
}
}
- String mode = display(wl, rw);
+ String mode = display(wl, bl, rw);
String trace = mode + "[ " + command + "] ";
for (Object arg : args) {
Object rep = null;
try {
- rep = doRequest(action, command, args, rw, whitelist);
+ rep = doRequest(action, command, args, rw, whitelist, blacklist);
} catch (IOException e) {
rep = new RemoteLibraryException(e, true);
}
commands.put(id, command);
wls.put(id, wl);
+ bls.put(id, bl);
rws.put(id, rw);
times.put(id, (new Date().getTime() - start));
return rep;
}
- private String display(boolean whitelist, boolean rw) {
+ private String display(boolean whitelist, boolean blacklist, boolean rw) {
String mode = "";
if (!rw) {
mode += "RO: ";
if (whitelist) {
mode += "WL: ";
}
+ if (blacklist) {
+ mode += "BL: ";
+ }
return mode;
}
@Override
protected void onRequestDone(long id, long bytesReceived, long bytesSent) {
boolean whitelist = wls.get(id);
+ boolean blacklist = bls.get(id);
boolean rw = rws.get(id);
wls.remove(id);
+ bls.remove(id);
rws.remove(id);
String rec = StringUtils.formatNumber(bytesReceived) + "b";
String sent = StringUtils.formatNumber(bytesSent) + "b";
long now = System.currentTimeMillis();
- System.out.println(StringUtils.fromTime(now)
- + ": "
+ System.out.println(StringUtils.fromTime(now) + ": "
+ String.format("%s[>%s]: (%s sent, %s rec) in %d ms",
- display(whitelist, rw), commands.get(id), sent, rec,
- times.get(id)));
+ display(whitelist, blacklist, rw), commands.get(id),
+ sent, rec, times.get(id)));
commands.remove(id);
times.remove(id);
}
private Object doRequest(ConnectActionServerObject action, String command,
- Object[] args, boolean rw, List<String> whitelist)
- throws NoSuchFieldException, NoSuchMethodException,
- ClassNotFoundException, IOException {
+ Object[] args, boolean rw, List<String> whitelist,
+ List<String> blacklist) throws NoSuchFieldException,
+ NoSuchMethodException, ClassNotFoundException, IOException {
if ("PING".equals(command)) {
return rw ? "r/w" : "r/o";
} else if ("GET_METADATA".equals(command)) {
if ("*".equals(args[0])) {
Progress pg = createPgForwarder(action);
- for (MetaData meta : Instance.getInstance().getLibrary().getMetas(pg)) {
+ for (MetaData meta : Instance.getInstance().getLibrary()
+ .getMetas(pg)) {
metas.add(removeCover(meta));
}
forcePgDoneSent(pg);
} else {
- MetaData meta = Instance.getInstance().getLibrary().getInfo((String) args[0]);
+ MetaData meta = Instance.getInstance().getLibrary()
+ .getInfo((String) args[0]);
MetaData light;
if (meta.getCover() == null) {
light = meta;
metas.add(light);
}
- if (!whitelist.isEmpty()) {
- for (int i = 0; i < metas.size(); i++) {
- if (!whitelist.contains(metas.get(i).getSource())) {
- metas.remove(i);
- i--;
- }
+ for (int i = 0; i < metas.size(); i++) {
+ if (!isAllowed(metas.get(i), whitelist, blacklist)) {
+ metas.remove(i);
+ i--;
}
}
return metas.toArray(new MetaData[0]);
+
} else if ("GET_STORY".equals(command)) {
- MetaData meta = Instance.getInstance().getLibrary().getInfo((String) args[0]);
- if (meta == null) {
+ MetaData meta = Instance.getInstance().getLibrary()
+ .getInfo((String) args[0]);
+ if (meta == null || !isAllowed(meta, whitelist, blacklist)) {
return null;
}
- if (!whitelist.isEmpty()) {
- if (!whitelist.contains(meta.getSource())) {
- return null;
- }
- }
-
meta = meta.clone();
meta.setCover(null);
action.send(meta);
action.rec();
- Story story = Instance.getInstance().getLibrary().getStory((String) args[0], null);
+ Story story = Instance.getInstance().getLibrary()
+ .getStory((String) args[0], null);
for (Object obj : breakStory(story)) {
action.send(obj);
action.rec();
}
} else if ("SAVE_STORY".equals(command)) {
if (!rw) {
- throw new RemoteLibraryException("Read-Only remote library: "
- + args[0], false);
+ throw new RemoteLibraryException(
+ "Read-Only remote library: " + args[0], false);
}
List<Object> list = new ArrayList<Object>();
}
Story story = rebuildStory(list);
- Instance.getInstance().getLibrary().save(story, (String) args[0], null);
+ Instance.getInstance().getLibrary().save(story, (String) args[0],
+ null);
return story.getMeta().getLuid();
} else if ("IMPORT".equals(command)) {
if (!rw) {
- throw new RemoteLibraryException("Read-Only remote library: "
- + args[0], false);
+ throw new RemoteLibraryException(
+ "Read-Only remote library: " + args[0], false);
}
Progress pg = createPgForwarder(action);
- MetaData meta = Instance.getInstance().getLibrary().imprt(new URL((String) args[0]), pg);
+ MetaData meta = Instance.getInstance().getLibrary()
+ .imprt(new URL((String) args[0]), pg);
forcePgDoneSent(pg);
return meta.getLuid();
} else if ("DELETE_STORY".equals(command)) {
if (!rw) {
- throw new RemoteLibraryException("Read-Only remote library: "
- + args[0], false);
+ throw new RemoteLibraryException(
+ "Read-Only remote library: " + args[0], false);
}
Instance.getInstance().getLibrary().delete((String) args[0]);
} else if ("GET_COVER".equals(command)) {
- return Instance.getInstance().getLibrary().getCover((String) args[0]);
+ return Instance.getInstance().getLibrary()
+ .getCover((String) args[0]);
} else if ("GET_CUSTOM_COVER".equals(command)) {
if ("SOURCE".equals(args[0])) {
- return Instance.getInstance().getLibrary().getCustomSourceCover((String) args[1]);
+ return Instance.getInstance().getLibrary()
+ .getCustomSourceCover((String) args[1]);
} else if ("AUTHOR".equals(args[0])) {
- return Instance.getInstance().getLibrary().getCustomAuthorCover((String) args[1]);
+ return Instance.getInstance().getLibrary()
+ .getCustomAuthorCover((String) args[1]);
} else {
return null;
}
} else if ("SET_COVER".equals(command)) {
if (!rw) {
- throw new RemoteLibraryException("Read-Only remote library: "
- + args[0] + ", " + args[1], false);
+ throw new RemoteLibraryException(
+ "Read-Only remote library: " + args[0] + ", " + args[1],
+ false);
}
if ("SOURCE".equals(args[0])) {
- Instance.getInstance().getLibrary().setSourceCover((String) args[1], (String) args[2]);
+ Instance.getInstance().getLibrary()
+ .setSourceCover((String) args[1], (String) args[2]);
} else if ("AUTHOR".equals(args[0])) {
- Instance.getInstance().getLibrary().setAuthorCover((String) args[1], (String) args[2]);
+ Instance.getInstance().getLibrary()
+ .setAuthorCover((String) args[1], (String) args[2]);
}
} else if ("CHANGE_STA".equals(command)) {
if (!rw) {
- throw new RemoteLibraryException("Read-Only remote library: " + args[0] + ", " + args[1], false);
+ throw new RemoteLibraryException(
+ "Read-Only remote library: " + args[0] + ", " + args[1],
+ false);
}
Progress pg = createPgForwarder(action);
- Instance.getInstance().getLibrary().changeSTA((String) args[0], (String) args[1], (String) args[2],
- (String) args[3], pg);
+ Instance.getInstance().getLibrary().changeSTA((String) args[0],
+ (String) args[1], (String) args[2], (String) args[3], pg);
forcePgDoneSent(pg);
} else if ("EXIT".equals(command)) {
if (!rw) {
int min = (Integer) a[0 + offset];
int max = (Integer) a[1 + offset];
int progress = (Integer) a[2 + offset];
-
+
Object meta = null;
if (a.length > (3 + offset)) {
meta = a[3 + offset];
}
-
+
String name = null;
if (a.length > (4 + offset)) {
name = a[4 + offset] == null ? "" : a[4 + offset].toString();
}
-
if (min >= 0 && min <= max) {
pg.setName(name);
public void progress(Progress progress, String name) {
Object meta = pg.get("meta");
if (meta instanceof MetaData) {
- meta = removeCover((MetaData)meta);
+ meta = removeCover((MetaData) meta);
}
-
+
int min = pg.getMin();
int max = pg.getMax();
- int rel = min
- + (int) Math.round(pg.getRelativeProgress()
- * (max - min));
-
+ int rel = min + (int) Math
+ .round(pg.getRelativeProgress() * (max - min));
+
boolean samePg = p[0] == min && p[1] == max && p[2] == rel;
-
+
// Do not re-send the same value twice over the wire,
// unless more than 2 seconds have elapsed (to maintain the
// connection)
- if (!samePg || !same(pMeta[0], meta)
- || !same(pName[0], name) //
+ if (!samePg || !same(pMeta[0], meta) || !same(pName[0], name) //
|| (new Date().getTime() - lastTime[0] > 2000)) {
p[0] = min;
p[1] = max;
return pg;
}
-
+
private boolean same(Object obj1, Object obj2) {
if (obj1 == null || obj2 == null)
return obj1 == null && obj2 == null;
}
}
}
-
+
private MetaData removeCover(MetaData meta) {
MetaData light = null;
if (meta != null) {
light.setCover(null);
}
}
-
+
return light;
}
+
+ private boolean isAllowed(MetaData meta, List<String> whitelist,
+ List<String> blacklist) {
+ if (!whitelist.isEmpty() && !whitelist.contains(meta.getSource())) {
+ return false;
+ }
+
+ if (blacklist.contains(meta.getSource())) {
+ return false;
+ }
+
+ return true;
+ }
}
package be.nikiroo.fanfix.library;
import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.security.KeyStore;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLServerSocketFactory;
-
import org.json.JSONArray;
import org.json.JSONObject;
import be.nikiroo.fanfix.Instance;
import be.nikiroo.fanfix.bundles.Config;
-import be.nikiroo.fanfix.bundles.UiConfig;
import be.nikiroo.fanfix.data.Chapter;
import be.nikiroo.fanfix.data.JsonIO;
import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.data.Paragraph;
import be.nikiroo.fanfix.data.Paragraph.ParagraphType;
import be.nikiroo.fanfix.data.Story;
-import be.nikiroo.fanfix.library.web.WebLibraryServerIndex;
-import be.nikiroo.fanfix.reader.TextOutput;
-import be.nikiroo.utils.CookieUtils;
-import be.nikiroo.utils.IOUtils;
import be.nikiroo.utils.Image;
+import be.nikiroo.utils.LoginResult;
import be.nikiroo.utils.NanoHTTPD;
-import be.nikiroo.utils.NanoHTTPD.IHTTPSession;
import be.nikiroo.utils.NanoHTTPD.Response;
import be.nikiroo.utils.NanoHTTPD.Response.Status;
-import be.nikiroo.utils.TraceHandler;
-import be.nikiroo.utils.Version;
-
-public class WebLibraryServer implements Runnable {
- static private String VIEWER_URL_BASE = "/view/story/";
- static private String VIEWER_URL = VIEWER_URL_BASE + "{luid}/{chap}/{para}";
- static private String STORY_URL_BASE = "/story/";
- static private String STORY_URL = STORY_URL_BASE + "{luid}/{chap}/{para}";
- static private String STORY_URL_COVER = STORY_URL_BASE + "{luid}/cover";
- static private String LIST_URL = "/list/";
- private class LoginResult {
- private boolean success;
+public class WebLibraryServer extends WebLibraryServerHtml {
+ class WLoginResult extends LoginResult {
private boolean rw;
private boolean wl;
- private String wookie;
- private String token;
- private boolean badLogin;
- private boolean badToken;
+ private boolean bl;
- public LoginResult(String who, String key, String subkey,
- boolean success, boolean rw, boolean wl) {
- this.success = success;
+ public WLoginResult(boolean badLogin, boolean badCookie) {
+ super(badLogin, badCookie);
+ }
+
+ public WLoginResult(String who, String key, String subkey, boolean rw,
+ boolean wl, boolean bl) {
+ super(who, key, subkey, (rw ? "|rw" : "") + (wl ? "|wl" : "")
+ + (bl ? "|bl" : "") + "|");
this.rw = rw;
this.wl = wl;
- this.wookie = CookieUtils.generateCookie(who + key, 0);
-
- String opts = "";
- if (rw)
- opts += "|rw";
- if (!wl)
- opts += "|wl";
-
- this.token = wookie + "~"
- + CookieUtils.generateCookie(wookie + subkey + opts, 0)
- + "~" + opts;
- this.badLogin = !success;
+ this.bl = bl;
}
- public LoginResult(String token, String who, String key,
+ public WLoginResult(String cookie, String who, String key,
List<String> subkeys) {
-
- if (token != null) {
- String hashes[] = token.split("~");
- if (hashes.length >= 2) {
- String wookie = hashes[0];
- String rehashed = hashes[1];
- String opts = hashes.length > 2 ? hashes[2] : "";
-
- if (CookieUtils.validateCookie(who + key, wookie)) {
- if (subkeys == null) {
- subkeys = new ArrayList<String>();
- }
- subkeys = new ArrayList<String>(subkeys);
- subkeys.add("");
-
- for (String subkey : subkeys) {
- if (CookieUtils.validateCookie(
- wookie + subkey + opts, rehashed)) {
- this.wookie = wookie;
- this.token = token;
- this.success = true;
-
- this.rw = opts.contains("|rw");
- this.wl = !opts.contains("|wl");
- }
- }
- }
- }
-
- this.badToken = !success;
- }
-
- // No token -> no bad token
- }
-
- public boolean isSuccess() {
- return success;
+ super(cookie, who, key, subkeys,
+ subkeys == null || subkeys.isEmpty());
}
public boolean isRw() {
- return rw;
+ return getOption().contains("|rw|");
}
public boolean isWl() {
- return wl;
+ return getOption().contains("|wl|");
}
- public String getToken() {
- return token;
- }
-
- public boolean isBadLogin() {
- return badLogin;
- }
-
- public boolean isBadToken() {
- return badToken;
+ public boolean isBl() {
+ return getOption().contains("|bl|");
}
}
- private NanoHTTPD server;
private Map<String, Story> storyCache = new HashMap<String, Story>();
private LinkedList<String> storyCacheOrder = new LinkedList<String>();
private long storyCacheSize = 0;
private long maxStoryCacheSize;
- private TraceHandler tracer = new TraceHandler();
+
+ private List<String> whitelist;
+ private List<String> blacklist;
public WebLibraryServer(boolean secure) throws IOException {
- Integer port = Instance.getInstance().getConfig()
- .getInteger(Config.SERVER_PORT);
- if (port == null) {
- throw new IOException(
- "Cannot start web server: port not specified");
- }
+ super(secure);
int cacheMb = Instance.getInstance().getConfig()
.getInteger(Config.SERVER_MAX_CACHE_MB, 100);
setTraceHandler(Instance.getInstance().getTraceHandler());
- SSLServerSocketFactory ssf = null;
- if (secure) {
- String keystorePath = Instance.getInstance().getConfig()
- .getString(Config.SERVER_SSL_KEYSTORE, "");
- String keystorePass = Instance.getInstance().getConfig()
- .getString(Config.SERVER_SSL_KEYSTORE_PASS);
-
- if (secure && keystorePath.isEmpty()) {
- throw new IOException(
- "Cannot start a secure web server: no keystore.jks file povided");
- }
-
- if (!keystorePath.isEmpty()) {
- File keystoreFile = new File(keystorePath);
- try {
- KeyStore keystore = KeyStore
- .getInstance(KeyStore.getDefaultType());
- InputStream keystoreStream = new FileInputStream(
- keystoreFile);
- try {
- keystore.load(keystoreStream,
- keystorePass.toCharArray());
- KeyManagerFactory keyManagerFactory = KeyManagerFactory
- .getInstance(KeyManagerFactory
- .getDefaultAlgorithm());
- keyManagerFactory.init(keystore,
- keystorePass.toCharArray());
- ssf = NanoHTTPD.makeSSLSocketFactory(keystore,
- keyManagerFactory);
- } finally {
- keystoreStream.close();
- }
- } catch (Exception e) {
- throw new IOException(e.getMessage());
- }
- }
- }
-
- server = new NanoHTTPD(port) {
- @Override
- public Response serve(final IHTTPSession session) {
- super.serve(session);
-
- String query = session.getQueryParameterString(); // a=a%20b&dd=2
- Method method = session.getMethod(); // GET, POST..
- String uri = session.getUri(); // /home.html
-
- // need them in real time (not just those sent by the UA)
- Map<String, String> cookies = new HashMap<String, String>();
- for (String cookie : session.getCookies()) {
- cookies.put(cookie, session.getCookies().read(cookie));
- }
-
- List<String> whitelist = Instance.getInstance().getConfig()
- .getList(Config.SERVER_WHITELIST);
- if (whitelist == null) {
- whitelist = new ArrayList<String>();
- }
-
- LoginResult login = null;
- Map<String, String> params = session.getParms();
- String who = session.getRemoteHostName()
- + session.getRemoteIpAddress();
- if (params.get("login") != null) {
- login = login(who, params.get("password"),
- params.get("login"), whitelist);
- } else {
- String token = cookies.get("token");
- login = login(who, token, Instance.getInstance().getConfig()
- .getList(Config.SERVER_ALLOWED_SUBKEYS));
- }
-
- if (login.isSuccess()) {
- if (!login.isWl()) {
- whitelist.clear();
- }
-
- // refresh token
- session.getCookies().set(new Cookie("token",
- login.getToken(), "30; path=/"));
-
- // set options
- String optionName = params.get("optionName");
- if (optionName != null && !optionName.isEmpty()) {
- String optionNo = params.get("optionNo");
- String optionValue = params.get("optionValue");
- if (optionNo != null || optionValue == null
- || optionValue.isEmpty()) {
- session.getCookies().delete(optionName);
- cookies.remove(optionName);
- } else {
- session.getCookies().set(new Cookie(optionName,
- optionValue, "; path=/"));
- cookies.put(optionName, optionValue);
- }
- }
- }
-
- Response rep = null;
- if (!login.isSuccess() && (uri.equals("/") //
- || uri.startsWith(STORY_URL_BASE) //
- || uri.startsWith(VIEWER_URL_BASE) //
- || uri.startsWith(LIST_URL))) {
- rep = loginPage(login, uri);
- }
-
- if (rep == null) {
- try {
- if (uri.equals("/")) {
- rep = root(session, cookies, whitelist);
- } else if (uri.startsWith(LIST_URL)) {
- rep = getList(uri, whitelist);
- } else if (uri.startsWith(STORY_URL_BASE)) {
- rep = getStoryPart(uri, whitelist);
- } else if (uri.startsWith(VIEWER_URL_BASE)) {
- rep = getViewer(cookies, uri, whitelist);
- } else if (uri.equals("/logout")) {
- session.getCookies().delete("token");
- cookies.remove("token");
- rep = loginPage(login, uri);
- } else {
- if (uri.startsWith("/"))
- uri = uri.substring(1);
- InputStream in = IOUtils.openResource(
- WebLibraryServerIndex.class, uri);
- if (in != null) {
- String mimeType = MIME_PLAINTEXT;
- if (uri.endsWith(".css")) {
- mimeType = "text/css";
- } else if (uri.endsWith(".html")) {
- mimeType = "text/html";
- } else if (uri.endsWith(".js")) {
- mimeType = "text/javascript";
- }
- rep = newChunkedResponse(Status.OK, mimeType,
- in);
- } else {
- getTraceHandler().trace("404: " + uri);
- }
- }
-
- if (rep == null) {
- rep = newFixedLengthResponse(Status.NOT_FOUND,
- NanoHTTPD.MIME_PLAINTEXT, "Not Found");
- }
- } catch (Exception e) {
- Instance.getInstance().getTraceHandler().error(
- new IOException("Cannot process web request",
- e));
- rep = newFixedLengthResponse(Status.INTERNAL_ERROR,
- NanoHTTPD.MIME_PLAINTEXT, "An error occured");
- }
- }
-
- return rep;
-
- // Get status: for story, use "luid" + active map of current
- // luids
- // map must use a addRef/removeRef and delete at 0
-
- // http://localhost:2000/?token=ok
-
- //
- // MetaData meta = new MetaData();
- // meta.setTitle("Title");
- // meta.setLuid("000");
- //
- // JSONObject json = new JSONObject();
- // json.put("", MetaData.class.getName());
- // json.put("title", meta.getTitle());
- // json.put("luid", meta.getLuid());
- //
- // return newFixedLengthResponse(json.toString());
- }
- };
-
- if (ssf != null) {
- getTraceHandler().trace("Install SSL on the web server...");
- server.makeSecure(ssf, null);
- getTraceHandler().trace("Done.");
- }
- }
-
- @Override
- public void run() {
- try {
- server.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
- } catch (IOException e) {
- tracer.error(new IOException("Cannot start the web server", e));
- }
+ whitelist = Instance.getInstance().getConfig()
+ .getList(Config.SERVER_WHITELIST, new ArrayList<String>());
+ blacklist = Instance.getInstance().getConfig()
+ .getList(Config.SERVER_BLACKLIST, new ArrayList<String>());
}
/**
new Thread(this).start();
}
- /**
- * The traces handler for this {@link WebLibraryServer}.
- *
- * @return the traces handler
- */
- public TraceHandler getTraceHandler() {
- return tracer;
- }
-
- /**
- * The traces handler for this {@link WebLibraryServer}.
- *
- * @param tracer
- * the new traces handler
- */
- public void setTraceHandler(TraceHandler tracer) {
- if (tracer == null) {
- tracer = new TraceHandler(false, false, false);
- }
-
- this.tracer = tracer;
+ @Override
+ protected WLoginResult login(boolean badLogin, boolean badCookie) {
+ return new WLoginResult(false, false);
}
- private LoginResult login(String who, String token, List<String> subkeys) {
+ @Override
+ protected WLoginResult login(String who, String cookie) {
+ List<String> subkeys = Instance.getInstance().getConfig()
+ .getList(Config.SERVER_ALLOWED_SUBKEYS);
String realKey = Instance.getInstance().getConfig()
.getString(Config.SERVER_KEY);
- realKey = realKey == null ? "" : realKey;
- return new LoginResult(token, who, realKey, subkeys);
+
+ return new WLoginResult(cookie, who, realKey, subkeys);
}
// allow rw/wl
- private LoginResult login(String who, String key, String subkey,
- List<String> whitelist) {
+ @Override
+ protected WLoginResult login(String who, String key, String subkey) {
String realKey = Instance.getInstance().getConfig()
- .getString(Config.SERVER_KEY);
+ .getString(Config.SERVER_KEY, "");
// I don't like NULLs...
- realKey = realKey == null ? "" : realKey;
key = key == null ? "" : key;
subkey = subkey == null ? "" : subkey;
if (!realKey.equals(key)) {
- return new LoginResult(null, null, null, false, false, false);
+ return new WLoginResult(true, false);
}
- // defaults are positive (as previous versions without the feature)
+ // defaults are true (as previous versions without the feature)
boolean rw = true;
boolean wl = true;
-
- if (whitelist.isEmpty()) {
- wl = false;
- }
+ boolean bl = true;
rw = Instance.getInstance().getConfig().getBoolean(Config.SERVER_RW,
rw);
- if (!subkey.isEmpty()) {
- List<String> allowed = Instance.getInstance().getConfig()
- .getList(Config.SERVER_ALLOWED_SUBKEYS);
- if (allowed != null && allowed.contains(subkey)) {
- if ((subkey + "|").contains("|rw|")) {
- rw = true;
- }
- if ((subkey + "|").contains("|wl|")) {
- wl = false; // |wl| = bypass whitelist
- }
- } else {
- return new LoginResult(null, null, null, false, false, false);
- }
- }
- return new LoginResult(who, key, subkey, true, rw, wl);
- }
-
- private Response loginPage(LoginResult login, String uri) {
- StringBuilder builder = new StringBuilder();
-
- appendPreHtml(builder, true);
+ List<String> allowed = Instance.getInstance().getConfig().getList(
+ Config.SERVER_ALLOWED_SUBKEYS, new ArrayList<String>());
- if (login.isBadLogin()) {
- builder.append("<div class='error'>Bad login or password</div>");
- } else if (login.isBadToken()) {
- builder.append("<div class='error'>Your session timed out</div>");
- }
+ if (!allowed.isEmpty()) {
+ if (!allowed.contains(subkey)) {
+ return new WLoginResult(true, false);
+ }
- if (uri.equals("/logout")) {
- uri = "/";
+ if ((subkey + "|").contains("|rw|")) {
+ rw = true;
+ }
+ if ((subkey + "|").contains("|wl|")) {
+ wl = false; // |wl| = bypass whitelist
+ }
+ if ((subkey + "|").contains("|bl|")) {
+ bl = false; // |bl| = bypass blacklist
+ }
}
- builder.append(
- "<form method='POST' action='" + uri + "' class='login'>\n");
- builder.append(
- "<p>You must be logged into the system to see the stories.</p>");
- builder.append("\t<input type='text' name='login' />\n");
- builder.append("\t<input type='password' name='password' />\n");
- builder.append("\t<input type='submit' value='Login' />\n");
- builder.append("</form>\n");
-
- appendPostHtml(builder);
-
- return NanoHTTPD.newFixedLengthResponse(Status.FORBIDDEN,
- NanoHTTPD.MIME_HTML, builder.toString());
+ return new WLoginResult(who, key, subkey, rw, wl, bl);
}
- protected Response getList(String uri, List<String> whitelist)
+ @Override
+ protected Response getList(String uri, WLoginResult login)
throws IOException {
- if (uri.equals("/list/luids")) {
- BasicLibrary lib = Instance.getInstance().getLibrary();
- List<MetaData> metas = lib.getList().filter(whitelist, null, null);
+ if (WebLibraryUrls.LIST_URL_METADATA.equals(uri)) {
List<JSONObject> jsons = new ArrayList<JSONObject>();
- for (MetaData meta : metas) {
+ for (MetaData meta : metas(login)) {
jsons.add(JsonIO.toJson(meta));
}
NanoHTTPD.MIME_PLAINTEXT, null);
}
- private Response root(IHTTPSession session, Map<String, String> cookies,
- List<String> whitelist) throws IOException {
- BasicLibrary lib = Instance.getInstance().getLibrary();
- MetaResultList result = lib.getList();
- result = new MetaResultList(result.filter(whitelist, null, null));
- StringBuilder builder = new StringBuilder();
-
- appendPreHtml(builder, true);
-
- Map<String, String> params = session.getParms();
-
- String filter = cookies.get("filter");
- if (params.get("optionNo") != null)
- filter = null;
- if (filter == null) {
- filter = "";
- }
-
- String browser = params.get("browser") == null ? ""
- : params.get("browser");
- String browser2 = params.get("browser2") == null ? ""
- : params.get("browser2");
- String browser3 = params.get("browser3") == null ? ""
- : params.get("browser3");
-
- String filterSource = null;
- String filterAuthor = null;
- String filterTag = null;
-
- // TODO: javascript in realtime, using visible=false + hide [submit]
-
- builder.append("<form class='browser'>\n");
- builder.append("<div class='breadcrumbs'>\n");
-
- builder.append("\t<select name='browser'>");
- appendOption(builder, 2, "", "", browser);
- appendOption(builder, 2, "Sources", "sources", browser);
- appendOption(builder, 2, "Authors", "authors", browser);
- appendOption(builder, 2, "Tags", "tags", browser);
- builder.append("\t</select>\n");
-
- if (!browser.isEmpty()) {
- builder.append("\t<select name='browser2'>");
- if (browser.equals("sources")) {
- filterSource = browser2.isEmpty() ? filterSource : browser2;
- // TODO: if 1 group -> no group
- appendOption(builder, 2, "", "", browser2);
- Map<String, List<String>> sources = result.getSourcesGrouped();
- for (String source : sources.keySet()) {
- appendOption(builder, 2, source, source, browser2);
- }
- } else if (browser.equals("authors")) {
- filterAuthor = browser2.isEmpty() ? filterAuthor : browser2;
- // TODO: if 1 group -> no group
- appendOption(builder, 2, "", "", browser2);
- Map<String, List<String>> authors = result.getAuthorsGrouped();
- for (String author : authors.keySet()) {
- appendOption(builder, 2, author, author, browser2);
- }
- } else if (browser.equals("tags")) {
- filterTag = browser2.isEmpty() ? filterTag : browser2;
- appendOption(builder, 2, "", "", browser2);
- for (String tag : result.getTags()) {
- appendOption(builder, 2, tag, tag, browser2);
- }
- }
- builder.append("\t</select>\n");
- }
-
- if (!browser2.isEmpty()) {
- if (browser.equals("sources")) {
- filterSource = browser3.isEmpty() ? filterSource : browser3;
- Map<String, List<String>> sourcesGrouped = result
- .getSourcesGrouped();
- List<String> sources = sourcesGrouped.get(browser2);
- if (sources != null && !sources.isEmpty()) {
- // TODO: single empty value
- builder.append("\t<select name='browser3'>");
- appendOption(builder, 2, "", "", browser3);
- for (String source : sources) {
- appendOption(builder, 2, source, source, browser3);
- }
- builder.append("\t</select>\n");
- }
- } else if (browser.equals("authors")) {
- filterAuthor = browser3.isEmpty() ? filterAuthor : browser3;
- Map<String, List<String>> authorsGrouped = result
- .getAuthorsGrouped();
- List<String> authors = authorsGrouped.get(browser2);
- if (authors != null && !authors.isEmpty()) {
- // TODO: single empty value
- builder.append("\t<select name='browser3'>");
- appendOption(builder, 2, "", "", browser3);
- for (String author : authors) {
- appendOption(builder, 2, author, author, browser3);
- }
- builder.append("\t</select>\n");
- }
- }
- }
-
- builder.append("\t<input type='submit' value='Select'/>\n");
- builder.append("</div>\n");
-
- // TODO: javascript in realtime, using visible=false + hide [submit]
- builder.append("<div class='filter'>\n");
- builder.append("\t<span class='label'>Filter: </span>\n");
- builder.append(
- "\t<input name='optionName' type='hidden' value='filter' />\n");
- builder.append("\t<input name='optionValue' type='text' value='"
- + filter + "' place-holder='...' />\n");
- builder.append("\t<input name='optionNo' type='submit' value='x' />");
- builder.append(
- "\t<input name='submit' type='submit' value='Filter' />\n");
- builder.append("</div>\n");
- builder.append("</form>\n");
-
- builder.append("\t<div class='books'>");
- for (MetaData meta : result.getMetas()) {
- if (!filter.isEmpty() && !meta.getTitle().toLowerCase()
- .contains(filter.toLowerCase())) {
- continue;
- }
-
- // TODO Sub sources
- if (filterSource != null
- && !filterSource.equals(meta.getSource())) {
- continue;
- }
-
- // TODO: sub authors
- if (filterAuthor != null
- && !filterAuthor.equals(meta.getAuthor())) {
- continue;
- }
-
- if (filterTag != null && !meta.getTags().contains(filterTag)) {
- continue;
- }
-
- builder.append("<div class='book_line'>");
- builder.append("<a href='");
- builder.append(getViewUrl(meta.getLuid(), 0, null));
- builder.append("'");
- builder.append(" class='link'>");
-
- if (lib.isCached(meta.getLuid())) {
- // â—‰ = ◉
- builder.append(
- "<span class='cache_icon cached'>◉</span>");
- } else {
- // â—‹ = ○
- builder.append(
- "<span class='cache_icon uncached'>○</span>");
- }
- builder.append("<span class='luid'>");
- builder.append(meta.getLuid());
- builder.append("</span>");
- builder.append("<span class='title'>");
- builder.append(meta.getTitle());
- builder.append("</span>");
- builder.append("<span class='author'>");
- if (meta.getAuthor() != null && !meta.getAuthor().isEmpty()) {
- builder.append("(").append(meta.getAuthor()).append(")");
- }
- builder.append("</span>");
- builder.append("</a></div>\n");
- }
- builder.append("</div>");
-
- appendPostHtml(builder);
- return NanoHTTPD.newFixedLengthResponse(builder.toString());
- }
-
// /story/luid/chapter/para <-- text/image
// /story/luid/cover <-- image
// /story/luid/metadata <-- json
// /story/luid/json <-- json, whole chapter (no images)
- private Response getStoryPart(String uri, List<String> whitelist) {
+ @Override
+ protected Response getStoryPart(String uri, WLoginResult login) {
String[] cover = uri.split("/");
int off = 2;
InputStream in = null;
try {
if ("cover".equals(chapterStr)) {
- Image img = getCover(luid, whitelist);
+ Image img = cover(luid, login);
if (img != null) {
in = img.newInputStream();
}
// TODO: get correct image type
mimeType = "image/png";
} else if ("metadata".equals(chapterStr)) {
- MetaData meta = meta(luid, whitelist);
+ MetaData meta = meta(luid, login);
JSONObject json = JsonIO.toJson(meta);
mimeType = "application/json";
in = new ByteArrayInputStream(json.toString().getBytes());
} else if ("json".equals(chapterStr)) {
- Story story = story(luid, whitelist);
+ Story story = story(luid, login);
JSONObject json = JsonIO.toJson(story);
mimeType = "application/json";
in = new ByteArrayInputStream(json.toString().getBytes());
} else {
- Story story = story(luid, whitelist);
+ Story story = story(luid, login);
if (story != null) {
if (chapter == 0) {
StringBuilder builder = new StringBuilder();
return newInputStreamResponse(mimeType, in);
}
- private Response getViewer(Map<String, String> cookies, String uri,
- List<String> whitelist) {
- String[] cover = uri.split("/");
- int off = 2;
-
- if (cover.length < off + 2) {
- return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
- NanoHTTPD.MIME_PLAINTEXT, null);
- }
-
- String type = cover[off + 0];
- String luid = cover[off + 1];
- String chapterStr = cover.length < off + 3 ? null : cover[off + 2];
- String paragraphStr = cover.length < off + 4 ? null : cover[off + 3];
-
- // 1-based (0 = desc)
- int chapter = -1;
- if (chapterStr != null) {
- try {
- chapter = Integer.parseInt(chapterStr);
- if (chapter < 0) {
- throw new NumberFormatException();
- }
- } catch (NumberFormatException e) {
- return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
- NanoHTTPD.MIME_PLAINTEXT, "Chapter is not valid");
- }
- }
-
- // 1-based
- int paragraph = 0;
- if (paragraphStr != null) {
- try {
- paragraph = Integer.parseInt(paragraphStr);
- if (paragraph <= 0) {
- throw new NumberFormatException();
- }
- } catch (NumberFormatException e) {
- return NanoHTTPD.newFixedLengthResponse(Status.BAD_REQUEST,
- NanoHTTPD.MIME_PLAINTEXT, "Paragraph is not valid");
- }
- }
-
- try {
- Story story = story(luid, whitelist);
- if (story == null) {
- return NanoHTTPD.newFixedLengthResponse(Status.NOT_FOUND,
- NanoHTTPD.MIME_PLAINTEXT, "Story not found");
- }
-
- StringBuilder builder = new StringBuilder();
- appendPreHtml(builder, false);
-
- // For images documents, always go to the images if not chap 0 desc
- if (story.getMeta().isImageDocument()) {
- if (chapter > 0 && paragraph <= 0)
- paragraph = 1;
- }
-
- Chapter chap = null;
- if (chapter <= 0) {
- chap = story.getMeta().getResume();
- } else {
- try {
- chap = story.getChapters().get(chapter - 1);
- } catch (IndexOutOfBoundsException e) {
- return NanoHTTPD.newFixedLengthResponse(Status.NOT_FOUND,
- NanoHTTPD.MIME_PLAINTEXT, "Chapter not found");
- }
- }
-
- String first, previous, next, last;
-
- StringBuilder content = new StringBuilder();
-
- String disabledLeft = "";
- String disabledRight = "";
- String disabledZoomReal = "";
- String disabledZoomWidth = "";
- String disabledZoomHeight = "";
-
- if (paragraph <= 0) {
- first = getViewUrl(luid, 0, null);
- previous = getViewUrl(luid, (Math.max(chapter - 1, 0)), null);
- next = getViewUrl(luid,
- (Math.min(chapter + 1, story.getChapters().size())),
- null);
- last = getViewUrl(luid, story.getChapters().size(), null);
-
- StringBuilder desc = new StringBuilder();
-
- if (chapter <= 0) {
- desc.append("<h1 class='title'>");
- desc.append(story.getMeta().getTitle());
- desc.append("</h1>\n");
- desc.append("<div class='desc'>\n");
- desc.append("\t<div class='cover'>\n");
- desc.append("\t\t<img src='/story/" + luid + "/cover'/>\n");
- desc.append("\t</div>\n");
- desc.append("\t<table class='details'>\n");
- Map<String, String> details = BasicLibrary
- .getMetaDesc(story.getMeta());
- for (String key : details.keySet()) {
- appendTableRow(desc, 2, key, details.get(key));
- }
- desc.append("\t</table>\n");
- desc.append("</div>\n");
- desc.append("<h1 class='title'>Description</h1>\n");
- }
-
- content.append("<div class='viewer text'>\n");
- content.append(desc);
- String description = new TextOutput(false).convert(chap,
- chapter > 0);
- content.append(chap.getParagraphs().size() <= 0
- ? "No content provided."
- : description);
- content.append("</div>\n");
-
- if (chapter <= 0)
- disabledLeft = " disabled='disbaled'";
- if (chapter >= story.getChapters().size())
- disabledRight = " disabled='disbaled'";
- } else {
- first = getViewUrl(luid, chapter, 1);
- previous = getViewUrl(luid, chapter,
- (Math.max(paragraph - 1, 1)));
- next = getViewUrl(luid, chapter,
- (Math.min(paragraph + 1, chap.getParagraphs().size())));
- last = getViewUrl(luid, chapter, chap.getParagraphs().size());
-
- if (paragraph <= 1)
- disabledLeft = " disabled='disbaled'";
- if (paragraph >= chap.getParagraphs().size())
- disabledRight = " disabled='disbaled'";
-
- // First -> previous *chapter*
- if (chapter > 0)
- disabledLeft = "";
- first = getViewUrl(luid, (Math.max(chapter - 1, 0)), null);
- if (paragraph <= 1) {
- previous = first;
- }
-
- Paragraph para = null;
- try {
- para = chap.getParagraphs().get(paragraph - 1);
- } catch (IndexOutOfBoundsException e) {
- return NanoHTTPD.newFixedLengthResponse(Status.NOT_FOUND,
- NanoHTTPD.MIME_PLAINTEXT,
- "Paragraph " + paragraph + " not found");
- }
-
- if (para.getType() == ParagraphType.IMAGE) {
- String zoomStyle = "max-width: 100%;";
- disabledZoomWidth = " disabled='disabled'";
- String zoomOption = cookies.get("zoom");
- if (zoomOption != null && !zoomOption.isEmpty()) {
- if (zoomOption.equals("real")) {
- zoomStyle = "";
- disabledZoomWidth = "";
- disabledZoomReal = " disabled='disabled'";
- } else if (zoomOption.equals("width")) {
- zoomStyle = "max-width: 100%;";
- } else if (zoomOption.equals("height")) {
- // see height of navbar + optionbar
- zoomStyle = "max-height: calc(100% - 128px);";
- disabledZoomWidth = "";
- disabledZoomHeight = " disabled='disabled'";
- }
- }
-
- content.append(String.format("" //
- + "<a class='viewer link' href='%s'>"
- + "<img class='viewer img' style='%s' src='%s'/>"
- + "</a>", //
- next, //
- zoomStyle, //
- getStoryUrl(luid, chapter, paragraph)));
- } else {
- content.append(String.format("" //
- + "<div class='viewer text'>%s</div>", //
- para.getContent()));
- }
- }
-
- builder.append(String.format("" //
- + "<div class='bar navbar'>\n" //
- + "\t<a%s class='button first' href='%s'><<</a>\n"//
- + "\t<a%s class='button previous' href='%s'><</a>\n" //
- + "\t<div class='gotobox itemsbox'>\n" //
- + "\t\t<div class='button goto'>%d</div>\n" //
- + "\t\t<div class='items goto'>\n", //
- disabledLeft, first, //
- disabledLeft, previous, //
- paragraph > 0 ? paragraph : chapter //
- ));
-
- // List of chap/para links
-
- String blink = "/view/story/" + luid + "/";
- appendItemA(builder, 3, blink + "0", "Description",
- paragraph == 0 && chapter == 0);
-
- if (paragraph > 0) {
- blink = blink + chapter + "/";
- for (int i = 1; i <= chap.getParagraphs().size(); i++) {
- appendItemA(builder, 3, blink + i, "Image " + i,
- paragraph == i);
- }
- } else {
- int i = 1;
- for (Chapter c : story.getChapters()) {
- String chapName = "Chapter " + c.getNumber();
- if (c.getName() != null && !c.getName().isEmpty()) {
- chapName += ": " + c.getName();
- }
-
- appendItemA(builder, 3, blink + i, chapName, chapter == i);
-
- i++;
- }
- }
-
- builder.append(String.format("" //
- + "\t\t</div>\n" //
- + "\t</div>\n" //
- + "\t<a%s class='button next' href='%s'>></a>\n" //
- + "\t<a%s class='button last' href='%s'>>></a>\n"//
- + "</div>\n", //
- disabledRight, next, //
- disabledRight, last //
- ));
-
- builder.append(content);
-
- builder.append("<div class='bar optionbar ");
- if (paragraph > 0) {
- builder.append("s4");
- } else {
- builder.append("s1");
- }
- builder.append("'>\n");
- builder.append(" <a class='button back' href='/'>BACK</a>\n");
-
- if (paragraph > 0) {
- builder.append(String.format("" //
- + "\t<a%s class='button zoomreal' href='%s'>REAL</a>\n"//
- + "\t<a%s class='button zoomwidth' href='%s'>WIDTH</a>\n"//
- + "\t<a%s class='button zoomheight' href='%s'>HEIGHT</a>\n"//
- + "</div>\n", //
- disabledZoomReal,
- uri + "?optionName=zoom&optionValue=real", //
- disabledZoomWidth,
- uri + "?optionName=zoom&optionValue=width", //
- disabledZoomHeight,
- uri + "?optionName=zoom&optionValue=height" //
- ));
- }
-
- appendPostHtml(builder);
- return NanoHTTPD.newFixedLengthResponse(Status.OK,
- NanoHTTPD.MIME_HTML, builder.toString());
- } catch (IOException e) {
- Instance.getInstance().getTraceHandler()
- .error(new IOException("Cannot get image: " + uri, e));
- return NanoHTTPD.newFixedLengthResponse(Status.INTERNAL_ERROR,
- NanoHTTPD.MIME_PLAINTEXT, "Error when processing request");
- }
- }
-
- private Response newInputStreamResponse(String mimeType, InputStream in) {
- if (in == null) {
- return NanoHTTPD.newFixedLengthResponse(Status.NO_CONTENT, "",
- null);
- }
- return NanoHTTPD.newChunkedResponse(Status.OK, mimeType, in);
- }
-
- private String getContentOf(String file) {
- InputStream in = IOUtils.openResource(WebLibraryServerIndex.class,
- file);
- if (in != null) {
- try {
- return IOUtils.readSmallStream(in);
- } catch (IOException e) {
- Instance.getInstance().getTraceHandler().error(
- new IOException("Cannot get file: index.pre.html", e));
- }
- }
-
- return "";
- }
-
- private String getViewUrl(String luid, int chap, Integer para) {
- return VIEWER_URL //
- .replace("{luid}", luid) //
- .replace("{chap}", Integer.toString(chap)) //
- .replace("/{para}",
- para == null ? "" : "/" + Integer.toString(para));
- }
-
- private String getStoryUrl(String luid, int chap, Integer para) {
- return STORY_URL //
- .replace("{luid}", luid) //
- .replace("{chap}", Integer.toString(chap)) //
- .replace("{para}", para == null ? "" : Integer.toString(para));
- }
-
- private String getStoryUrlCover(String luid) {
- return STORY_URL_COVER //
- .replace("{luid}", luid);
- }
-
- private MetaData meta(String luid, List<String> whitelist)
- throws IOException {
+ @Override
+ protected List<MetaData> metas(WLoginResult login) throws IOException {
BasicLibrary lib = Instance.getInstance().getLibrary();
- MetaData meta = lib.getInfo(luid);
- if (!whitelist.isEmpty() && !whitelist.contains(meta.getSource())) {
- return null;
- }
-
- return meta;
- }
-
- private Image getCover(String luid, List<String> whitelist)
- throws IOException {
- MetaData meta = meta(luid, whitelist);
- if (meta != null) {
- BasicLibrary lib = Instance.getInstance().getLibrary();
- return lib.getCover(meta.getLuid());
+ List<MetaData> metas = new ArrayList<MetaData>();
+ for (MetaData meta : lib.getList().getMetas()) {
+ if (isAllowed(meta, login)) {
+ metas.add(meta);
+ }
}
- return null;
+ return metas;
}
// NULL if not whitelist OK or if not found
- private Story story(String luid, List<String> whitelist)
- throws IOException {
+ @Override
+ protected Story story(String luid, WLoginResult login) throws IOException {
synchronized (storyCache) {
if (storyCache.containsKey(luid)) {
Story story = storyCache.get(luid);
- if (!whitelist.isEmpty()
- && !whitelist.contains(story.getMeta().getSource())) {
+ if (!isAllowed(story.getMeta(), login))
return null;
- }
return story;
}
}
Story story = null;
- MetaData meta = meta(luid, whitelist);
+ MetaData meta = meta(luid, login);
if (meta != null) {
BasicLibrary lib = Instance.getInstance().getLibrary();
story = lib.getStory(luid, null);
return story;
}
- private long sizeOf(Story story) {
- long size = 0;
- for (Chapter chap : story) {
- for (Paragraph para : chap) {
- if (para.getType() == ParagraphType.IMAGE) {
- size += para.getContentImage().getSize();
- } else {
- size += para.getContent().length();
- }
- }
- }
+ private MetaData meta(String luid, WLoginResult login) throws IOException {
+ BasicLibrary lib = Instance.getInstance().getLibrary();
+ MetaData meta = lib.getInfo(luid);
+ if (!isAllowed(meta, login))
+ return null;
- return size;
+ return meta;
}
- private void appendPreHtml(StringBuilder builder, boolean banner) {
- String favicon = "favicon.ico";
- String icon = Instance.getInstance().getUiConfig()
- .getString(UiConfig.PROGRAM_ICON);
- if (icon != null) {
- favicon = "icon_" + icon.replace("-", "_") + ".png";
- }
-
- builder.append(
- getContentOf("index.pre.html").replace("favicon.ico", favicon));
-
- if (banner) {
- builder.append("<div class='banner'>\n");
- builder.append("\t<img class='ico' src='/") //
- .append(favicon) //
- .append("'/>\n");
- builder.append("\t<h1>Fanfix</h1>\n");
- builder.append("\t<h2>") //
- .append(Version.getCurrentVersion()) //
- .append("</h2>\n");
- builder.append("</div>\n");
+ private Image cover(String luid, WLoginResult login) throws IOException {
+ MetaData meta = meta(luid, login);
+ if (meta != null) {
+ BasicLibrary lib = Instance.getInstance().getLibrary();
+ return lib.getCover(meta.getLuid());
}
- }
- private void appendPostHtml(StringBuilder builder) {
- builder.append(getContentOf("index.post.html"));
+ return null;
}
- private void appendOption(StringBuilder builder, int depth, String name,
- String value, String selected) {
- for (int i = 0; i < depth; i++) {
- builder.append("\t");
+ private boolean isAllowed(MetaData meta, WLoginResult login) {
+ if (login.isWl() && !whitelist.isEmpty()
+ && !whitelist.contains(meta.getSource())) {
+ return false;
}
- builder.append("<option value='").append(value).append("'");
- if (value.equals(selected)) {
- builder.append(" selected='selected'");
- }
- builder.append(">").append(name).append("</option>\n");
- }
-
- private void appendTableRow(StringBuilder builder, int depth,
- String... tds) {
- for (int i = 0; i < depth; i++) {
- builder.append("\t");
+ if (login.isBl() && blacklist.contains(meta.getSource())) {
+ return false;
}
- int col = 1;
- builder.append("<tr>");
- for (String td : tds) {
- builder.append("<td class='col");
- builder.append(col++);
- builder.append("'>");
- builder.append(td);
- builder.append("</td>");
- }
- builder.append("</tr>\n");
+ return true;
}
- private void appendItemA(StringBuilder builder, int depth, String link,
- String name, boolean selected) {
- for (int i = 0; i < depth; i++) {
- builder.append("\t");
+ private long sizeOf(Story story) {
+ long size = 0;
+ for (Chapter chap : story) {
+ for (Paragraph para : chap) {
+ if (para.getType() == ParagraphType.IMAGE) {
+ size += para.getContentImage().getSize();
+ } else {
+ size += para.getContent().length();
+ }
+ }
}
- builder.append("<a href='");
- builder.append(link);
- builder.append("' class='item goto");
- if (selected) {
- builder.append(" selected");
- }
- builder.append("'>");
- builder.append(name);
- builder.append("</a>\n");
+ return size;
}
public static void main(String[] args) throws IOException {