X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Flibrary%2FWebLibraryServer.java;h=c4be6633dc563949a5f146a86225017d43b987c4;hb=d11fb35b34e44744c8b1f9226321f133af4eb151;hp=e0096fcc590b94963137d1476d9f57caf7398124;hpb=f433d15308b70e23280a65cef8c54002a7a971ce;p=nikiroo-utils.git diff --git a/src/be/nikiroo/fanfix/library/WebLibraryServer.java b/src/be/nikiroo/fanfix/library/WebLibraryServer.java index e0096fc..c4be663 100644 --- a/src/be/nikiroo/fanfix/library/WebLibraryServer.java +++ b/src/be/nikiroo/fanfix/library/WebLibraryServer.java @@ -51,16 +51,18 @@ public class WebLibraryServer implements Runnable { private boolean success; private boolean rw; private boolean wl; + private boolean bl; 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) { + boolean success, boolean rw, boolean wl, boolean bl) { this.success = success; this.rw = rw; this.wl = wl; + this.bl = bl; this.wookie = CookieUtils.generateCookie(who + key, 0); String opts = ""; @@ -68,6 +70,8 @@ public class WebLibraryServer implements Runnable { opts += "|rw"; if (!wl) opts += "|wl"; + if (!bl) + opts += "|bl"; this.token = wookie + "~" + CookieUtils.generateCookie(wookie + subkey + opts, 0) @@ -101,6 +105,7 @@ public class WebLibraryServer implements Runnable { this.rw = opts.contains("|rw"); this.wl = !opts.contains("|wl"); + this.bl = !opts.contains("|bl"); } } } @@ -124,6 +129,10 @@ public class WebLibraryServer implements Runnable { return wl; } + public boolean isBl() { + return bl; + } + public String getToken() { return token; } @@ -144,6 +153,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 +170,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,23 +228,16 @@ 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; 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)); + login = login(who, token); } if (login.isSuccess()) { @@ -238,8 +248,10 @@ public class WebLibraryServer implements Runnable { // set options String optionName = params.get("optionName"); if (optionName != null && !optionName.isEmpty()) { + String optionNo = params.get("optionNo"); String optionValue = params.get("optionValue"); - if (optionValue == null || optionValue.isEmpty()) { + if (optionNo != null || optionValue == null + || optionValue.isEmpty()) { session.getCookies().delete(optionName); cookies.remove(optionName); } else { @@ -261,13 +273,13 @@ public class WebLibraryServer implements Runnable { if (rep == null) { try { if (uri.equals("/")) { - rep = root(session, cookies, whitelist); + rep = root(session, cookies, login); } else if (uri.startsWith(LIST_URL)) { - rep = getList(uri, whitelist); + rep = getList(uri, login); } else if (uri.startsWith(STORY_URL_BASE)) { - rep = getStoryPart(uri, whitelist); + rep = getStoryPart(uri, login); } else if (uri.startsWith(VIEWER_URL_BASE)) { - rep = getViewer(cookies, uri, whitelist); + rep = getViewer(cookies, uri, login); } else if (uri.equals("/logout")) { session.getCookies().delete("token"); cookies.remove("token"); @@ -307,24 +319,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()); } }; @@ -379,35 +373,33 @@ public class WebLibraryServer implements Runnable { this.tracer = tracer; } - private LoginResult login(String who, String token, List subkeys) { + private LoginResult login(String who, String token) { + List subkeys = Instance.getInstance().getConfig().getList( + Config.SERVER_ALLOWED_SUBKEYS, new ArrayList()); String realKey = Instance.getInstance().getConfig() - .getString(Config.SERVER_KEY); - realKey = realKey == null ? "" : realKey; + .getString(Config.SERVER_KEY, ""); + return new LoginResult(token, who, realKey, subkeys); } // allow rw/wl - private LoginResult login(String who, String key, String subkey, - List whitelist) { + private LoginResult 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 LoginResult(null, null, null, false, false, false, + 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); @@ -421,12 +413,16 @@ public class WebLibraryServer implements Runnable { if ((subkey + "|").contains("|wl|")) { wl = false; // |wl| = bypass whitelist } + if ((subkey + "|").contains("|bl|")) { + bl = false; // |bl| = bypass blacklist + } } else { - return new LoginResult(null, null, null, false, false, false); + return new LoginResult(null, null, null, false, false, false, + false); } } - return new LoginResult(who, key, subkey, true, rw, wl); + return new LoginResult(who, key, subkey, true, rw, wl, bl); } private Response loginPage(LoginResult login, String uri) { @@ -459,13 +455,11 @@ public class WebLibraryServer implements Runnable { NanoHTTPD.MIME_HTML, builder.toString()); } - protected Response getList(String uri, List whitelist) + protected Response getList(String uri, LoginResult login) throws IOException { if (uri.equals("/list/luids")) { - BasicLibrary lib = Instance.getInstance().getLibrary(); - List metas = lib.getList().filter(whitelist, null, null); List jsons = new ArrayList(); - for (MetaData meta : metas) { + for (MetaData meta : metas(login)) { jsons.add(JsonIO.toJson(meta)); } @@ -479,20 +473,22 @@ public class WebLibraryServer implements Runnable { } private Response root(IHTTPSession session, Map cookies, - List whitelist) throws IOException { + LoginResult 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); + Map params = session.getParms(); + String filter = cookies.get("filter"); + if (params.get("optionNo") != null) + filter = null; if (filter == null) { filter = ""; } - Map params = session.getParms(); String browser = params.get("browser") == null ? "" : params.get("browser"); String browser2 = params.get("browser2") == null ? "" @@ -581,11 +577,12 @@ public class WebLibraryServer implements Runnable { // TODO: javascript in realtime, using visible=false + hide [submit] builder.append("
\n"); - builder.append("\tFilter: \n"); + builder.append("\tFilter: \n"); builder.append( "\t\n"); builder.append("\t\n"); + builder.append("\t"); builder.append( "\t\n"); builder.append("
\n"); @@ -616,7 +613,7 @@ public class WebLibraryServer implements Runnable { builder.append("
"); builder.append(""); @@ -651,7 +648,8 @@ public class WebLibraryServer implements Runnable { // /story/luid/chapter/para <-- text/image // /story/luid/cover <-- image // /story/luid/metadata <-- json - private Response getStoryPart(String uri, List whitelist) { + // /story/luid/json <-- json, whole chapter (no images) + private Response getStoryPart(String uri, LoginResult login) { String[] cover = uri.split("/"); int off = 2; @@ -667,7 +665,8 @@ public class WebLibraryServer implements Runnable { // 1-based (0 = desc) int chapter = 0; if (chapterStr != null && !"cover".equals(chapterStr) - && !"metadata".equals(chapterStr)) { + && !"metadata".equals(chapterStr) + && !"json".equals(chapterStr)) { try { chapter = Integer.parseInt(chapterStr); if (chapter < 0) { @@ -697,17 +696,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, 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(); @@ -750,7 +756,7 @@ public class WebLibraryServer implements Runnable { } private Response getViewer(Map cookies, String uri, - List whitelist) { + LoginResult login) { String[] cover = uri.split("/"); int off = 2; @@ -765,7 +771,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); @@ -793,7 +799,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"); @@ -802,123 +808,213 @@ public class WebLibraryServer implements Runnable { StringBuilder builder = new StringBuilder(); appendPreHtml(builder, false); - if (chapter < 0) { - builder.append(story); - } else { - if (chapter == 0) { - // TODO: description - chapter = 1; - } + // 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; + 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"); } + } - if (story.getMeta().isImageDocument() && paragraph <= 0) { - paragraph = 1; + 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("

"); + desc.append(story.getMeta().getTitle()); + desc.append("

\n"); + desc.append("
\n"); + desc.append("\t\n"); + desc.append("\t\t\n"); + desc.append("\t\n"); + desc.append("\t\n"); + Map details = BasicLibrary + .getMetaDesc(story.getMeta()); + for (String key : details.keySet()) { + appendTableRow(desc, 2, key, details.get(key)); + } + desc.append("\t
\n"); + desc.append("
\n"); + desc.append("

Description

\n"); } - String first, previous, next, last; - String content; + content.append("
\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("
\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; + } - if (paragraph <= 0) { - first = getViewUrl(luid, 1, null); - previous = getViewUrl(luid, (Math.max(chapter - 1, 1)), - null); - next = getViewUrl(luid, - (Math.min(chapter + 1, story.getChapters().size())), - null); - last = getViewUrl(luid, story.getChapters().size(), null); - - content = "
\n" - + new TextOutput(false).convert(chap, true) - + "
\n"; - } 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()); - - Paragraph para = null; - try { - para = chap.getParagraphs().get(paragraph - 1); - } catch (IndexOutOfBoundsException e) { - return NanoHTTPD.newFixedLengthResponse( - Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, - "Paragraph not found"); - } + 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%;"; - String zoomOption = cookies.get("zoom"); - if (zoomOption != null && !zoomOption.isEmpty()) { - if (zoomOption.equals("real")) { - zoomStyle = ""; - } 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);"; - } + 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 = String.format("" // - + "" // - + "" - + "", // - next, // - zoomStyle, // - getStoryUrl(luid, chapter, paragraph)); - } else { - content = para.getContent(); } + String javascript = "document.getElementById(\"previous\").click(); return false;"; + content.append(String.format("" // + + "" + + "" + + "", // + javascript, // + next, // + zoomStyle, // + getStoryUrl(luid, chapter, paragraph))); + } else { + content.append(String.format("" // + + "
%s
", // + para.getContent())); } + } - builder.append(String.format("" // - + "\n" // - + "%s", // - first, // - previous, // - next, // - last, // - content // - )); - - builder.append("
\n" // + + "\t<<\n"// + + "\t<\n" // + + "\t
\n" // + + "\t\t
%d
\n" // + + "\t\t
\n", // + disabledLeft, first, // + disabledLeft, previous, // + paragraph > 0 ? paragraph : chapter // + )); + + // List of chap/para links + + appendItemA(builder, 3, getViewUrl(luid, 0, null), "Description", + paragraph == 0 && chapter == 0); + if (paragraph > 0) { + for (int i = 1; i <= chap.getParagraphs().size(); i++) { + appendItemA(builder, 3, getViewUrl(luid, chapter, i), + "Image " + i, paragraph == i); } - builder.append("'>\n"); - builder.append( - " BACK\n"); - - if (paragraph > 0) { - builder.append(String.format("" // - + "\tREAL\n"// - + "\tWIDTH\n"// - + "\tHEIGHT\n"// - + "
\n", // - uri + "?optionName=zoom&optionValue=real", // - uri + "?optionName=zoom&optionValue=width", // - uri + "?optionName=zoom&optionValue=height" // - )); + } 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, getViewUrl(luid, i, null), chapName, + chapter == i); + + i++; } } + builder.append(String.format("" // + + "\t\t
\n" // + + "\t
\n" // + + "\t>\n" // + + "\t>>\n"// + + "
\n", // + disabledRight, next, // + disabledRight, last // + )); + + builder.append(content); + + builder.append("
\n"); + builder.append(" BACK\n"); + + if (paragraph > 0) { + builder.append(String.format("" // + + "\tREAL\n"// + + "\tWIDTH\n"// + + "\tHEIGHT\n"// + + "
\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()); @@ -953,12 +1049,12 @@ public class WebLibraryServer implements Runnable { return ""; } - private String getViewUrl(String luid, int chap, Integer para) { + private String getViewUrl(String luid, Integer chap, Integer para) { return VIEWER_URL // .replace("{luid}", luid) // - .replace("{chap}", Integer.toString(chap)) // + .replace("/{chap}", chap == null ? "" : "/" + chap) // .replace("/{para}", - para == null ? "" : "/" + Integer.toString(para)); + (chap == null || para == null) ? "" : "/" + para); } private String getStoryUrl(String luid, int chap, Integer para) { @@ -973,44 +1069,63 @@ public class WebLibraryServer implements Runnable { .replace("{luid}", luid); } - private MetaData meta(String luid, List whitelist) - throws IOException { + private boolean isAllowed(MetaData meta, LoginResult login) { + if (login.isWl() && !whitelist.isEmpty() + && !whitelist.contains(meta.getSource())) { + return false; + } + if (login.isBl() && blacklist.contains(meta.getSource())) { + return false; + } + + return true; + } + + private List metas(LoginResult login) throws IOException { + BasicLibrary lib = Instance.getInstance().getLibrary(); + List metas = new ArrayList(); + for (MetaData meta : lib.getList().getMetas()) { + if (isAllowed(meta, login)) { + metas.add(meta); + } + } + + return metas; + } + + private MetaData meta(String luid, LoginResult login) throws IOException { BasicLibrary lib = Instance.getInstance().getLibrary(); MetaData meta = lib.getInfo(luid); - if (!whitelist.isEmpty() && !whitelist.contains(meta.getSource())) { + if (!isAllowed(meta, login)) return null; - } return meta; } - private Image getCover(String luid, List whitelist) - throws IOException { - MetaData meta = meta(luid, whitelist); + private Image getCover(String luid, LoginResult login) throws IOException { + MetaData meta = meta(luid, login); if (meta != null) { - return meta.getCover(); + BasicLibrary lib = Instance.getInstance().getLibrary(); + return lib.getCover(meta.getLuid()); } return null; } // NULL if not whitelist OK or if not found - private Story story(String luid, List whitelist) - throws IOException { + private Story story(String luid, LoginResult 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); @@ -1063,7 +1178,7 @@ public class WebLibraryServer implements Runnable { if (banner) { builder.append("