Use session storage instead of location.hash
This commit is contained in:
parent
7cf9537f3e
commit
69c66e7d99
|
@ -1,38 +0,0 @@
|
|||
// @ts-check
|
||||
|
||||
/**
|
||||
* Convert a `Uint8Array` to a URL-safe base64 string.
|
||||
* @param {Uint8Array} bytes
|
||||
* @returns {string}
|
||||
*/
|
||||
export const stringify = (bytes) => {
|
||||
const string = String.fromCharCode(...bytes);
|
||||
const base64 = btoa(string);
|
||||
return base64
|
||||
.replaceAll("+", "-")
|
||||
.replaceAll("/", "_")
|
||||
.replaceAll("=", "");
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a URL-safe base64 string to a `Uint8Array`.
|
||||
* Returns `null` if the string is invalid.
|
||||
* @param {string} text
|
||||
* @returns {null | Uint8Array}
|
||||
*/
|
||||
export const parse = (text) => {
|
||||
const normalizedText = text
|
||||
.replaceAll("-", "+")
|
||||
.replaceAll("_", "/")
|
||||
.replaceAll(" ", "+");
|
||||
try {
|
||||
const string = atob(normalizedText);
|
||||
const bytes = new Uint8Array(string.length);
|
||||
for (let i = 0; i < string.length; i++) {
|
||||
bytes[i] = string.charCodeAt(i);
|
||||
}
|
||||
return bytes;
|
||||
} catch (_err) {
|
||||
return null;
|
||||
}
|
||||
};
|
|
@ -1,41 +0,0 @@
|
|||
// @ts-check
|
||||
|
||||
import maybeJsonParse from "../common/maybeJsonParse.js";
|
||||
import * as base64url from "../common/base64url.js";
|
||||
|
||||
/**
|
||||
* Parse a location hash into `name` and `bytes`.
|
||||
* @param {string} hash
|
||||
* @returns {null | { name: string, bytes: Uint8Array }} The parsed data, or `null` if the hash can't be parsed.
|
||||
*/
|
||||
export default (hash) => {
|
||||
const normalizedHash = decodeURI(hash.replace(/^#/, ""));
|
||||
|
||||
const parsed = maybeJsonParse(normalizedHash);
|
||||
if (!parsed || typeof parsed !== "object") {
|
||||
console.warn("Couldn't parse hash as JSON object");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
!("name" in parsed) || (typeof parsed.name !== "string") ||
|
||||
!("bytes" in parsed) || (typeof parsed.bytes !== "string")
|
||||
) {
|
||||
console.warn("Hash fields missing or invalid type");
|
||||
return null;
|
||||
}
|
||||
|
||||
const { name } = parsed;
|
||||
if (!name) {
|
||||
console.warn("Name is empty");
|
||||
return null;
|
||||
}
|
||||
|
||||
const bytes = base64url.parse(parsed.bytes);
|
||||
if (!bytes || !bytes.byteLength) {
|
||||
console.warn("Bytes is empty");
|
||||
return null;
|
||||
}
|
||||
|
||||
return { name, bytes };
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
/*! base64-js
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Jameson Little
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// deno-lint-ignore-file
|
||||
// deno-fmt-ignore-file
|
||||
|
||||
var B=Object.create;var l=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var H=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports),U=(r,e)=>{for(var t in e)l(r,t,{get:e[t],enumerable:!0})},A=(r,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of k(e))!j.call(r,o)&&o!==t&&l(r,o,{get:()=>e[o],enumerable:!(a=_(e,o))||a.enumerable});return r},u=(r,e,t)=>(A(r,e,"default"),t&&A(t,e,"default")),C=(r,e,t)=>(t=r!=null?B(w(r)):{},A(e||!r||!r.__esModule?l(t,"default",{value:r,enumerable:!0}):t,r));var p=H(y=>{"use strict";y.byteLength=I;y.toByteArray=T;y.fromByteArray=D;var h=[],d=[],E=typeof Uint8Array<"u"?Uint8Array:Array,s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(F=0,L=s.length;F<L;++F)h[F]=s[F],d[s.charCodeAt(F)]=F;var F,L;d["-".charCodeAt(0)]=62;d["_".charCodeAt(0)]=63;function g(r){var e=r.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var t=r.indexOf("=");t===-1&&(t=e);var a=t===e?0:4-t%4;return[t,a]}function I(r){var e=g(r),t=e[0],a=e[1];return(t+a)*3/4-a}function O(r,e,t){return(e+t)*3/4-t}function T(r){var e,t=g(r),a=t[0],o=t[1],n=new E(O(r,a,o)),v=0,x=o>0?a-4:a,f;for(f=0;f<x;f+=4)e=d[r.charCodeAt(f)]<<18|d[r.charCodeAt(f+1)]<<12|d[r.charCodeAt(f+2)]<<6|d[r.charCodeAt(f+3)],n[v++]=e>>16&255,n[v++]=e>>8&255,n[v++]=e&255;return o===2&&(e=d[r.charCodeAt(f)]<<2|d[r.charCodeAt(f+1)]>>4,n[v++]=e&255),o===1&&(e=d[r.charCodeAt(f)]<<10|d[r.charCodeAt(f+1)]<<4|d[r.charCodeAt(f+2)]>>2,n[v++]=e>>8&255,n[v++]=e&255),n}function q(r){return h[r>>18&63]+h[r>>12&63]+h[r>>6&63]+h[r&63]}function z(r,e,t){for(var a,o=[],n=e;n<t;n+=3)a=(r[n]<<16&16711680)+(r[n+1]<<8&65280)+(r[n+2]&255),o.push(q(a));return o.join("")}function D(r){for(var e,t=r.length,a=t%3,o=[],n=16383,v=0,x=t-a;v<x;v+=n)o.push(z(r,v,v+n>x?x:v+n));return a===1?(e=r[t-1],o.push(h[e>>2]+h[e<<4&63]+"==")):a===2&&(e=(r[t-2]<<8)+r[t-1],o.push(h[e>>10]+h[e>>4&63]+h[e<<2&63]+"=")),o.join("")}});var c={};U(c,{byteLength:()=>G,default:()=>N,fromByteArray:()=>K,toByteArray:()=>J});var i=C(p());u(c,C(p()));var{byteLength:G,toByteArray:J,fromByteArray:K}=i,{default:m,...M}=i,N=m!==void 0?m:M;export{G as byteLength,N as default,K as fromByteArray,J as toByteArray};
|
|
@ -1,17 +1,16 @@
|
|||
// @ts-check
|
||||
|
||||
import parseHash from "../common/parseHash.js";
|
||||
import * as base64 from "../common/vendor/base64-js.js";
|
||||
|
||||
const main = () => {
|
||||
// TODO: We may want a better UI here.
|
||||
// TODO: Handle hash changes.
|
||||
const parsedHash = parseHash(location.hash);
|
||||
if (!parsedHash) {
|
||||
// TODO: Handle errors.
|
||||
const fileDataBase64 = window.sessionStorage.getItem("fileData");
|
||||
if (!fileDataBase64) {
|
||||
location.href = "..";
|
||||
return;
|
||||
}
|
||||
|
||||
const { bytes } = parsedHash;
|
||||
const bytes = base64.toByteArray(fileDataBase64);
|
||||
|
||||
console.log(bytes);
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// @ts-check
|
||||
|
||||
import * as base64 from "../common/vendor/base64-js.js";
|
||||
import { SUPPORTED_FILE_TYPES } from "./constants.js";
|
||||
import crel from "../common/crel.js";
|
||||
import * as base64url from "../common/base64url.js";
|
||||
import routeFile from "./routeFile.js";
|
||||
|
||||
const accept = SUPPORTED_FILE_TYPES
|
||||
|
@ -51,16 +51,6 @@ const disclaimerParagraphEl = crel(
|
|||
crel("small", {}, "Your files do not leave your computer."),
|
||||
);
|
||||
|
||||
/**
|
||||
* @param {Blob} blob
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
const formatBytes = async (blob) => {
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
const bytes = new Uint8Array(arrayBuffer);
|
||||
return base64url.stringify(bytes);
|
||||
};
|
||||
|
||||
const main = () => {
|
||||
const appEl = document.getElementById("app");
|
||||
if (!appEl) throw new Error("HTML is not set up correctly");
|
||||
|
@ -81,10 +71,10 @@ const main = () => {
|
|||
return;
|
||||
}
|
||||
|
||||
location.href = route + "#" + JSON.stringify({
|
||||
name: file.name,
|
||||
bytes: await formatBytes(file),
|
||||
});
|
||||
const fileData = new Uint8Array(await file.arrayBuffer());
|
||||
window.sessionStorage.setItem("fileData", base64.fromByteArray(fileData));
|
||||
|
||||
location.href = route;
|
||||
});
|
||||
|
||||
appEl.append(labelParagraphEl, inputContainerEl, disclaimerParagraphEl);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @ts-check
|
||||
|
||||
import parseHash from "../common/parseHash.js";
|
||||
import * as base64 from "../common/vendor/base64-js.js";
|
||||
import parsePng from "./parsePng.js";
|
||||
import getNodeUi from "./getNodeUi.js";
|
||||
import explorer from "./explorer.js";
|
||||
|
@ -11,14 +11,13 @@ if (!errorEl || !explorerEl) throw new Error("HTML is not set up correctly");
|
|||
|
||||
const main = () => {
|
||||
// TODO: We may want a better UI here.
|
||||
// TODO: Handle hash changes.
|
||||
const parsedHash = parseHash(location.hash);
|
||||
if (!parsedHash) {
|
||||
// TODO: Handle errors.
|
||||
const fileDataBase64 = window.sessionStorage.getItem("fileData");
|
||||
if (!fileDataBase64) {
|
||||
location.href = "..";
|
||||
return;
|
||||
}
|
||||
|
||||
const { bytes } = parsedHash;
|
||||
const bytes = base64.toByteArray(fileDataBase64);
|
||||
|
||||
const rootNode = parsePng(bytes);
|
||||
if (!rootNode) {
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import { assertEquals } from "assert";
|
||||
import { b } from "../helpers.ts";
|
||||
import * as base64url from "../../public/common/base64url.js";
|
||||
|
||||
Deno.test('encodes no bytes as ""', () => {
|
||||
assertEquals(base64url.stringify(b()), "");
|
||||
});
|
||||
|
||||
Deno.test("encodes in a URL-safe way", () => {
|
||||
const input = b(105, 183, 62, 249, 215, 191, 254);
|
||||
assertEquals(
|
||||
base64url.stringify(input),
|
||||
"abc--de__g",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("decodes the empty string", () => {
|
||||
assertEquals(base64url.parse(""), b());
|
||||
});
|
||||
|
||||
Deno.test("decodes URL-safe strings", () => {
|
||||
assertEquals(base64url.parse("_-o"), b(255, 234));
|
||||
});
|
||||
|
||||
Deno.test("decodes URL-unsafe strings (as a bonus)", () => {
|
||||
assertEquals(base64url.parse("/+o="), b(255, 234));
|
||||
});
|
||||
|
||||
Deno.test("round-trips", () => {
|
||||
const testCases = [
|
||||
b(),
|
||||
b(1),
|
||||
b(1, 2, 3),
|
||||
b(255, 234),
|
||||
b(105, 183, 62, 249, 215, 191, 254),
|
||||
];
|
||||
|
||||
for (const original of testCases) {
|
||||
const string = base64url.stringify(original);
|
||||
const parsed = base64url.parse(string);
|
||||
assertEquals(parsed, original, `Round-trip failed for ${original}`);
|
||||
}
|
||||
});
|
|
@ -1,35 +0,0 @@
|
|||
import { assertEquals } from "assert";
|
||||
import { stubbingWarn } from "../helpers.ts";
|
||||
import parseHash from "../../public/common/parseHash.js";
|
||||
|
||||
Deno.test(
|
||||
"returns null if hash cannot be parsed",
|
||||
stubbingWarn(() => {
|
||||
const testCases = [
|
||||
// Missing fields
|
||||
"#null",
|
||||
"#{}",
|
||||
"#{%22name%22:%22image.png%22}",
|
||||
"#{%22bytes%22:%22AQID%22}",
|
||||
// Invalid JSON
|
||||
"",
|
||||
"#{%22name%22:%22small.png%22,%22bytes%22:%22iAQID",
|
||||
];
|
||||
|
||||
for (const testCase of testCases) {
|
||||
assertEquals(
|
||||
parseHash(testCase),
|
||||
null,
|
||||
`Parsing ${testCase} should fail`,
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
Deno.test("parses hashes", () => {
|
||||
const hash = "#{%22name%22:%22small.png%22,%22bytes%22:%22AQID%22}";
|
||||
assertEquals(parseHash(hash), {
|
||||
name: "small.png",
|
||||
bytes: new Uint8Array([1, 2, 3]),
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue