| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- /*
- ArozOS Office Suite - share link unit tests (common/share.js)
- Run with: node test_share.js (exits 1 on failure)
- parse() is the security boundary of ?request=: whatever it returns is
- fetched, so most of these pin what it refuses.
- */
- global.OfficeContainer = require("./container.js");
- var S = require("./share.js");
- var failures = 0, passes = 0;
- function eq(name, got, want) {
- if (got === want) { passes++; return; }
- failures++;
- console.log("FAIL " + name + "\n got: " + JSON.stringify(got) + "\n want: " + JSON.stringify(want));
- }
- function throws(name, fn) {
- try { fn(); } catch (e) { passes++; return; }
- failures++;
- console.log("FAIL " + name + ": expected an error");
- }
- var ID = "f7453c19-66c8-4e84-8288-76b84ec0da9f";
- var PREVIEW = "http://localhost:8080/share/preview/" + ID + "/";
- /* ---- parse: accepted link shapes ---- */
- [
- ["share page, trailing slash", "http://localhost:8080/share/" + ID + "/", PREVIEW],
- ["share page, no slash", "http://localhost:8080/share/" + ID, PREVIEW],
- ["preview link", PREVIEW, PREVIEW],
- ["download link", "http://localhost:8080/share/download/" + ID + "/HelloWorld.doca", PREVIEW],
- ["legacy ?id=", "http://localhost:8080/share?id=" + ID, PREVIEW],
- ["surrounding space", " http://localhost:8080/share/" + ID + "/ ", PREVIEW],
- ["query and hash ignored", "http://localhost:8080/share/" + ID + "/?x=1#top", PREVIEW],
- ["https + reverse-proxy prefix", "https://example.com/aroz/share/" + ID + "/",
- "https://example.com/aroz/share/preview/" + ID + "/"],
- ["prefix folder called share", "https://example.com/share/share/" + ID + "/",
- "https://example.com/share/share/preview/" + ID + "/"]
- ].forEach(function (c) {
- var info;
- try { info = S.parse(c[1]); } catch (e) { eq("parse " + c[0], "threw: " + e.message, c[2]); return; }
- eq("parse " + c[0], info.previewUrl, c[2]);
- });
- eq("download link name hint",
- S.parse("http://localhost:8080/share/download/" + ID + "/My%20Doc.doca").nameHint, "My Doc.doca");
- eq("share page has no name hint", S.parse("http://localhost:8080/share/" + ID + "/").nameHint, "");
- /* ---- parse: refused ---- */
- [
- ["empty", ""],
- ["not a url", "share/" + ID],
- ["relative", "/share/" + ID + "/"],
- ["javascript scheme", "javascript:alert(1)//share/" + ID],
- ["file scheme", "file:///share/" + ID],
- ["data scheme", "data:text/plain,share/" + ID],
- ["credentials", "http://user:pw@localhost:8080/share/" + ID + "/"],
- ["not a share path", "http://localhost:8080/files/" + ID],
- ["bad id chars", "http://localhost:8080/share/..%2F..%2Fsystem/"],
- ["id too short", "http://localhost:8080/share/abc/"],
- ["folder listing", "http://localhost:8080/share/"],
- ["other share op", "http://localhost:8080/share/opg/123/" + ID]
- ].forEach(function (c) { throws("parse refuses " + c[0], function () { S.parse(c[1]); }); });
- /* ---- file names ---- */
- eq("name kept", S.fileName("document", ["Report.doca"]), "Report.doca");
- eq("first usable wins", S.fileName("document", [null, "", "B.doca"]), "B.doca");
- eq("wrong ext replaced", S.fileName("spreadsheet", ["Budget.doca"]), "Budget.xlsa");
- eq("no ext added", S.fileName("presentation", ["Pitch"]), "Pitch.ppta");
- eq("ext case-insensitive", S.fileName("document", ["A.DOCA"]), "A.DOCA");
- eq("default name", S.fileName("spreadsheet", []), "Shared spreadsheet.xlsa");
- eq("path stripped", S.fileName("document", ["../../etc/x.doca"]), "x.doca");
- eq("backslash path stripped", S.fileName("document", ["C:\\a\\y.doca"]), "y.doca");
- eq("control chars stripped", S.fileName("document", ["a\u0000b\n.doca"]), "ab.doca");
- eq("bare extension gets default", S.fileName("document", [".doca"]), "Shared document.doca");
- /* ---- Content-Disposition ---- */
- eq("disposition quoted", S.dispositionName('inline; filename="HelloWorld.doca"'), "HelloWorld.doca");
- eq("disposition bare", S.dispositionName("inline; filename=Plain.xlsa"), "Plain.xlsa");
- eq("disposition escaped quote", S.dispositionName('inline; filename="say \\"hi\\".ppta"'), 'say "hi".ppta');
- eq("disposition rfc2231 wins", S.dispositionName(
- "inline; filename*=utf-8''%E5%A0%B1%E5%91%8A.doca; filename=\"fallback.doca\""), "\u5831\u544a.doca");
- eq("disposition absent", S.dispositionName(null), "");
- eq("disposition without name", S.dispositionName("inline"), "");
- /* ---- appOf ---- */
- function containerFor(app) {
- return OfficeContainer.pack(JSON.stringify({
- type: "arozos-office", app: app, version: 1, body: {}
- }));
- }
- eq("appOf document", S.appOf(containerFor("document")), "document");
- eq("appOf spreadsheet", S.appOf(containerFor("spreadsheet")), "spreadsheet");
- eq("appOf presentation", S.appOf(containerFor("presentation")), "presentation");
- eq("appOf unknown app", S.appOf(containerFor("paint")), null);
- eq("appOf plain JSON document",
- S.appOf(OfficeContainer.utf8Encode('{"app":"spreadsheet","body":{}}')), "spreadsheet");
- eq("appOf html page", S.appOf(OfficeContainer.utf8Encode("<!DOCTYPE html><html>")), null);
- eq("appOf garbage zip", S.appOf(new Uint8Array([0x50, 0x4B, 1, 2, 3])), null);
- eq("appOf empty", S.appOf(new Uint8Array(0)), null);
- console.log(passes + " passed, " + failures + " failed");
- process.exit(failures ? 1 : 0);
|