react-cheminfo 0.52.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -31
- package/lib/i18n/core/chromeCatalog.d.ts +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
- package/lib/language/ui/siteLanguageContext.d.ts.map +1 -1
- package/lib/language/ui/siteLanguageContext.js +2 -1
- package/lib/language/ui/siteLanguageContext.js.map +1 -1
- package/lib/locales/de.json +5 -0
- package/lib/locales/en.json +5 -0
- package/lib/locales/es.json +5 -0
- package/lib/locales/fr.json +5 -0
- package/lib/locales/it.json +5 -0
- package/lib/router/core/history.d.ts +4 -3
- package/lib/router/core/history.d.ts.map +1 -1
- package/lib/router/core/history.js +9 -13
- package/lib/router/core/history.js.map +1 -1
- package/lib/router/core/index.d.ts +2 -0
- package/lib/router/core/index.d.ts.map +1 -1
- package/lib/router/core/index.js +1 -0
- package/lib/router/core/index.js.map +1 -1
- package/lib/router/core/pageAddress.d.ts +61 -0
- package/lib/router/core/pageAddress.d.ts.map +1 -0
- package/lib/router/core/pageAddress.js +69 -0
- package/lib/router/core/pageAddress.js.map +1 -0
- package/lib/share/core/index.d.ts +4 -0
- package/lib/share/core/index.d.ts.map +1 -1
- package/lib/share/core/index.js +2 -0
- package/lib/share/core/index.js.map +1 -1
- package/lib/share/core/preferences.d.ts +2 -2
- package/lib/share/core/preferences.d.ts.map +1 -1
- package/lib/share/core/preferences.js +8 -3
- package/lib/share/core/preferences.js.map +1 -1
- package/lib/share/core/seal.d.ts +42 -0
- package/lib/share/core/seal.d.ts.map +1 -0
- package/lib/share/core/seal.js +185 -0
- package/lib/share/core/seal.js.map +1 -0
- package/lib/share/core/sealedAddress.d.ts +31 -0
- package/lib/share/core/sealedAddress.d.ts.map +1 -0
- package/lib/share/core/sealedAddress.js +38 -0
- package/lib/share/core/sealedAddress.js.map +1 -0
- package/lib/share/ui/SealedLinkRefused.d.ts +17 -0
- package/lib/share/ui/SealedLinkRefused.d.ts.map +1 -0
- package/lib/share/ui/SealedLinkRefused.js +23 -0
- package/lib/share/ui/SealedLinkRefused.js.map +1 -0
- package/lib/share/ui/ShareConfigOptions.d.ts +12 -1
- package/lib/share/ui/ShareConfigOptions.d.ts.map +1 -1
- package/lib/share/ui/ShareConfigOptions.js +4 -3
- package/lib/share/ui/ShareConfigOptions.js.map +1 -1
- package/lib/share/ui/ShareDialogContent.d.ts.map +1 -1
- package/lib/share/ui/ShareDialogContent.js +20 -6
- package/lib/share/ui/ShareDialogContent.js.map +1 -1
- package/lib/share/ui/ShareLinkBar.d.ts +5 -0
- package/lib/share/ui/ShareLinkBar.d.ts.map +1 -1
- package/lib/share/ui/ShareLinkBar.js +4 -4
- package/lib/share/ui/ShareLinkBar.js.map +1 -1
- package/lib/share/ui/index.d.ts +2 -0
- package/lib/share/ui/index.d.ts.map +1 -1
- package/lib/share/ui/index.js +1 -0
- package/lib/share/ui/index.js.map +1 -1
- package/lib/share/ui/useSealedUrl.d.ts +17 -0
- package/lib/share/ui/useSealedUrl.d.ts.map +1 -0
- package/lib/share/ui/useSealedUrl.js +31 -0
- package/lib/share/ui/useSealedUrl.js.map +1 -0
- package/package.json +1 -1
- package/src/language/ui/siteLanguageContext.ts +2 -1
- package/src/locales/de.json +5 -0
- package/src/locales/en.json +5 -0
- package/src/locales/es.json +5 -0
- package/src/locales/fr.json +5 -0
- package/src/locales/it.json +5 -0
- package/src/router/core/history.ts +9 -15
- package/src/router/core/index.ts +8 -0
- package/src/router/core/pageAddress.ts +110 -0
- package/src/share/core/index.ts +10 -0
- package/src/share/core/preferences.ts +10 -10
- package/src/share/core/seal.ts +233 -0
- package/src/share/core/sealedAddress.ts +48 -0
- package/src/share/ui/SealedLinkRefused.tsx +43 -0
- package/src/share/ui/ShareConfigOptions.tsx +23 -1
- package/src/share/ui/ShareDialogContent.tsx +37 -6
- package/src/share/ui/ShareLinkBar.tsx +9 -1
- package/src/share/ui/index.ts +2 -0
- package/src/share/ui/useSealedUrl.ts +40 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a page reads its own address and writes it back. Normally that is the
|
|
3
|
+
* browser's `location` and `history`; a page opened from a sealed link holds
|
|
4
|
+
* its address in memory instead, so the app navigates as usual while the
|
|
5
|
+
* address bar keeps showing the link that was handed out.
|
|
6
|
+
*/
|
|
7
|
+
/** The part of `window.location` a page reads its address from. */
|
|
8
|
+
export interface PageLocation {
|
|
9
|
+
/** The path of the address. */
|
|
10
|
+
readonly pathname: string;
|
|
11
|
+
/** The query string, with its leading `?` or empty. */
|
|
12
|
+
readonly search: string;
|
|
13
|
+
/** The fragment, with its leading `#` or empty. */
|
|
14
|
+
readonly hash: string;
|
|
15
|
+
}
|
|
16
|
+
/** The part of `window.history` a page writes its address through. */
|
|
17
|
+
export interface PageHistory {
|
|
18
|
+
/** The state of the current entry. */
|
|
19
|
+
readonly state: unknown;
|
|
20
|
+
/**
|
|
21
|
+
* Add an entry.
|
|
22
|
+
* @param data - The state of the new entry.
|
|
23
|
+
* @param unused - Ignored by browsers.
|
|
24
|
+
* @param url - The new address, absolute or relative to the current one.
|
|
25
|
+
*/
|
|
26
|
+
pushState(data: unknown, unused: string, url: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Rewrite the current entry without adding one.
|
|
29
|
+
* @param data - The state to keep.
|
|
30
|
+
* @param unused - Ignored by browsers.
|
|
31
|
+
* @param url - The new address, absolute or relative to the current one.
|
|
32
|
+
*/
|
|
33
|
+
replaceState(data: unknown, unused: string, url: string): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The address the page reads: the held one when there is one, else the
|
|
37
|
+
* browser's.
|
|
38
|
+
* @returns It, or `undefined` where there is no browser.
|
|
39
|
+
*/
|
|
40
|
+
export declare function pageLocation(): PageLocation | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* The history the page writes its address through: the held address when
|
|
43
|
+
* there is one, else the browser's.
|
|
44
|
+
* @returns It, or `undefined` where there is no browser.
|
|
45
|
+
*/
|
|
46
|
+
export declare function pageHistory(): PageHistory | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Hold the page's address in memory from now on. Every read through
|
|
49
|
+
* {@link pageLocation} and every write through {@link pageHistory} uses it, and
|
|
50
|
+
* the browser's address bar is never written again.
|
|
51
|
+
* @param address - The address the page opens on: path, query and fragment.
|
|
52
|
+
*/
|
|
53
|
+
export declare function holdPageAddress(address: string): void;
|
|
54
|
+
/**
|
|
55
|
+
* Whether the page's address is held in memory.
|
|
56
|
+
* @returns True after {@link holdPageAddress}.
|
|
57
|
+
*/
|
|
58
|
+
export declare function isPageAddressHeld(): boolean;
|
|
59
|
+
/** Go back to reading and writing the browser's own address. */
|
|
60
|
+
export declare function releasePageAddress(): void;
|
|
61
|
+
//# sourceMappingURL=pageAddress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageAddress.d.ts","sourceRoot":"","sources":["../../../src/router/core/pageAddress.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5D;;;;;OAKG;IACH,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAChE;AAOD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,YAAY,GAAG,SAAS,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,WAAW,GAAG,SAAS,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAErD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a page reads its own address and writes it back. Normally that is the
|
|
3
|
+
* browser's `location` and `history`; a page opened from a sealed link holds
|
|
4
|
+
* its address in memory instead, so the app navigates as usual while the
|
|
5
|
+
* address bar keeps showing the link that was handed out.
|
|
6
|
+
*/
|
|
7
|
+
// Only parses addresses relative to the held one; never fetched or shown.
|
|
8
|
+
const HELD_ORIGIN = 'https://held.invalid';
|
|
9
|
+
let held;
|
|
10
|
+
/**
|
|
11
|
+
* The address the page reads: the held one when there is one, else the
|
|
12
|
+
* browser's.
|
|
13
|
+
* @returns It, or `undefined` where there is no browser.
|
|
14
|
+
*/
|
|
15
|
+
export function pageLocation() {
|
|
16
|
+
return held ?? globalThis.location;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The history the page writes its address through: the held address when
|
|
20
|
+
* there is one, else the browser's.
|
|
21
|
+
* @returns It, or `undefined` where there is no browser.
|
|
22
|
+
*/
|
|
23
|
+
export function pageHistory() {
|
|
24
|
+
return held ?? globalThis.history;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Hold the page's address in memory from now on. Every read through
|
|
28
|
+
* {@link pageLocation} and every write through {@link pageHistory} uses it, and
|
|
29
|
+
* the browser's address bar is never written again.
|
|
30
|
+
* @param address - The address the page opens on: path, query and fragment.
|
|
31
|
+
*/
|
|
32
|
+
export function holdPageAddress(address) {
|
|
33
|
+
held = new HeldAddress(address);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Whether the page's address is held in memory.
|
|
37
|
+
* @returns True after {@link holdPageAddress}.
|
|
38
|
+
*/
|
|
39
|
+
export function isPageAddressHeld() {
|
|
40
|
+
return held !== undefined;
|
|
41
|
+
}
|
|
42
|
+
/** Go back to reading and writing the browser's own address. */
|
|
43
|
+
export function releasePageAddress() {
|
|
44
|
+
held = undefined;
|
|
45
|
+
}
|
|
46
|
+
class HeldAddress {
|
|
47
|
+
pathname = '/';
|
|
48
|
+
search = '';
|
|
49
|
+
hash = '';
|
|
50
|
+
state = null;
|
|
51
|
+
constructor(address) {
|
|
52
|
+
this.go(null, address);
|
|
53
|
+
}
|
|
54
|
+
pushState(data, unused, url) {
|
|
55
|
+
this.go(data, url);
|
|
56
|
+
}
|
|
57
|
+
replaceState(data, unused, url) {
|
|
58
|
+
this.go(data, url);
|
|
59
|
+
}
|
|
60
|
+
go(data, url) {
|
|
61
|
+
const base = `${HELD_ORIGIN}${this.pathname}${this.search}${this.hash}`;
|
|
62
|
+
const next = new URL(url, base);
|
|
63
|
+
this.pathname = next.pathname;
|
|
64
|
+
this.search = next.search;
|
|
65
|
+
this.hash = next.hash;
|
|
66
|
+
this.state = data;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=pageAddress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageAddress.js","sourceRoot":"","sources":["../../../src/router/core/pageAddress.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgCH,0EAA0E;AAC1E,MAAM,WAAW,GAAG,sBAAsB,CAAC;AAE3C,IAAI,IAA6B,CAAC;AAElC;;;;GAIG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,IAAI,UAAU,CAAC,QAAQ,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,IAAI,UAAU,CAAC,OAAO,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,KAAK,SAAS,CAAC;AAC5B,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,kBAAkB;IAChC,IAAI,GAAG,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,WAAW;IACf,QAAQ,GAAG,GAAG,CAAC;IACf,MAAM,GAAG,EAAE,CAAC;IACZ,IAAI,GAAG,EAAE,CAAC;IACV,KAAK,GAAY,IAAI,CAAC;IAEtB,YAAY,OAAe;QACzB,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,SAAS,CAAC,IAAa,EAAE,MAAc,EAAE,GAAW;QAClD,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,YAAY,CAAC,IAAa,EAAE,MAAc,EAAE,GAAW;QACrD,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACrB,CAAC;IAEO,EAAE,CAAC,IAAa,EAAE,GAAW;QACnC,MAAM,IAAI,GAAG,GAAG,WAAW,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACxE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -11,6 +11,10 @@ export type { PreferenceHistory, PreferenceLocation, SyncPreferencesOptions, Url
|
|
|
11
11
|
export { applyPreferencesFromSearch, syncPreferencesWithUrl, writePreferencesToSearch, } from './preferences.ts';
|
|
12
12
|
export type { SharePreset } from './presets.ts';
|
|
13
13
|
export { applySharePreset, findSharePreset } from './presets.ts';
|
|
14
|
+
export type { SealProblem, UnsealResult } from './seal.ts';
|
|
15
|
+
export { SEAL_PARAM, sealQuery, sealShareUrl, sealedToken, unsealQuery, } from './seal.ts';
|
|
16
|
+
export type { SealedAddress } from './sealedAddress.ts';
|
|
17
|
+
export { canOpenSealedAddresses, openSealedAddress } from './sealedAddress.ts';
|
|
14
18
|
export type { EmbedCodeOptions, ShareUrlOptions } from './url.ts';
|
|
15
19
|
export { buildEmbedCode, buildShareUrl } from './url.ts';
|
|
16
20
|
export type { HideablePart, ShareParamCodecs, ShareParamValues, ShareVocabulary, } from './vocabulary.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/share/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EACL,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,QAAQ,EACR,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EACb,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzD,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,GAChB,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/share/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EACL,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,QAAQ,EACR,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EACb,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EACL,UAAU,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzD,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,GAChB,MAAM,iBAAiB,CAAC"}
|
package/lib/share/core/index.js
CHANGED
|
@@ -5,5 +5,7 @@ export { SHARE_REGIONS_MESSAGE, SHARE_REGIONS_REQUEST, isShareRegionsRequest, re
|
|
|
5
5
|
export { booleanParam, enumParam, integerParam, numberParam, stringParam, } from "./params.js";
|
|
6
6
|
export { applyPreferencesFromSearch, syncPreferencesWithUrl, writePreferencesToSearch, } from "./preferences.js";
|
|
7
7
|
export { applySharePreset, findSharePreset } from "./presets.js";
|
|
8
|
+
export { SEAL_PARAM, sealQuery, sealShareUrl, sealedToken, unsealQuery, } from "./seal.js";
|
|
9
|
+
export { canOpenSealedAddresses, openSealedAddress } from "./sealedAddress.js";
|
|
8
10
|
export { buildEmbedCode, buildShareUrl } from "./url.js";
|
|
9
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/share/core/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,QAAQ,EACR,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AAQtB,OAAO,EACL,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,aAAa,CAAC;AAQrB,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEjE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/share/core/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,QAAQ,EACR,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AAQtB,OAAO,EACL,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,aAAa,CAAC;AAQrB,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEjE,OAAO,EACL,UAAU,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE/E,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -48,12 +48,12 @@ export interface SyncPreferencesOptions {
|
|
|
48
48
|
subscribe: (listener: () => void) => () => void;
|
|
49
49
|
/**
|
|
50
50
|
* The address to read and keep up to date.
|
|
51
|
-
* @default
|
|
51
|
+
* @default pageLocation()
|
|
52
52
|
*/
|
|
53
53
|
location?: PreferenceLocation;
|
|
54
54
|
/**
|
|
55
55
|
* The history to rewrite.
|
|
56
|
-
* @default
|
|
56
|
+
* @default pageHistory()
|
|
57
57
|
*/
|
|
58
58
|
history?: PreferenceHistory;
|
|
59
59
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../../../src/share/core/preferences.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../../../src/share/core/preferences.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAInD;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK;IAClC,wFAAwF;IACxF,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B;;;OAGG;IACH,GAAG,IAAI,KAAK,CAAC;IACb;;;OAGG;IACH,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACzB;AAED,yEAAyE;AACzE,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAE9E,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,oEAAoE;AACpE,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAChE;AAED,oDAAoD;AACpD,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,WAAW,EAAE,cAAc,CAAC;IAC5B,sGAAsG;IACtG,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAChD;;;OAGG;IACH,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,cAAc,GAC1B,MAAM,EAAE,CAWV;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,cAAc,GAC1B,MAAM,CAuBR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,sBAAsB,GAC9B,MAAM,IAAI,CA0BZ"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { pageHistory, pageLocation } from "../../router/core/pageAddress.js";
|
|
1
2
|
import { EMBED_PARAM, HIDE_PARAM } from "./config.js";
|
|
2
3
|
import { firstValues, parseQuery, serializeQuery } from "./query.js";
|
|
3
4
|
/**
|
|
@@ -85,11 +86,15 @@ export function writePreferencesToSearch(search, preferences) {
|
|
|
85
86
|
* @returns A function that stops rewriting the address.
|
|
86
87
|
*/
|
|
87
88
|
export function syncPreferencesWithUrl(options) {
|
|
88
|
-
const { preferences, subscribe
|
|
89
|
+
const { preferences, subscribe } = options;
|
|
90
|
+
const location = options.location ?? pageLocation();
|
|
91
|
+
const history = options.history ?? pageHistory();
|
|
89
92
|
assertPreferenceNames(preferences);
|
|
93
|
+
if (location === undefined || history === undefined)
|
|
94
|
+
return () => undefined;
|
|
90
95
|
applyPreferencesFromSearch(location.search, preferences);
|
|
91
96
|
let active = true;
|
|
92
|
-
|
|
97
|
+
const write = () => {
|
|
93
98
|
if (!active)
|
|
94
99
|
return;
|
|
95
100
|
const current = location.search;
|
|
@@ -98,7 +103,7 @@ export function syncPreferencesWithUrl(options) {
|
|
|
98
103
|
return;
|
|
99
104
|
const query = next === '' ? '' : `?${next}`;
|
|
100
105
|
history.replaceState(history.state, '', `${location.pathname}${query}${location.hash}`);
|
|
101
|
-
}
|
|
106
|
+
};
|
|
102
107
|
const unsubscribe = subscribe(write);
|
|
103
108
|
write();
|
|
104
109
|
return () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preferences.js","sourceRoot":"","sources":["../../../src/share/core/preferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGtD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAiErE;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAc,EACd,WAA2B;IAE3B,qBAAqB,CAAC,WAAW,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7D,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS;QAChC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CACtC,MAAc,EACd,WAA2B;IAE3B,qBAAqB,CAAC,WAAW,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IACjD,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QACD,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC9B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,OAAO,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAA+B;IAE/B,MAAM,
|
|
1
|
+
{"version":3,"file":"preferences.js","sourceRoot":"","sources":["../../../src/share/core/preferences.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** The query parameter a sealed link carries, and the only one it carries. */
|
|
2
|
+
export declare const SEAL_PARAM = "s";
|
|
3
|
+
/** Why a sealed link could not be opened. */
|
|
4
|
+
export type SealProblem = 'malformed' | 'tampered' | 'unsupported';
|
|
5
|
+
/** What opening a sealed link gave. */
|
|
6
|
+
export type UnsealResult = {
|
|
7
|
+
ok: true;
|
|
8
|
+
query: string;
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
problem: SealProblem;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Seal a query string: compressed when that makes it shorter, then encrypted
|
|
15
|
+
* under a tag computed from it, so the token can be neither read nor edited
|
|
16
|
+
* without the key, and the same query always gives the same token.
|
|
17
|
+
* @param query - The query string the page is to read, without its leading `?`.
|
|
18
|
+
* @returns The token, `e1.` followed by base64url.
|
|
19
|
+
*/
|
|
20
|
+
export declare function sealQuery(query: string): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Open a token written by {@link sealQuery}. Never throws: a token that was
|
|
23
|
+
* edited, cut, or minted by a newer key is answered with the reason.
|
|
24
|
+
* @param token - The value of the `s` parameter.
|
|
25
|
+
* @returns The query string it carries, or why it cannot be opened.
|
|
26
|
+
*/
|
|
27
|
+
export declare function unsealQuery(token: string): Promise<UnsealResult>;
|
|
28
|
+
/**
|
|
29
|
+
* The sealed token a query string carries.
|
|
30
|
+
* @param search - The query string, with or without its leading `?`.
|
|
31
|
+
* @returns The value of `s`, or `null` when the address is not sealed.
|
|
32
|
+
*/
|
|
33
|
+
export declare function sealedToken(search: string): string | null;
|
|
34
|
+
/**
|
|
35
|
+
* Turn a share link into its sealed form: the same page, with everything its
|
|
36
|
+
* query string said moved into one `s` token. A sealed page is always
|
|
37
|
+
* embedded, so the token says `embed=1` whatever the link said.
|
|
38
|
+
* @param url - The absolute share link.
|
|
39
|
+
* @returns The sealed link.
|
|
40
|
+
*/
|
|
41
|
+
export declare function sealShareUrl(url: string): Promise<string>;
|
|
42
|
+
//# sourceMappingURL=seal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seal.d.ts","sourceRoot":"","sources":["../../../src/share/core/seal.ts"],"names":[],"mappings":"AAGA,8EAA8E;AAC9E,eAAO,MAAM,UAAU,MAAM,CAAC;AAE9B,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,aAAa,CAAC;AAEnE,uCAAuC;AACvC,MAAM,MAAM,YAAY,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AA0BpE;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgB9D;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAkCtE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEzD;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAS/D"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { EMBED_PARAM } from "./config.js";
|
|
2
|
+
import { firstValues, parseQuery, serializeQuery } from "./query.js";
|
|
3
|
+
/** The query parameter a sealed link carries, and the only one it carries. */
|
|
4
|
+
export const SEAL_PARAM = 's';
|
|
5
|
+
// The key is in every page that opens a sealed link, so it is not a secret: the
|
|
6
|
+
// seal keeps a class from reading or editing a link, not someone who digs the
|
|
7
|
+
// key out of the bundle. The version prefix of a token picks its key, so a new
|
|
8
|
+
// key ships under a new version and every older link keeps opening.
|
|
9
|
+
const KEYRING = {
|
|
10
|
+
e1: 'MOCyEX25cEtWf2QJ6Ux_2lFxN_4oCwjtqyOkOC4tCXA',
|
|
11
|
+
};
|
|
12
|
+
const CURRENT_VERSION = 'e1';
|
|
13
|
+
// The tag is an HMAC of the message, and also the counter the message is
|
|
14
|
+
// encrypted under: the synthetic-IV construction. One 8-byte value both refuses
|
|
15
|
+
// an edited link and makes sealing deterministic, so the same query always
|
|
16
|
+
// gives the same link.
|
|
17
|
+
const TAG_LENGTH = 8;
|
|
18
|
+
const COUNTER_BITS = 64;
|
|
19
|
+
const COMPRESSED = 1;
|
|
20
|
+
const keys = new Map();
|
|
21
|
+
/**
|
|
22
|
+
* Seal a query string: compressed when that makes it shorter, then encrypted
|
|
23
|
+
* under a tag computed from it, so the token can be neither read nor edited
|
|
24
|
+
* without the key, and the same query always gives the same token.
|
|
25
|
+
* @param query - The query string the page is to read, without its leading `?`.
|
|
26
|
+
* @returns The token, `e1.` followed by base64url.
|
|
27
|
+
*/
|
|
28
|
+
export async function sealQuery(query) {
|
|
29
|
+
const plain = new TextEncoder().encode(query);
|
|
30
|
+
const packed = await transform(plain, new CompressionStream('deflate-raw'));
|
|
31
|
+
const compressed = packed.length < plain.length;
|
|
32
|
+
const body = compressed ? packed : plain;
|
|
33
|
+
const message = new Uint8Array(1 + body.length);
|
|
34
|
+
message[0] = compressed ? COMPRESSED : 0;
|
|
35
|
+
message.set(body, 1);
|
|
36
|
+
const { cipher, mac } = await keysOf(CURRENT_VERSION);
|
|
37
|
+
const tag = await tagOf(mac, CURRENT_VERSION, message);
|
|
38
|
+
const encrypted = await crypto.subtle.encrypt(ctr(tag), cipher, message);
|
|
39
|
+
const sealed = new Uint8Array(TAG_LENGTH + encrypted.byteLength);
|
|
40
|
+
sealed.set(tag);
|
|
41
|
+
sealed.set(new Uint8Array(encrypted), TAG_LENGTH);
|
|
42
|
+
return `${CURRENT_VERSION}.${toBase64Url(sealed)}`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Open a token written by {@link sealQuery}. Never throws: a token that was
|
|
46
|
+
* edited, cut, or minted by a newer key is answered with the reason.
|
|
47
|
+
* @param token - The value of the `s` parameter.
|
|
48
|
+
* @returns The query string it carries, or why it cannot be opened.
|
|
49
|
+
*/
|
|
50
|
+
export async function unsealQuery(token) {
|
|
51
|
+
const dot = token.indexOf('.');
|
|
52
|
+
if (dot === -1)
|
|
53
|
+
return { ok: false, problem: 'malformed' };
|
|
54
|
+
const version = token.slice(0, dot);
|
|
55
|
+
if (!Object.hasOwn(KEYRING, version)) {
|
|
56
|
+
return { ok: false, problem: 'unsupported' };
|
|
57
|
+
}
|
|
58
|
+
const sealed = fromBase64Url(token.slice(dot + 1));
|
|
59
|
+
if (sealed === null || sealed.length <= TAG_LENGTH) {
|
|
60
|
+
return { ok: false, problem: 'malformed' };
|
|
61
|
+
}
|
|
62
|
+
const { cipher, mac } = await keysOf(version);
|
|
63
|
+
const tag = sealed.subarray(0, TAG_LENGTH);
|
|
64
|
+
const message = new Uint8Array(await crypto.subtle.decrypt(ctr(tag), cipher, sealed.subarray(TAG_LENGTH)));
|
|
65
|
+
if (!sameBytes(tag, await tagOf(mac, version, message))) {
|
|
66
|
+
return { ok: false, problem: 'tampered' };
|
|
67
|
+
}
|
|
68
|
+
const flags = message[0] ?? 0;
|
|
69
|
+
if (flags > COMPRESSED)
|
|
70
|
+
return { ok: false, problem: 'unsupported' };
|
|
71
|
+
const body = message.subarray(1);
|
|
72
|
+
try {
|
|
73
|
+
const plain = flags === COMPRESSED
|
|
74
|
+
? await transform(body, new DecompressionStream('deflate-raw'))
|
|
75
|
+
: body;
|
|
76
|
+
const query = new TextDecoder('utf-8', { fatal: true }).decode(plain);
|
|
77
|
+
return { ok: true, query };
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return { ok: false, problem: 'malformed' };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The sealed token a query string carries.
|
|
85
|
+
* @param search - The query string, with or without its leading `?`.
|
|
86
|
+
* @returns The value of `s`, or `null` when the address is not sealed.
|
|
87
|
+
*/
|
|
88
|
+
export function sealedToken(search) {
|
|
89
|
+
return firstValues(parseQuery(search)).get(SEAL_PARAM) ?? null;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Turn a share link into its sealed form: the same page, with everything its
|
|
93
|
+
* query string said moved into one `s` token. A sealed page is always
|
|
94
|
+
* embedded, so the token says `embed=1` whatever the link said.
|
|
95
|
+
* @param url - The absolute share link.
|
|
96
|
+
* @returns The sealed link.
|
|
97
|
+
*/
|
|
98
|
+
export async function sealShareUrl(url) {
|
|
99
|
+
const address = new URL(url);
|
|
100
|
+
const entries = parseQuery(address.search).filter(([key]) => key !== EMBED_PARAM && key !== SEAL_PARAM);
|
|
101
|
+
entries.push([EMBED_PARAM, '1']);
|
|
102
|
+
const token = await sealQuery(serializeQuery(entries));
|
|
103
|
+
address.search = `?${SEAL_PARAM}=${token}`;
|
|
104
|
+
return address.href;
|
|
105
|
+
}
|
|
106
|
+
function keysOf(version) {
|
|
107
|
+
let pair = keys.get(version);
|
|
108
|
+
if (pair === undefined) {
|
|
109
|
+
pair = deriveKeys(version);
|
|
110
|
+
keys.set(version, pair);
|
|
111
|
+
}
|
|
112
|
+
return pair;
|
|
113
|
+
}
|
|
114
|
+
// One key per purpose, both derived from the version's key, since a key is
|
|
115
|
+
// never used for two algorithms.
|
|
116
|
+
async function deriveKeys(version) {
|
|
117
|
+
const raw = fromBase64Url(KEYRING[version] ?? '') ?? new Uint8Array();
|
|
118
|
+
const base = await crypto.subtle.importKey('raw', raw, 'HKDF', false, [
|
|
119
|
+
'deriveKey',
|
|
120
|
+
]);
|
|
121
|
+
function derive(purpose, algorithm, usages) {
|
|
122
|
+
const info = new TextEncoder().encode(`cheminfo seal ${version} ${purpose}`);
|
|
123
|
+
return crypto.subtle.deriveKey({ name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(), info }, base, algorithm, false, usages);
|
|
124
|
+
}
|
|
125
|
+
const [cipher, mac] = await Promise.all([
|
|
126
|
+
derive('cipher', { name: 'AES-CTR', length: 256 }, ['encrypt', 'decrypt']),
|
|
127
|
+
derive('mac', { name: 'HMAC', hash: 'SHA-256', length: 256 }, ['sign']),
|
|
128
|
+
]);
|
|
129
|
+
return { cipher, mac };
|
|
130
|
+
}
|
|
131
|
+
// The version is signed with the message, so a token cannot be moved under
|
|
132
|
+
// another version's key.
|
|
133
|
+
async function tagOf(mac, version, message) {
|
|
134
|
+
const prefix = new TextEncoder().encode(`${version}.`);
|
|
135
|
+
const signed = new Uint8Array(prefix.length + message.length);
|
|
136
|
+
signed.set(prefix);
|
|
137
|
+
signed.set(message, prefix.length);
|
|
138
|
+
const digest = await crypto.subtle.sign('HMAC', mac, signed);
|
|
139
|
+
return new Uint8Array(digest, 0, TAG_LENGTH);
|
|
140
|
+
}
|
|
141
|
+
function ctr(tag) {
|
|
142
|
+
const counter = new Uint8Array(16);
|
|
143
|
+
counter.set(tag);
|
|
144
|
+
return { name: 'AES-CTR', counter, length: COUNTER_BITS };
|
|
145
|
+
}
|
|
146
|
+
function sameBytes(left, right) {
|
|
147
|
+
if (left.length !== right.length)
|
|
148
|
+
return false;
|
|
149
|
+
let difference = 0;
|
|
150
|
+
for (let index = 0; index < left.length; index++) {
|
|
151
|
+
difference |= (left[index] ?? 0) ^ (right[index] ?? 0);
|
|
152
|
+
}
|
|
153
|
+
return difference === 0;
|
|
154
|
+
}
|
|
155
|
+
async function transform(bytes, stream) {
|
|
156
|
+
const source = new ReadableStream({
|
|
157
|
+
start(controller) {
|
|
158
|
+
controller.enqueue(bytes);
|
|
159
|
+
controller.close();
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
const output = await new Response(source.pipeThrough(stream)).arrayBuffer();
|
|
163
|
+
return new Uint8Array(output);
|
|
164
|
+
}
|
|
165
|
+
function toBase64Url(bytes) {
|
|
166
|
+
let binary = '';
|
|
167
|
+
for (const byte of bytes)
|
|
168
|
+
binary += String.fromCodePoint(byte);
|
|
169
|
+
return btoa(binary)
|
|
170
|
+
.replaceAll('+', '-')
|
|
171
|
+
.replaceAll('/', '_')
|
|
172
|
+
.replace(/[=]+$/, '');
|
|
173
|
+
}
|
|
174
|
+
function fromBase64Url(text) {
|
|
175
|
+
if (!/^[\w-]*$/.test(text) || text.length % 4 === 1)
|
|
176
|
+
return null;
|
|
177
|
+
const base64 = text.replaceAll('-', '+').replaceAll('_', '/');
|
|
178
|
+
const binary = atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, '='));
|
|
179
|
+
const bytes = new Uint8Array(binary.length);
|
|
180
|
+
for (let index = 0; index < binary.length; index++) {
|
|
181
|
+
bytes[index] = binary.codePointAt(index) ?? 0;
|
|
182
|
+
}
|
|
183
|
+
return bytes;
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=seal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seal.js","sourceRoot":"","sources":["../../../src/share/core/seal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { PageLocation } from '../../router/core/pageAddress.ts';
|
|
2
|
+
import type { SealProblem } from './seal.ts';
|
|
3
|
+
/** How the page was opened. */
|
|
4
|
+
export type SealedAddress = {
|
|
5
|
+
status: 'plain';
|
|
6
|
+
} | {
|
|
7
|
+
status: 'sealed';
|
|
8
|
+
} | {
|
|
9
|
+
status: 'refused';
|
|
10
|
+
problem: SealProblem;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Open the page's address before anything reads it. A plain address is left
|
|
14
|
+
* as it is. A sealed one is unsealed and held in memory, so the page reads
|
|
15
|
+
* what the token carries through `pageLocation` while the address bar keeps
|
|
16
|
+
* showing the link that was handed out, whatever the page does next.
|
|
17
|
+
*
|
|
18
|
+
* Call it once at startup, and import every module that reads the address
|
|
19
|
+
* only once it has resolved. Calling it is also what lets the share dialog
|
|
20
|
+
* offer to protect a link: a site that never opens a sealed address must not
|
|
21
|
+
* hand one out.
|
|
22
|
+
* @param location - The address the page was opened at.
|
|
23
|
+
* @returns How the page was opened; on `refused` nothing is held.
|
|
24
|
+
*/
|
|
25
|
+
export declare function openSealedAddress(location?: PageLocation | undefined): Promise<SealedAddress>;
|
|
26
|
+
/**
|
|
27
|
+
* Whether this page opens sealed links, so may hand them out.
|
|
28
|
+
* @returns True once {@link openSealedAddress} has been called.
|
|
29
|
+
*/
|
|
30
|
+
export declare function canOpenSealedAddresses(): boolean;
|
|
31
|
+
//# sourceMappingURL=sealedAddress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sealedAddress.d.ts","sourceRoot":"","sources":["../../../src/share/core/sealedAddress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAGrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7C,+BAA+B;AAC/B,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GACnB;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAIhD;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,GAAE,YAAY,GAAG,SAA+B,GACvD,OAAO,CAAC,aAAa,CAAC,CAUxB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { holdPageAddress } from "../../router/core/pageAddress.js";
|
|
2
|
+
import { sealedToken, unsealQuery } from "./seal.js";
|
|
3
|
+
let opensSealedAddresses = false;
|
|
4
|
+
/**
|
|
5
|
+
* Open the page's address before anything reads it. A plain address is left
|
|
6
|
+
* as it is. A sealed one is unsealed and held in memory, so the page reads
|
|
7
|
+
* what the token carries through `pageLocation` while the address bar keeps
|
|
8
|
+
* showing the link that was handed out, whatever the page does next.
|
|
9
|
+
*
|
|
10
|
+
* Call it once at startup, and import every module that reads the address
|
|
11
|
+
* only once it has resolved. Calling it is also what lets the share dialog
|
|
12
|
+
* offer to protect a link: a site that never opens a sealed address must not
|
|
13
|
+
* hand one out.
|
|
14
|
+
* @param location - The address the page was opened at.
|
|
15
|
+
* @returns How the page was opened; on `refused` nothing is held.
|
|
16
|
+
*/
|
|
17
|
+
export async function openSealedAddress(location = globalThis.location) {
|
|
18
|
+
opensSealedAddresses = true;
|
|
19
|
+
if (location === undefined)
|
|
20
|
+
return { status: 'plain' };
|
|
21
|
+
const token = sealedToken(location.search);
|
|
22
|
+
if (token === null)
|
|
23
|
+
return { status: 'plain' };
|
|
24
|
+
const result = await unsealQuery(token);
|
|
25
|
+
if (!result.ok)
|
|
26
|
+
return { status: 'refused', problem: result.problem };
|
|
27
|
+
const query = result.query === '' ? '' : `?${result.query}`;
|
|
28
|
+
holdPageAddress(`${location.pathname}${query}${location.hash}`);
|
|
29
|
+
return { status: 'sealed' };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Whether this page opens sealed links, so may hand them out.
|
|
33
|
+
* @returns True once {@link openSealedAddress} has been called.
|
|
34
|
+
*/
|
|
35
|
+
export function canOpenSealedAddresses() {
|
|
36
|
+
return opensSealedAddresses;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=sealedAddress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sealedAddress.js","sourceRoot":"","sources":["../../../src/share/core/sealedAddress.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAGnE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAQrD,IAAI,oBAAoB,GAAG,KAAK,CAAC;AAEjC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAqC,UAAU,CAAC,QAAQ;IAExD,oBAAoB,GAAG,IAAI,CAAC;IAC5B,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACvD,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC/C,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACtE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;IAC5D,eAAe,CAAC,GAAG,QAAQ,CAAC,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAChE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,oBAAoB,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
export interface SealedLinkRefusedProps {
|
|
3
|
+
/**
|
|
4
|
+
* Where the tool opens without the link.
|
|
5
|
+
* @default the path the link was opened at
|
|
6
|
+
*/
|
|
7
|
+
href?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* What a page shows instead of itself when its sealed link cannot be opened —
|
|
11
|
+
* edited, cut, or minted by a newer key — so it never opens something the link
|
|
12
|
+
* did not say, and never a blank page.
|
|
13
|
+
* @param props - Where the tool opens without the link.
|
|
14
|
+
* @returns The whole page.
|
|
15
|
+
*/
|
|
16
|
+
export declare function SealedLinkRefused(props: SealedLinkRefusedProps): ReactElement;
|
|
17
|
+
//# sourceMappingURL=SealedLinkRefused.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SealedLinkRefused.d.ts","sourceRoot":"","sources":["../../../src/share/ui/SealedLinkRefused.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAC;AAYzD,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CAc7E"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { AnchorButton, NonIdealState } from '@blueprintjs/core';
|
|
3
|
+
import { useChromeT } from "../../i18n/ui/useT.js";
|
|
4
|
+
// A grid, because the card's own `height: 100%` keeps a flex row from
|
|
5
|
+
// stretching it, and it would sit at the top of the page.
|
|
6
|
+
const PAGE_STYLE = {
|
|
7
|
+
display: 'grid',
|
|
8
|
+
minHeight: '100vh',
|
|
9
|
+
placeItems: 'center',
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* What a page shows instead of itself when its sealed link cannot be opened —
|
|
13
|
+
* edited, cut, or minted by a newer key — so it never opens something the link
|
|
14
|
+
* did not say, and never a blank page.
|
|
15
|
+
* @param props - Where the tool opens without the link.
|
|
16
|
+
* @returns The whole page.
|
|
17
|
+
*/
|
|
18
|
+
export function SealedLinkRefused(props) {
|
|
19
|
+
const { href = globalThis.location?.pathname ?? '/' } = props;
|
|
20
|
+
const t = useChromeT();
|
|
21
|
+
return (_jsx("div", { style: PAGE_STYLE, children: _jsx(NonIdealState, { icon: "lock", title: t('seal.refusedTitle'), description: t('seal.refusedBody'), action: _jsx(AnchorButton, { href: href, text: t('seal.openWithout') }) }) }));
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=SealedLinkRefused.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SealedLinkRefused.js","sourceRoot":"","sources":["../../../src/share/ui/SealedLinkRefused.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,sEAAsE;AACtE,0DAA0D;AAC1D,MAAM,UAAU,GAAkB;IAChC,OAAO,EAAE,MAAM;IACf,SAAS,EAAE,OAAO;IAClB,UAAU,EAAE,QAAQ;CACrB,CAAC;AAUF;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAA6B;IAC7D,MAAM,EAAE,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,QAAQ,IAAI,GAAG,EAAE,GAAG,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;IAEvB,OAAO,CACL,cAAK,KAAK,EAAE,UAAU,YACpB,KAAC,aAAa,IACZ,IAAI,EAAC,MAAM,EACX,KAAK,EAAE,CAAC,CAAC,mBAAmB,CAAC,EAC7B,WAAW,EAAE,CAAC,CAAC,kBAAkB,CAAC,EAClC,MAAM,EAAE,KAAC,YAAY,IAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,kBAAkB,CAAC,GAAI,GACjE,GACE,CACP,CAAC;AACJ,CAAC"}
|