@blackbyte/sugar 1.0.0-beta.33 → 1.0.0-beta.34
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/dist/js/dom/query/_exports.d.ts +3 -1
- package/dist/js/dom/query/_exports.js +3 -1
- package/dist/js/dom/query/_exports.js.map +1 -1
- package/dist/js/dom/query/queryStegaElements/queryStegaElements.d.ts +35 -0
- package/dist/js/dom/query/queryStegaElements/queryStegaElements.js +47 -0
- package/dist/js/dom/query/queryStegaElements/queryStegaElements.js.map +1 -0
- package/dist/js/dom/query/queryStegaElementsLive/queryStegaElementsLive.d.ts +65 -0
- package/dist/js/dom/query/queryStegaElementsLive/queryStegaElementsLive.js +151 -0
- package/dist/js/dom/query/queryStegaElementsLive/queryStegaElementsLive.js.map +1 -0
- package/dist/shared/crypto/_exports.d.ts +2 -1
- package/dist/shared/crypto/_exports.js +2 -1
- package/dist/shared/crypto/_exports.js.map +1 -1
- package/dist/shared/crypto/stega/stega.d.ts +53 -0
- package/dist/shared/crypto/stega/stega.js +93 -0
- package/dist/shared/crypto/stega/stega.js.map +1 -0
- package/package.json +3 -2
|
@@ -11,4 +11,6 @@ import querySelectorAll from './querySelectorAll/querySelectorAll.js';
|
|
|
11
11
|
import querySelectorAllUp from './querySelectorAllUp/querySelectorAllUp.js';
|
|
12
12
|
import querySelectorLive from './querySelectorLive/querySelectorLive.js';
|
|
13
13
|
import querySelectorUp from './querySelectorUp/querySelectorUp.js';
|
|
14
|
-
|
|
14
|
+
import queryStegaElements from './queryStegaElements/queryStegaElements.js';
|
|
15
|
+
import queryStegaElementsLive from './queryStegaElementsLive/queryStegaElementsLive.js';
|
|
16
|
+
export { closestElement as __closestElement, closestNotVisibleElement as __closestNotVisibleElement, closestScrollableElement as __closestScrollableElement, elementsInViewport as __elementsInViewport, matches as __matches, nearestElement as __nearestElement, nextElement as __nextElement, previousElement as __previousElement, querySelector as __querySelector, querySelectorAll as __querySelectorAll, querySelectorAllUp as __querySelectorAllUp, querySelectorLive as __querySelectorLive, querySelectorUp as __querySelectorUp, queryStegaElements as __queryStegaElements, queryStegaElementsLive as __queryStegaElementsLive, closestElement, closestNotVisibleElement, closestScrollableElement, elementsInViewport, matches, nearestElement, nextElement, previousElement, querySelector, querySelectorAll, querySelectorAllUp, querySelectorLive, querySelectorUp, queryStegaElements, queryStegaElementsLive, };
|
|
@@ -11,5 +11,7 @@ import querySelectorAll from './querySelectorAll/querySelectorAll.js';
|
|
|
11
11
|
import querySelectorAllUp from './querySelectorAllUp/querySelectorAllUp.js';
|
|
12
12
|
import querySelectorLive from './querySelectorLive/querySelectorLive.js';
|
|
13
13
|
import querySelectorUp from './querySelectorUp/querySelectorUp.js';
|
|
14
|
-
|
|
14
|
+
import queryStegaElements from './queryStegaElements/queryStegaElements.js';
|
|
15
|
+
import queryStegaElementsLive from './queryStegaElementsLive/queryStegaElementsLive.js';
|
|
16
|
+
export { closestElement as __closestElement, closestNotVisibleElement as __closestNotVisibleElement, closestScrollableElement as __closestScrollableElement, elementsInViewport as __elementsInViewport, matches as __matches, nearestElement as __nearestElement, nextElement as __nextElement, previousElement as __previousElement, querySelector as __querySelector, querySelectorAll as __querySelectorAll, querySelectorAllUp as __querySelectorAllUp, querySelectorLive as __querySelectorLive, querySelectorUp as __querySelectorUp, queryStegaElements as __queryStegaElements, queryStegaElementsLive as __queryStegaElementsLive, closestElement, closestNotVisibleElement, closestScrollableElement, elementsInViewport, matches, nearestElement, nextElement, previousElement, querySelector, querySelectorAll, querySelectorAllUp, querySelectorLive, querySelectorUp, queryStegaElements, queryStegaElementsLive, };
|
|
15
17
|
//# sourceMappingURL=_exports.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_exports.js","sourceRoot":"","sources":["../../../../src/js/dom/query/_exports.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,oCAAoC,CAAC;AAChE,OAAO,wBAAwB,MAAM,wDAAwD,CAAC;AAC9F,OAAO,wBAAwB,MAAM,wDAAwD,CAAC;AAC9F,OAAO,kBAAkB,MAAM,4CAA4C,CAAC;AAC5E,OAAO,OAAO,MAAM,sBAAsB,CAAC;AAC3C,OAAO,cAAc,MAAM,oCAAoC,CAAC;AAChE,OAAO,WAAW,MAAM,8BAA8B,CAAC;AACvD,OAAO,eAAe,MAAM,sCAAsC,CAAC;AACnE,OAAO,aAAa,MAAM,kCAAkC,CAAC;AAC7D,OAAO,gBAAgB,MAAM,wCAAwC,CAAC;AACtE,OAAO,kBAAkB,MAAM,4CAA4C,CAAC;AAC5E,OAAO,iBAAiB,MAAM,0CAA0C,CAAC;AACzE,OAAO,eAAe,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"_exports.js","sourceRoot":"","sources":["../../../../src/js/dom/query/_exports.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,oCAAoC,CAAC;AAChE,OAAO,wBAAwB,MAAM,wDAAwD,CAAC;AAC9F,OAAO,wBAAwB,MAAM,wDAAwD,CAAC;AAC9F,OAAO,kBAAkB,MAAM,4CAA4C,CAAC;AAC5E,OAAO,OAAO,MAAM,sBAAsB,CAAC;AAC3C,OAAO,cAAc,MAAM,oCAAoC,CAAC;AAChE,OAAO,WAAW,MAAM,8BAA8B,CAAC;AACvD,OAAO,eAAe,MAAM,sCAAsC,CAAC;AACnE,OAAO,aAAa,MAAM,kCAAkC,CAAC;AAC7D,OAAO,gBAAgB,MAAM,wCAAwC,CAAC;AACtE,OAAO,kBAAkB,MAAM,4CAA4C,CAAC;AAC5E,OAAO,iBAAiB,MAAM,0CAA0C,CAAC;AACzE,OAAO,eAAe,MAAM,sCAAsC,CAAC;AACnE,OAAO,kBAAkB,MAAM,4CAA4C,CAAC;AAC5E,OAAO,sBAAsB,MAAM,oDAAoD,CAAC;AAExF,OAAO,EACL,cAAc,IAAI,gBAAgB,EAClC,wBAAwB,IAAI,0BAA0B,EACtD,wBAAwB,IAAI,0BAA0B,EACtD,kBAAkB,IAAI,oBAAoB,EAC1C,OAAO,IAAI,SAAS,EACpB,cAAc,IAAI,gBAAgB,EAClC,WAAW,IAAI,aAAa,EAC5B,eAAe,IAAI,iBAAiB,EACpC,aAAa,IAAI,eAAe,EAChC,gBAAgB,IAAI,kBAAkB,EACtC,kBAAkB,IAAI,oBAAoB,EAC1C,iBAAiB,IAAI,mBAAmB,EACxC,eAAe,IAAI,iBAAiB,EACpC,kBAAkB,IAAI,oBAAoB,EAC1C,sBAAsB,IAAI,wBAAwB,EAClD,cAAc,EACd,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,OAAO,EACP,cAAc,EACd,WAAW,EACX,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,sBAAsB,GACvB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name queryStegaElements
|
|
3
|
+
* @namespace js.dom.query
|
|
4
|
+
* @type Function
|
|
5
|
+
* @platform js
|
|
6
|
+
* @status stable
|
|
7
|
+
*
|
|
8
|
+
* This function queries all elements (HTMLElement) that contain stega encoded metadata
|
|
9
|
+
* either in their attributes or in their text content.
|
|
10
|
+
* Stega encodes metadata as zero-width Unicode characters interleaved in strings.
|
|
11
|
+
*
|
|
12
|
+
* @param {HTMLElement | Document} [$root = document] The root element to query stega elements in
|
|
13
|
+
* @return {TQueryStegaElementsResult[]} Array of results containing stega encoded data
|
|
14
|
+
*
|
|
15
|
+
* @setting {Boolean|String[]} [attributes=true] If true, check all attributes on the elements. If false, do not check attributes at all. If an array of string, check the corresponding attributes
|
|
16
|
+
*
|
|
17
|
+
* @snippet queryStegaElements($1)
|
|
18
|
+
*
|
|
19
|
+
* @example js
|
|
20
|
+
* import { queryStegaElements } from '@blackbyte/sugar/dom';
|
|
21
|
+
* const stegaElements = queryStegaElements();
|
|
22
|
+
*
|
|
23
|
+
* @since 1.0.0
|
|
24
|
+
* @author Olivier Bossel <olivier.bossel@gmail.com> (https://blackbyte.space)
|
|
25
|
+
*/
|
|
26
|
+
export type TQueryStegaElementsSettings = {
|
|
27
|
+
attributes?: boolean | string[];
|
|
28
|
+
};
|
|
29
|
+
export type TQueryStegaElementsResult = {
|
|
30
|
+
$elm: HTMLElement;
|
|
31
|
+
attr?: string;
|
|
32
|
+
stega: string;
|
|
33
|
+
decode(): any;
|
|
34
|
+
};
|
|
35
|
+
export default function queryStegaElements($root?: HTMLElement | Document, settings?: Partial<TQueryStegaElementsSettings>): TQueryStegaElementsResult[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { stega } from '@blackbyte/sugar/crypto';
|
|
2
|
+
const STEGA_REGEX = /[\u200B\u200C]+/g;
|
|
3
|
+
function extractStega(value) {
|
|
4
|
+
const matches = value.match(STEGA_REGEX);
|
|
5
|
+
return matches ? matches.join('') : null;
|
|
6
|
+
}
|
|
7
|
+
export default function queryStegaElements($root = document, settings) {
|
|
8
|
+
const finalSettings = Object.assign({ attributes: true }, settings);
|
|
9
|
+
const results = [];
|
|
10
|
+
const allElements = Array.from($root.querySelectorAll('*'));
|
|
11
|
+
for (const $elm of allElements) {
|
|
12
|
+
// Check text nodes for stega-encoded content
|
|
13
|
+
for (const node of Array.from($elm.childNodes)) {
|
|
14
|
+
if (node.nodeType === Node.TEXT_NODE && node.textContent) {
|
|
15
|
+
const raw = extractStega(node.textContent);
|
|
16
|
+
if (raw) {
|
|
17
|
+
results.push({
|
|
18
|
+
$elm,
|
|
19
|
+
stega: raw,
|
|
20
|
+
decode: () => stega.decrypt(raw),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Check attributes for stega-encoded content
|
|
26
|
+
if (finalSettings.attributes !== false) {
|
|
27
|
+
for (const attr of Array.from($elm.attributes)) {
|
|
28
|
+
// If attrs is an array, only check the listed attribute names
|
|
29
|
+
if (Array.isArray(finalSettings.attributes) &&
|
|
30
|
+
!finalSettings.attributes.includes(attr.name)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const raw = extractStega(attr.value);
|
|
34
|
+
if (raw) {
|
|
35
|
+
results.push({
|
|
36
|
+
$elm,
|
|
37
|
+
attr: attr.name,
|
|
38
|
+
stega: raw,
|
|
39
|
+
decode: () => stega.decrypt(raw),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return results;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=queryStegaElements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryStegaElements.js","sourceRoot":"","sources":["../../../../../src/js/dom/query/queryStegaElements/queryStegaElements.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAuChD,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAEvC,SAAS,YAAY,CAAC,KAAa;IACjC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACzC,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,kBAAkB,CACxC,QAAgC,QAAQ,EACxC,QAA+C;IAE/C,MAAM,aAAa,mBACjB,UAAU,EAAE,IAAI,IACb,QAAQ,CACZ,CAAC;IAEF,MAAM,OAAO,GAAgC,EAAE,CAAC;IAChD,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAkB,CAAC;IAE7E,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,6CAA6C;QAC7C,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/C,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACzD,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC3C,IAAI,GAAG,EAAE,CAAC;oBACR,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI;wBACJ,KAAK,EAAE,GAAG;wBACV,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;qBACjC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,6CAA6C;QAC7C,IAAI,aAAa,CAAC,UAAU,KAAK,KAAK,EAAE,CAAC;YACvC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/C,8DAA8D;gBAC9D,IACE,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC;oBACvC,CAAC,aAAa,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAC7C,CAAC;oBACD,SAAS;gBACX,CAAC;gBACD,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrC,IAAI,GAAG,EAAE,CAAC;oBACR,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI;wBACJ,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,KAAK,EAAE,GAAG;wBACV,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;qBACjC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { TWhenTrigger } from '@blackbyte/sugar/dom';
|
|
2
|
+
/**
|
|
3
|
+
* @name queryStegaElementsLive
|
|
4
|
+
* @namespace js.dom.query
|
|
5
|
+
* @type Function
|
|
6
|
+
* @platform js
|
|
7
|
+
* @status stable
|
|
8
|
+
*
|
|
9
|
+
* Monitor the specified $root element and all its descendants for stega encoded
|
|
10
|
+
* metadata, either in attributes or text content. When detected, calls the
|
|
11
|
+
* provided callback with the result. Uses a MutationObserver to react to DOM
|
|
12
|
+
* changes in real time.
|
|
13
|
+
*
|
|
14
|
+
* @feature Detects stega data in text nodes and attributes
|
|
15
|
+
* @feature Reacts to DOM mutations in real time via MutationObserver
|
|
16
|
+
* @feature Supports the "once" flag to call the callback only once per element
|
|
17
|
+
* @feature Supports a "when" trigger to defer the callback until a condition is met
|
|
18
|
+
* @feature Supports a disconnectedCallback when a detected element is removed
|
|
19
|
+
* @feature Supports attribute filtering via the "attributes" setting
|
|
20
|
+
*
|
|
21
|
+
* @param {TQueryStegaElementsLiveCallback} cb The callback called with each detected stega element
|
|
22
|
+
* @param {Partial<TQueryStegaElementsLiveSettings>} [settings={}] Optional settings
|
|
23
|
+
* @return {TQueryStegaElementsLiveApi} API object with a cancel() method
|
|
24
|
+
*
|
|
25
|
+
* @setting {HTMLElement | Document} [rootNode=document] The root node to observe
|
|
26
|
+
* @setting {Boolean} [once=true] Only call the callback once per element
|
|
27
|
+
* @setting {TWhenTrigger} [when=undefined] Call the callback only when the trigger is fulfilled
|
|
28
|
+
* @setting {Function} [disconnectedCallback=undefined] Called when a detected element is removed from the DOM
|
|
29
|
+
* @setting {Boolean | String[]} [attributes=true] If true, check all attributes. If false, skip attributes. If string[], check only listed attributes.
|
|
30
|
+
*
|
|
31
|
+
* @snippet queryStegaElementsLive($1)
|
|
32
|
+
* queryStegaElementsLive(element => {
|
|
33
|
+
* $1
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* @example js
|
|
37
|
+
* import { queryStegaElementsLive } from '@blackbyte/sugar/dom';
|
|
38
|
+
* const query = queryStegaElementsLive(element => {
|
|
39
|
+
* console.log(element.$elm, element.decode());
|
|
40
|
+
* });
|
|
41
|
+
* // stop observing when needed
|
|
42
|
+
* query.cancel();
|
|
43
|
+
*
|
|
44
|
+
* @since 1.0.0
|
|
45
|
+
* @author Olivier Bossel <olivier.bossel@gmail.com> (https://blackbyte.space)
|
|
46
|
+
*/
|
|
47
|
+
export type TQueryStegaElementsLiveElement = {
|
|
48
|
+
$elm: HTMLElement;
|
|
49
|
+
attr?: string;
|
|
50
|
+
stega: string;
|
|
51
|
+
decode(): any;
|
|
52
|
+
};
|
|
53
|
+
export type TQueryStegaElementsLiveSettings = {
|
|
54
|
+
rootNode: HTMLElement | Document;
|
|
55
|
+
once: boolean;
|
|
56
|
+
when?: TWhenTrigger<string>;
|
|
57
|
+
disconnectedCallback?: (element: TQueryStegaElementsLiveElement) => void;
|
|
58
|
+
attributes: boolean | string[];
|
|
59
|
+
};
|
|
60
|
+
export type TQueryStegaElementsLiveApi = {
|
|
61
|
+
cancel: Function;
|
|
62
|
+
};
|
|
63
|
+
type TQueryStegaElementsLiveCallback = (element: TQueryStegaElementsLiveElement, api: TQueryStegaElementsLiveApi) => void;
|
|
64
|
+
export default function queryStegaElementsLive(cb: TQueryStegaElementsLiveCallback, settings?: Partial<TQueryStegaElementsLiveSettings>): TQueryStegaElementsLiveApi;
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { stega } from '@blackbyte/sugar/crypto';
|
|
11
|
+
import { when } from '@blackbyte/sugar/dom';
|
|
12
|
+
const STEGA_REGEX = /[\u200B\u200C]+/g;
|
|
13
|
+
function extractStega(value) {
|
|
14
|
+
const matches = value.match(STEGA_REGEX);
|
|
15
|
+
return matches ? matches.join('') : null;
|
|
16
|
+
}
|
|
17
|
+
export default function queryStegaElementsLive(cb, settings) {
|
|
18
|
+
// ─── State ────────────────────────────────────────────────────────────────
|
|
19
|
+
let canceled = false;
|
|
20
|
+
// Unique key per (element, attr?) pair to track already-dispatched results
|
|
21
|
+
const seen = new Set();
|
|
22
|
+
let seenCounter = 0;
|
|
23
|
+
const elmIds = new WeakMap();
|
|
24
|
+
function elmId($elm) {
|
|
25
|
+
if (!elmIds.has($elm))
|
|
26
|
+
elmIds.set($elm, String(seenCounter++));
|
|
27
|
+
return elmIds.get($elm);
|
|
28
|
+
}
|
|
29
|
+
function seenKey($elm, attr) {
|
|
30
|
+
return attr ? `${elmId($elm)}|${attr}` : elmId($elm);
|
|
31
|
+
}
|
|
32
|
+
// ─── Settings ─────────────────────────────────────────────────────────────
|
|
33
|
+
const finalSettings = Object.assign({ rootNode: document, once: true, attributes: true, when: undefined, disconnectedCallback: undefined }, (settings !== null && settings !== void 0 ? settings : {}));
|
|
34
|
+
// ─── API ──────────────────────────────────────────────────────────────────
|
|
35
|
+
const api = { cancel };
|
|
36
|
+
function cancel() {
|
|
37
|
+
canceled = true;
|
|
38
|
+
observer.disconnect();
|
|
39
|
+
}
|
|
40
|
+
// ─── disconnectedCallback watcher ─────────────────────────────────────────
|
|
41
|
+
function watchDisconnect($elm, result) {
|
|
42
|
+
if (!finalSettings.disconnectedCallback || !$elm.parentNode)
|
|
43
|
+
return;
|
|
44
|
+
const parentObserver = new MutationObserver(() => {
|
|
45
|
+
if (!document.contains($elm)) {
|
|
46
|
+
parentObserver.disconnect();
|
|
47
|
+
finalSettings.disconnectedCallback(result);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
parentObserver.observe($elm.parentNode, { childList: true });
|
|
51
|
+
}
|
|
52
|
+
// ─── Core: handle one stega result ────────────────────────────────────────
|
|
53
|
+
function handleResult(result) {
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
if (canceled)
|
|
56
|
+
return;
|
|
57
|
+
const key = seenKey(result.$elm, result.attr);
|
|
58
|
+
if (finalSettings.once && seen.has(key))
|
|
59
|
+
return;
|
|
60
|
+
if (finalSettings.when) {
|
|
61
|
+
yield when(result.$elm, [finalSettings.when]);
|
|
62
|
+
if (canceled)
|
|
63
|
+
return;
|
|
64
|
+
if (finalSettings.once && seen.has(key))
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (finalSettings.once)
|
|
68
|
+
seen.add(key);
|
|
69
|
+
cb(result, api);
|
|
70
|
+
watchDisconnect(result.$elm, result);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// ─── Scan one element for stega data ──────────────────────────────────────
|
|
74
|
+
function scanElement($elm) {
|
|
75
|
+
if (canceled)
|
|
76
|
+
return;
|
|
77
|
+
// Check text nodes
|
|
78
|
+
for (const node of Array.from($elm.childNodes)) {
|
|
79
|
+
if (node.nodeType === Node.TEXT_NODE && node.textContent) {
|
|
80
|
+
const raw = extractStega(node.textContent);
|
|
81
|
+
if (raw) {
|
|
82
|
+
handleResult({
|
|
83
|
+
$elm,
|
|
84
|
+
stega: raw,
|
|
85
|
+
decode: () => stega.decrypt(raw),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Check attributes
|
|
91
|
+
if (finalSettings.attributes !== false) {
|
|
92
|
+
for (const attr of Array.from($elm.attributes)) {
|
|
93
|
+
if (Array.isArray(finalSettings.attributes) &&
|
|
94
|
+
!finalSettings.attributes.includes(attr.name)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const raw = extractStega(attr.value);
|
|
98
|
+
if (raw) {
|
|
99
|
+
handleResult({
|
|
100
|
+
$elm,
|
|
101
|
+
attr: attr.name,
|
|
102
|
+
stega: raw,
|
|
103
|
+
decode: () => stega.decrypt(raw),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// ─── Walk a subtree ────────────────────────────────────────────────────────
|
|
110
|
+
function scan(root) {
|
|
111
|
+
if (canceled)
|
|
112
|
+
return;
|
|
113
|
+
if (root instanceof HTMLElement)
|
|
114
|
+
scanElement(root);
|
|
115
|
+
if ('querySelectorAll' in root) {
|
|
116
|
+
root
|
|
117
|
+
.querySelectorAll('*')
|
|
118
|
+
.forEach(($elm) => scanElement($elm));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// ─── MutationObserver ─────────────────────────────────────────────────────
|
|
122
|
+
const observer = new MutationObserver((mutations) => {
|
|
123
|
+
if (canceled)
|
|
124
|
+
return;
|
|
125
|
+
for (const mutation of mutations) {
|
|
126
|
+
if (mutation.type === 'childList') {
|
|
127
|
+
mutation.addedNodes.forEach((node) => scan(node));
|
|
128
|
+
}
|
|
129
|
+
else if (mutation.type === 'attributes' ||
|
|
130
|
+
mutation.type === 'characterData') {
|
|
131
|
+
const target = mutation.target;
|
|
132
|
+
if (target instanceof HTMLElement) {
|
|
133
|
+
scanElement(target);
|
|
134
|
+
}
|
|
135
|
+
else if (target.nodeType === Node.TEXT_NODE && target.parentElement) {
|
|
136
|
+
scanElement(target.parentElement);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
observer.observe(finalSettings.rootNode, {
|
|
142
|
+
childList: true,
|
|
143
|
+
subtree: true,
|
|
144
|
+
attributes: true,
|
|
145
|
+
characterData: true,
|
|
146
|
+
});
|
|
147
|
+
// ─── Initial scan ─────────────────────────────────────────────────────────
|
|
148
|
+
scan(finalSettings.rootNode);
|
|
149
|
+
return api;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=queryStegaElementsLive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryStegaElementsLive.js","sourceRoot":"","sources":["../../../../../src/js/dom/query/queryStegaElementsLive/queryStegaElementsLive.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,4 +4,5 @@ import md5 from './md5/md5.js';
|
|
|
4
4
|
import object from './object/object.js';
|
|
5
5
|
import sha256 from './sha256/sha256.js';
|
|
6
6
|
import sha512 from './sha512/sha512.js';
|
|
7
|
-
|
|
7
|
+
import stega from './stega/stega.js';
|
|
8
|
+
export { aes as __aes, base64 as __base64, md5 as __md5, object as __object, sha256 as __sha256, sha512 as __sha512, stega as __stega, aes, base64, md5, object, sha256, sha512, stega, };
|
|
@@ -4,5 +4,6 @@ import md5 from './md5/md5.js';
|
|
|
4
4
|
import object from './object/object.js';
|
|
5
5
|
import sha256 from './sha256/sha256.js';
|
|
6
6
|
import sha512 from './sha512/sha512.js';
|
|
7
|
-
|
|
7
|
+
import stega from './stega/stega.js';
|
|
8
|
+
export { aes as __aes, base64 as __base64, md5 as __md5, object as __object, sha256 as __sha256, sha512 as __sha512, stega as __stega, aes, base64, md5, object, sha256, sha512, stega, };
|
|
8
9
|
//# sourceMappingURL=_exports.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_exports.js","sourceRoot":"","sources":["../../../src/shared/crypto/_exports.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,cAAc,CAAC;AAC/B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,GAAG,MAAM,cAAc,CAAC;AAC/B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,MAAM,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"_exports.js","sourceRoot":"","sources":["../../../src/shared/crypto/_exports.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,cAAc,CAAC;AAC/B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,GAAG,MAAM,cAAc,CAAC;AAC/B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,KAAK,MAAM,kBAAkB,CAAC;AAErC,OAAO,EACL,GAAG,IAAI,KAAK,EACZ,MAAM,IAAI,QAAQ,EAClB,GAAG,IAAI,KAAK,EACZ,MAAM,IAAI,QAAQ,EAClB,MAAM,IAAI,QAAQ,EAClB,MAAM,IAAI,QAAQ,EAClB,KAAK,IAAI,OAAO,EAChB,GAAG,EACH,MAAM,EACN,GAAG,EACH,MAAM,EACN,MAAM,EACN,MAAM,EACN,KAAK,GACN,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name stega
|
|
3
|
+
* @namespace shared.crypto
|
|
4
|
+
* @type Object
|
|
5
|
+
* @platform js
|
|
6
|
+
* @status stable
|
|
7
|
+
*
|
|
8
|
+
* Expose two functions named "encrypt" and "decrypt" to process content using the stega algorithm.
|
|
9
|
+
* Stega encodes data by converting a JSON payload to UTF-8 bytes, then representing each bit
|
|
10
|
+
* as a zero-width Unicode character (\u200B for 0, \u200C for 1) interleaved into a cover string.
|
|
11
|
+
*
|
|
12
|
+
* @snippet stega.encrypt($1)
|
|
13
|
+
*
|
|
14
|
+
* @example js
|
|
15
|
+
* import { stega } from '@blackbyte/sugar/crypto';
|
|
16
|
+
* const encoded = stega.encrypt({ source: 'cms', field: 'title' });
|
|
17
|
+
* const data = stega.decrypt(encoded);
|
|
18
|
+
*
|
|
19
|
+
* @since 1.0.0
|
|
20
|
+
* @author Olivier Bossel <olivier.bossel@gmail.com> (https://blackbyte.space)
|
|
21
|
+
*/
|
|
22
|
+
declare const _default: {
|
|
23
|
+
/**
|
|
24
|
+
* @name encrypt
|
|
25
|
+
* @type Function
|
|
26
|
+
*
|
|
27
|
+
* Encodes a payload into a cover string using the stega algorithm.
|
|
28
|
+
* The payload is serialized to JSON, converted to UTF-8 bytes, then each bit
|
|
29
|
+
* is represented as a zero-width Unicode character and interleaved into the cover string.
|
|
30
|
+
*
|
|
31
|
+
* @param {any} payload The data to encode (will be JSON-serialized)
|
|
32
|
+
* @return {String} The stega-encoded string of zero-width characters
|
|
33
|
+
*
|
|
34
|
+
* @since 1.0.0
|
|
35
|
+
* @author Olivier Bossel <olivier.bossel@gmail.com> (https://blackbyte.space)
|
|
36
|
+
*/
|
|
37
|
+
encrypt: (payload: any) => string;
|
|
38
|
+
/**
|
|
39
|
+
* @name decrypt
|
|
40
|
+
* @type Function
|
|
41
|
+
*
|
|
42
|
+
* Extracts and decodes the stega payload hidden inside a string.
|
|
43
|
+
* Returns the decoded value (parsed from JSON if possible), or null if no payload is found.
|
|
44
|
+
*
|
|
45
|
+
* @param {String} message The string containing a hidden stega payload
|
|
46
|
+
* @return {any} The decoded payload, or null if none found
|
|
47
|
+
*
|
|
48
|
+
* @since 1.0.0
|
|
49
|
+
* @author Olivier Bossel <olivier.bossel@gmail.com> (https://blackbyte.space)
|
|
50
|
+
*/
|
|
51
|
+
decrypt: (message: string) => any;
|
|
52
|
+
};
|
|
53
|
+
export default _default;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name stega
|
|
3
|
+
* @namespace shared.crypto
|
|
4
|
+
* @type Object
|
|
5
|
+
* @platform js
|
|
6
|
+
* @status stable
|
|
7
|
+
*
|
|
8
|
+
* Expose two functions named "encrypt" and "decrypt" to process content using the stega algorithm.
|
|
9
|
+
* Stega encodes data by converting a JSON payload to UTF-8 bytes, then representing each bit
|
|
10
|
+
* as a zero-width Unicode character (\u200B for 0, \u200C for 1) interleaved into a cover string.
|
|
11
|
+
*
|
|
12
|
+
* @snippet stega.encrypt($1)
|
|
13
|
+
*
|
|
14
|
+
* @example js
|
|
15
|
+
* import { stega } from '@blackbyte/sugar/crypto';
|
|
16
|
+
* const encoded = stega.encrypt({ source: 'cms', field: 'title' });
|
|
17
|
+
* const data = stega.decrypt(encoded);
|
|
18
|
+
*
|
|
19
|
+
* @since 1.0.0
|
|
20
|
+
* @author Olivier Bossel <olivier.bossel@gmail.com> (https://blackbyte.space)
|
|
21
|
+
*/
|
|
22
|
+
// Zero-width chars used as the binary alphabet
|
|
23
|
+
const ZW_ZERO = '\u200B'; // zero-width space → bit 0
|
|
24
|
+
const ZW_ONE = '\u200C'; // zero-width non-joiner → bit 1
|
|
25
|
+
const ZW_REGEX = /[\u200B\u200C]+/g;
|
|
26
|
+
function payloadToBits(payload) {
|
|
27
|
+
const json = typeof payload === 'string' ? payload : JSON.stringify(payload);
|
|
28
|
+
const bytes = new TextEncoder().encode(json);
|
|
29
|
+
let bits = '';
|
|
30
|
+
for (const byte of bytes) {
|
|
31
|
+
bits += byte.toString(2).padStart(8, '0');
|
|
32
|
+
}
|
|
33
|
+
return bits;
|
|
34
|
+
}
|
|
35
|
+
function bitsToZeroWidth(bits) {
|
|
36
|
+
return bits.split('').map((b) => (b === '0' ? ZW_ZERO : ZW_ONE)).join('');
|
|
37
|
+
}
|
|
38
|
+
function zeroWidthToBits(zw) {
|
|
39
|
+
return zw.split('').map((c) => (c === ZW_ZERO ? '0' : '1')).join('');
|
|
40
|
+
}
|
|
41
|
+
function bitsToPayload(bits) {
|
|
42
|
+
const bytes = bits.match(/.{8}/g);
|
|
43
|
+
if (!bytes)
|
|
44
|
+
return null;
|
|
45
|
+
const uint8 = new Uint8Array(bytes.map((b) => parseInt(b, 2)));
|
|
46
|
+
const text = new TextDecoder().decode(uint8);
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(text);
|
|
49
|
+
}
|
|
50
|
+
catch (_a) {
|
|
51
|
+
return text;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export default {
|
|
55
|
+
/**
|
|
56
|
+
* @name encrypt
|
|
57
|
+
* @type Function
|
|
58
|
+
*
|
|
59
|
+
* Encodes a payload into a cover string using the stega algorithm.
|
|
60
|
+
* The payload is serialized to JSON, converted to UTF-8 bytes, then each bit
|
|
61
|
+
* is represented as a zero-width Unicode character and interleaved into the cover string.
|
|
62
|
+
*
|
|
63
|
+
* @param {any} payload The data to encode (will be JSON-serialized)
|
|
64
|
+
* @return {String} The stega-encoded string of zero-width characters
|
|
65
|
+
*
|
|
66
|
+
* @since 1.0.0
|
|
67
|
+
* @author Olivier Bossel <olivier.bossel@gmail.com> (https://blackbyte.space)
|
|
68
|
+
*/
|
|
69
|
+
encrypt: function (payload) {
|
|
70
|
+
return bitsToZeroWidth(payloadToBits(payload));
|
|
71
|
+
},
|
|
72
|
+
/**
|
|
73
|
+
* @name decrypt
|
|
74
|
+
* @type Function
|
|
75
|
+
*
|
|
76
|
+
* Extracts and decodes the stega payload hidden inside a string.
|
|
77
|
+
* Returns the decoded value (parsed from JSON if possible), or null if no payload is found.
|
|
78
|
+
*
|
|
79
|
+
* @param {String} message The string containing a hidden stega payload
|
|
80
|
+
* @return {any} The decoded payload, or null if none found
|
|
81
|
+
*
|
|
82
|
+
* @since 1.0.0
|
|
83
|
+
* @author Olivier Bossel <olivier.bossel@gmail.com> (https://blackbyte.space)
|
|
84
|
+
*/
|
|
85
|
+
decrypt: function (message) {
|
|
86
|
+
const matches = message.match(ZW_REGEX);
|
|
87
|
+
if (!matches)
|
|
88
|
+
return null;
|
|
89
|
+
const bits = zeroWidthToBits(matches.join(''));
|
|
90
|
+
return bitsToPayload(bits);
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=stega.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stega.js","sourceRoot":"","sources":["../../../../src/shared/crypto/stega/stega.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,+CAA+C;AAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,4BAA4B;AACtD,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAE,gCAAgC;AAC1D,MAAM,QAAQ,GAAG,kBAAkB,CAAC;AAEpC,SAAS,aAAa,CAAC,OAAY;IACjC,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,eAAe,CAAC,EAAU;IACjC,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,eAAe;IACb;;;;;;;;;;;;;OAaG;IACH,OAAO,EAAE,UAAU,OAAY;QAC7B,OAAO,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,OAAO,EAAE,UAAU,OAAe;QAChC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/C,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;CACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blackbyte/sugar",
|
|
3
3
|
"description": "The toolkit that you missed... like a sugar in your coffee!",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.34",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"javascript",
|
|
7
7
|
"typescript",
|
|
@@ -224,8 +224,9 @@
|
|
|
224
224
|
"currency-symbol-map": "^5.1.0",
|
|
225
225
|
"escape-html": "^1.0.3",
|
|
226
226
|
"fast-folder-size": "^2.2.0",
|
|
227
|
-
"fast-xml-parser": "^5.
|
|
227
|
+
"fast-xml-parser": "^5.5.0",
|
|
228
228
|
"fecha": "^4.2.3",
|
|
229
|
+
"figlet": "^1.11.0",
|
|
229
230
|
"filesize": "^10.1.0",
|
|
230
231
|
"find-package-json": "^1.2.0",
|
|
231
232
|
"flattenjs": "^2.1.3",
|