X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Flibrary%2FWebLibraryServer.java;h=b6d11f9baa2f1bf91c6743ba4d5e06da5c558639;hb=5ee0fc14dbffa8d11b914537d957ef892ba20ef9;hp=b4a6e4bb25f3776c819a43e9235f58b5c63b7788;hpb=3f468ac7897811d06598c88c98ba31fb57b4170e;p=nikiroo-utils.git diff --git a/src/be/nikiroo/fanfix/library/WebLibraryServer.java b/src/be/nikiroo/fanfix/library/WebLibraryServer.java index b4a6e4b..b6d11f9 100644 --- a/src/be/nikiroo/fanfix/library/WebLibraryServer.java +++ b/src/be/nikiroo/fanfix/library/WebLibraryServer.java @@ -29,9 +29,9 @@ 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; @@ -40,100 +40,40 @@ 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; + private class WLoginResult extends LoginResult { private boolean rw; private boolean wl; - private String wookie; - private String token; - private boolean badLogin; - private boolean badToken; - - public LoginResult(String who, String key, String subkey, - boolean success, boolean rw, boolean wl) { - this.success = success; + private boolean bl; + + 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 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(); - } - subkeys = new ArrayList(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|"); } } @@ -144,6 +84,9 @@ public class WebLibraryServer implements Runnable { private long maxStoryCacheSize; private TraceHandler tracer = new TraceHandler(); + private List whitelist; + private List blacklist; + public WebLibraryServer(boolean secure) throws IOException { Integer port = Instance.getInstance().getConfig() .getInteger(Config.SERVER_PORT); @@ -158,6 +101,11 @@ public class WebLibraryServer implements Runnable { setTraceHandler(Instance.getInstance().getTraceHandler()); + whitelist = Instance.getInstance().getConfig() + .getList(Config.SERVER_WHITELIST, new ArrayList()); + blacklist = Instance.getInstance().getConfig() + .getList(Config.SERVER_BLACKLIST, new ArrayList()); + SSLServerSocketFactory ssf = null; if (secure) { String keystorePath = Instance.getInstance().getConfig() @@ -211,33 +159,22 @@ public class WebLibraryServer implements Runnable { cookies.put(cookie, session.getCookies().read(cookie)); } - List whitelist = Instance.getInstance().getConfig() - .getList(Config.SERVER_WHITELIST); - if (whitelist == null) { - whitelist = new ArrayList(); - } - - LoginResult login = null; + WLoginResult login = null; Map params = session.getParms(); String who = session.getRemoteHostName() + session.getRemoteIpAddress(); if (params.get("login") != null) { login = login(who, params.get("password"), - params.get("login"), whitelist); + params.get("login")); } else { - String token = cookies.get("token"); - login = login(who, token, Instance.getInstance().getConfig() - .getList(Config.SERVER_ALLOWED_SUBKEYS)); + String cookie = cookies.get("cookie"); + login = login(who, cookie); } if (login.isSuccess()) { - if (!login.isWl()) { - whitelist.clear(); - } - - // refresh token - session.getCookies().set(new Cookie("token", - login.getToken(), "30; path=/")); + // refresh cookie + session.getCookies().set(new Cookie("cookie", + login.getCookie(), "30; path=/")); // set options String optionName = params.get("optionName"); @@ -257,27 +194,39 @@ public class WebLibraryServer implements Runnable { } Response rep = null; - if (!login.isSuccess() && (uri.equals("/") // - || uri.startsWith(STORY_URL_BASE) // - || uri.startsWith(VIEWER_URL_BASE) // - || uri.startsWith(LIST_URL))) { + if (!login.isSuccess() && WebLibraryUrls.isSupportedUrl(uri)) { 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); + if (WebLibraryUrls.isSupportedUrl(uri)) { + if (WebLibraryUrls.INDEX_URL.equals(uri)) { + rep = root(session, cookies, login); + } else if (WebLibraryUrls.VERSION_URL.equals(uri)) { + rep = newFixedLengthResponse(Status.OK, + MIME_PLAINTEXT, + Version.getCurrentVersion().toString()); + } else if (WebLibraryUrls.isListUrl(uri)) { + rep = getList(uri, login); + } else if (WebLibraryUrls.isStoryUrl(uri)) { + rep = getStoryPart(uri, login); + } else if (WebLibraryUrls.isViewUrl(uri)) { + rep = getViewer(cookies, uri, login); + } else if (WebLibraryUrls.LOGOUT_URL.equals(uri)) { + session.getCookies().delete("cookie"); + cookies.remove("cookie"); + rep = loginPage(new WLoginResult(false, false), + uri); + } else { + getTraceHandler().error( + "Supported URL was not processed: " + + uri); + rep = newFixedLengthResponse( + Status.INTERNAL_ERROR, + NanoHTTPD.MIME_PLAINTEXT, + "An error happened"); + } } else { if (uri.startsWith("/")) uri = uri.substring(1); @@ -294,14 +243,13 @@ public class WebLibraryServer implements Runnable { } rep = newChunkedResponse(Status.OK, mimeType, in); - } else { - getTraceHandler().trace("404: " + uri); } - } - if (rep == null) { - rep = newFixedLengthResponse(Status.NOT_FOUND, - NanoHTTPD.MIME_PLAINTEXT, "Not Found"); + if (rep == null) { + getTraceHandler().trace("404: " + uri); + rep = newFixedLengthResponse(Status.NOT_FOUND, + NanoHTTPD.MIME_PLAINTEXT, "Not Found"); + } } } catch (Exception e) { Instance.getInstance().getTraceHandler().error( @@ -313,24 +261,6 @@ public class WebLibraryServer implements Runnable { } 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()); } }; @@ -385,69 +315,71 @@ public class WebLibraryServer implements Runnable { this.tracer = tracer; } - private LoginResult login(String who, String token, List subkeys) { + private WLoginResult login(String who, String cookie) { + List 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 whitelist) { + private 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 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); + + List allowed = Instance.getInstance().getConfig().getList( + Config.SERVER_ALLOWED_SUBKEYS, new ArrayList()); + + if (!allowed.isEmpty()) { + if (!allowed.contains(subkey)) { + return new WLoginResult(true, false); + } + + if ((subkey + "|").contains("|rw|")) { + rw = true; + } + if ((subkey + "|").contains("|wl|")) { + wl = false; // |wl| = bypass whitelist + } + if ((subkey + "|").contains("|bl|")) { + bl = false; // |bl| = bypass blacklist } } - return new LoginResult(who, key, subkey, true, rw, wl); + return new WLoginResult(who, key, subkey, rw, wl, bl); } - private Response loginPage(LoginResult login, String uri) { + private Response loginPage(WLoginResult login, String uri) { StringBuilder builder = new StringBuilder(); appendPreHtml(builder, true); if (login.isBadLogin()) { builder.append("
Bad login or password
"); - } else if (login.isBadToken()) { + } else if (login.isBadCookie()) { builder.append("
Your session timed out
"); } - if (uri.equals("/logout")) { - uri = "/"; + if (WebLibraryUrls.LOGOUT_URL.equals(uri)) { + uri = WebLibraryUrls.INDEX_URL; } builder.append( @@ -465,13 +397,11 @@ public class WebLibraryServer implements Runnable { NanoHTTPD.MIME_HTML, builder.toString()); } - protected Response getList(String uri, List whitelist) + protected Response getList(String uri, WLoginResult login) throws IOException { - if (uri.equals("/list/luids")) { - BasicLibrary lib = Instance.getInstance().getLibrary(); - List metas = lib.getList().filter(whitelist, null, null); + if (WebLibraryUrls.LIST_URL_METADATA.equals(uri)) { List jsons = new ArrayList(); - for (MetaData meta : metas) { + for (MetaData meta : metas(login)) { jsons.add(JsonIO.toJson(meta)); } @@ -485,10 +415,9 @@ public class WebLibraryServer implements Runnable { } private Response root(IHTTPSession session, Map cookies, - List whitelist) throws IOException { + WLoginResult login) throws IOException { BasicLibrary lib = Instance.getInstance().getLibrary(); - MetaResultList result = lib.getList(); - result = new MetaResultList(result.filter(whitelist, null, null)); + MetaResultList result = new MetaResultList(metas(login)); StringBuilder builder = new StringBuilder(); appendPreHtml(builder, true); @@ -626,7 +555,8 @@ public class WebLibraryServer implements Runnable { builder.append("
"); builder.append(""); @@ -662,7 +592,7 @@ public class WebLibraryServer implements Runnable { // /story/luid/cover <-- image // /story/luid/metadata <-- json // /story/luid/json <-- json, whole chapter (no images) - private Response getStoryPart(String uri, List whitelist) { + private Response getStoryPart(String uri, WLoginResult login) { String[] cover = uri.split("/"); int off = 2; @@ -709,24 +639,24 @@ public class WebLibraryServer implements Runnable { InputStream in = null; try { if ("cover".equals(chapterStr)) { - Image img = getCover(luid, whitelist); + Image img = getCover(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(); @@ -769,7 +699,7 @@ public class WebLibraryServer implements Runnable { } private Response getViewer(Map cookies, String uri, - List whitelist) { + WLoginResult login) { String[] cover = uri.split("/"); int off = 2; @@ -784,7 +714,7 @@ public class WebLibraryServer implements Runnable { String paragraphStr = cover.length < off + 4 ? null : cover[off + 3]; // 1-based (0 = desc) - int chapter = -1; + int chapter = 0; if (chapterStr != null) { try { chapter = Integer.parseInt(chapterStr); @@ -812,7 +742,7 @@ public class WebLibraryServer implements Runnable { } try { - Story story = story(luid, whitelist); + Story story = story(luid, login); if (story == null) { return NanoHTTPD.newFixedLengthResponse(Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, "Story not found"); @@ -850,12 +780,14 @@ public class WebLibraryServer implements Runnable { String disabledZoomHeight = ""; if (paragraph <= 0) { - first = getViewUrl(luid, 0, null); - previous = getViewUrl(luid, (Math.max(chapter - 1, 0)), null); - next = getViewUrl(luid, + first = WebLibraryUrls.getViewUrl(luid, 0, null); + previous = WebLibraryUrls.getViewUrl(luid, + (Math.max(chapter - 1, 0)), null); + next = WebLibraryUrls.getViewUrl(luid, (Math.min(chapter + 1, story.getChapters().size())), null); - last = getViewUrl(luid, story.getChapters().size(), null); + last = WebLibraryUrls.getViewUrl(luid, + story.getChapters().size(), null); StringBuilder desc = new StringBuilder(); @@ -864,9 +796,9 @@ public class WebLibraryServer implements Runnable { desc.append(story.getMeta().getTitle()); desc.append("\n"); desc.append("
\n"); - desc.append("\t\n"); + desc.append("\t\n"); desc.append("\t\n"); Map details = BasicLibrary .getMetaDesc(story.getMeta()); @@ -892,12 +824,13 @@ public class WebLibraryServer implements Runnable { if (chapter >= story.getChapters().size()) disabledRight = " disabled='disbaled'"; } else { - first = getViewUrl(luid, chapter, 1); - previous = getViewUrl(luid, chapter, + first = WebLibraryUrls.getViewUrl(luid, chapter, 1); + previous = WebLibraryUrls.getViewUrl(luid, chapter, (Math.max(paragraph - 1, 1))); - next = getViewUrl(luid, chapter, + next = WebLibraryUrls.getViewUrl(luid, chapter, (Math.min(paragraph + 1, chap.getParagraphs().size()))); - last = getViewUrl(luid, chapter, chap.getParagraphs().size()); + last = WebLibraryUrls.getViewUrl(luid, chapter, + chap.getParagraphs().size()); if (paragraph <= 1) disabledLeft = " disabled='disbaled'"; @@ -907,7 +840,8 @@ public class WebLibraryServer implements Runnable { // First -> previous *chapter* if (chapter > 0) disabledLeft = ""; - first = getViewUrl(luid, (Math.max(chapter - 1, 0)), null); + first = WebLibraryUrls.getViewUrl(luid, + (Math.max(chapter - 1, 0)), null); if (paragraph <= 1) { previous = first; } @@ -940,13 +874,16 @@ public class WebLibraryServer implements Runnable { } } + String javascript = "document.getElementById(\"previous\").click(); return false;"; content.append(String.format("" // - + "" + + "" + "" + "", // + javascript, // next, // zoomStyle, // - getStoryUrl(luid, chapter, paragraph))); + WebLibraryUrls.getStoryUrl(luid, chapter, + paragraph))); } else { content.append(String.format("" // + "
%s
", // @@ -957,7 +894,7 @@ public class WebLibraryServer implements Runnable { builder.append(String.format("" // + "