@wenathlan/extension 1.1.61 → 1.1.62
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 +4 -3
- package/dist/confirmgates.d.ts +60 -0
- package/dist/confirmgates.d.ts.map +1 -0
- package/dist/inboundguard.d.ts +86 -0
- package/dist/inboundguard.d.ts.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +747 -3
- package/dist/index.js.map +4 -4
- package/dist/memory.d.ts +89 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/originpolicy.d.ts +10 -0
- package/dist/originpolicy.d.ts.map +1 -1
- package/dist/phishguard.d.ts +24 -0
- package/dist/phishguard.d.ts.map +1 -0
- package/dist/policy.d.ts +68 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +88 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/redactshots.d.ts +54 -0
- package/dist/redactshots.d.ts.map +1 -0
- package/dist/secretvault.d.ts +89 -0
- package/dist/secretvault.d.ts.map +1 -0
- package/dist/transparency.d.ts +46 -0
- package/dist/transparency.d.ts.map +1 -0
- package/dist/types.d.ts +173 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/extension/dist/background.js +984 -54
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/manifest.json +5 -1
- package/extension/dist/pagebridge.js.map +2 -2
- package/extension/dist/popup.html +1 -1
- package/extension/dist/popup.js +15 -0
- package/extension/dist/popup.js.map +2 -2
- package/extension/dist/sidepanel.js +52 -0
- package/extension/dist/sidepanel.js.map +2 -2
- package/extension/dist/transparencypage.html +24 -0
- package/extension/dist/transparencypage.js +156 -0
- package/extension/dist/transparencypage.js.map +7 -0
- package/extension/manifest.json +5 -1
- package/package.json +1 -1
|
@@ -4737,6 +4737,169 @@ var sessionmemory = class {
|
|
|
4737
4737
|
}
|
|
4738
4738
|
return kept;
|
|
4739
4739
|
}
|
|
4740
|
+
/**
|
|
4741
|
+
* Security part two persistence of the 1.1.62 family.
|
|
4742
|
+
* The protections for secrets, messages and money live here: the secretvault metadata with labels and scopes only and never values, scoped per profile workspace; the connectallow entries with their senders shipping empty by default; the ratelimit bucket state per origin and per session; the confirm gates with their resolution events and their human action provenance; the redactshot regions per origin and page template; the phishguard verdicts with their distance scores expiring past their freshness window; the permdiff records of each installed version; the safedefaults applications with their first seen origins; and the deferred command events waiting for their bucket reset.
|
|
4743
|
+
* The vault values never touch this seam: only metadata persists while the values stay behind the vault seam the background wires.
|
|
4744
|
+
*/
|
|
4745
|
+
/** Replaces the secretvault metadata of the profile workspaces: labels, scopes, provenance and digests only, never values. */
|
|
4746
|
+
async setsecretvault(entries) {
|
|
4747
|
+
return this.adapter.set("secretvault", entries);
|
|
4748
|
+
}
|
|
4749
|
+
/** Returns the stored secretvault metadata, oldest record first; the values live behind the vault seam and never persist. */
|
|
4750
|
+
async getsecretvault() {
|
|
4751
|
+
return await this.adapter.get("secretvault") ?? [];
|
|
4752
|
+
}
|
|
4753
|
+
/** Adds one secretvault metadata record scoped to a profile workspace; a duplicate vault id keeps its first record. */
|
|
4754
|
+
async addsecret(entry) {
|
|
4755
|
+
const entries = await this.getsecretvault();
|
|
4756
|
+
if (entries.some((candidate) => candidate.vaultid === entry.vaultid)) return;
|
|
4757
|
+
await this.setsecretvault([...entries, entry]);
|
|
4758
|
+
}
|
|
4759
|
+
/** Removes one secretvault metadata record by its vault id; the background drops the value behind the seam in the same action. */
|
|
4760
|
+
async removesecret(vaultid) {
|
|
4761
|
+
await this.setsecretvault((await this.getsecretvault()).filter((entry) => entry.vaultid !== vaultid));
|
|
4762
|
+
}
|
|
4763
|
+
/** Stamps the last use of one secretvault record: the metadata notes when the vault last released its value while the value itself stays unrecorded. */
|
|
4764
|
+
async stampsecretuse(vaultid, at) {
|
|
4765
|
+
await this.setsecretvault((await this.getsecretvault()).map((entry) => entry.vaultid === vaultid ? { ...entry, lastusedat: at } : entry));
|
|
4766
|
+
}
|
|
4767
|
+
/** Replaces the connectallow entries of external senders; the list ships empty by default with user managed entries only. */
|
|
4768
|
+
async setconnectallow(entries) {
|
|
4769
|
+
return this.adapter.set("connectallow", entries);
|
|
4770
|
+
}
|
|
4771
|
+
/** Returns the stored connectallow entries, oldest add first. */
|
|
4772
|
+
async getconnectallow() {
|
|
4773
|
+
return await this.adapter.get("connectallow") ?? [];
|
|
4774
|
+
}
|
|
4775
|
+
/** Adds one connectallow entry for an external sender; a duplicate sender id keeps its first entry. */
|
|
4776
|
+
async addconnectallow(entry) {
|
|
4777
|
+
const entries = await this.getconnectallow();
|
|
4778
|
+
if (entries.some((candidate) => candidate.senderid === entry.senderid)) return;
|
|
4779
|
+
await this.setconnectallow([...entries, entry]);
|
|
4780
|
+
}
|
|
4781
|
+
/** Removes one connectallow entry by its sender id; the origincheck drops the sender again after the removal. */
|
|
4782
|
+
async removeconnectallow(senderid) {
|
|
4783
|
+
await this.setconnectallow((await this.getconnectallow()).filter((entry) => entry.senderid !== senderid));
|
|
4784
|
+
}
|
|
4785
|
+
/** Replaces the ratelimit bucket state per origin and per session: the user configured bounds and windows with their used counts. */
|
|
4786
|
+
async setratelimitbuckets(buckets) {
|
|
4787
|
+
return this.adapter.set("ratelimitbuckets", buckets);
|
|
4788
|
+
}
|
|
4789
|
+
/** Returns the stored ratelimit buckets per origin and per session. */
|
|
4790
|
+
async getratelimitbuckets() {
|
|
4791
|
+
return await this.adapter.get("ratelimitbuckets") ?? [];
|
|
4792
|
+
}
|
|
4793
|
+
/** Upserts one ratelimit bucket: a bucket of the same origin and session replaces its state while a new pair joins the list. */
|
|
4794
|
+
async saveratelimitbucket(bucket) {
|
|
4795
|
+
const buckets = await this.getratelimitbuckets();
|
|
4796
|
+
await this.setratelimitbuckets(buckets.some((candidate) => candidate.origin === bucket.origin && candidate.sessionid === bucket.sessionid) ? buckets.map((candidate) => candidate.origin === bucket.origin && candidate.sessionid === bucket.sessionid ? bucket : candidate) : [...buckets, bucket]);
|
|
4797
|
+
}
|
|
4798
|
+
/** Removes the ratelimit bucket of one origin and session; the origin runs without a bucket because the bounds stay user choices only. */
|
|
4799
|
+
async removeratelimitbucket(origin, sessionid) {
|
|
4800
|
+
await this.setratelimitbuckets((await this.getratelimitbuckets()).filter((bucket) => !(bucket.origin === origin && bucket.sessionid === sessionid)));
|
|
4801
|
+
}
|
|
4802
|
+
/** Replaces the confirm gates with their payloads and states; a resolved or refused gate stays terminal for the audit trail. */
|
|
4803
|
+
async setgates(gates) {
|
|
4804
|
+
return this.adapter.set("confirmgates", gates);
|
|
4805
|
+
}
|
|
4806
|
+
/** Returns the stored confirm gates, newest open first. */
|
|
4807
|
+
async getgates() {
|
|
4808
|
+
return await this.adapter.get("confirmgates") ?? [];
|
|
4809
|
+
}
|
|
4810
|
+
/** Upserts one confirm gate: a gate of the same step keeps its latest record because one gated step carries one live gate. */
|
|
4811
|
+
async savegate(gate) {
|
|
4812
|
+
const gates = await this.getgates();
|
|
4813
|
+
await this.setgates(gates.some((candidate) => candidate.stepid === gate.stepid && candidate.kind === gate.kind) ? gates.map((candidate) => candidate.stepid === gate.stepid && candidate.kind === gate.kind ? gate : candidate) : [gate, ...gates]);
|
|
4814
|
+
}
|
|
4815
|
+
/** Records one gate resolution event with its human action provenance; the resolution history stays visible for the audit trail. */
|
|
4816
|
+
async addgateresolution(resolution) {
|
|
4817
|
+
await this.adapter.set("gateresolutions", [resolution, ...await this.adapter.get("gateresolutions") ?? []].slice(0, 500));
|
|
4818
|
+
}
|
|
4819
|
+
/** Returns the recorded gate resolution events with their human action provenance, newest first. */
|
|
4820
|
+
async getgateresolutions() {
|
|
4821
|
+
return await this.adapter.get("gateresolutions") ?? [];
|
|
4822
|
+
}
|
|
4823
|
+
/** Replaces the redactshot regions per origin and page template. */
|
|
4824
|
+
async setredactregions(regions) {
|
|
4825
|
+
return this.adapter.set("redactregions", regions);
|
|
4826
|
+
}
|
|
4827
|
+
/** Returns the stored redactshot regions per origin and page template, oldest rule first. */
|
|
4828
|
+
async getredactregions() {
|
|
4829
|
+
return await this.adapter.get("redactregions") ?? [];
|
|
4830
|
+
}
|
|
4831
|
+
/** Adds one redactshot region, derived from a field shape or drawn by the user. */
|
|
4832
|
+
async addredactregion(region) {
|
|
4833
|
+
await this.setredactregions([...await this.getredactregions(), region]);
|
|
4834
|
+
}
|
|
4835
|
+
/** Removes one redactshot region by its id. */
|
|
4836
|
+
async removeredactregion(id) {
|
|
4837
|
+
await this.setredactregions((await this.getredactregions()).filter((region) => region.id !== id));
|
|
4838
|
+
}
|
|
4839
|
+
/** Records one phishguard verdict with its distance score; the records stay for the audit trail while the freshness window governs the live set. */
|
|
4840
|
+
async addphishverdict(verdict) {
|
|
4841
|
+
await this.adapter.set("phishverdicts", [verdict, ...(await this.adapter.get("phishverdicts") ?? []).filter((candidate) => candidate.origin !== verdict.origin)].slice(0, 500));
|
|
4842
|
+
}
|
|
4843
|
+
/** Returns the stored phishguard verdicts with their distance scores, newest first. */
|
|
4844
|
+
async getphishverdicts() {
|
|
4845
|
+
return await this.adapter.get("phishverdicts") ?? [];
|
|
4846
|
+
}
|
|
4847
|
+
/** Expires the phishguard verdicts past the user configured freshness window: the expired verdicts keep their records for the audit trail while the guard recomputes the next login step. */
|
|
4848
|
+
async expirephishverdicts(freshness, now) {
|
|
4849
|
+
const verdicts = await this.getphishverdicts();
|
|
4850
|
+
if (freshness === void 0) return verdicts;
|
|
4851
|
+
return verdicts.filter((verdict) => now - verdict.at < freshness);
|
|
4852
|
+
}
|
|
4853
|
+
/** Records one permdiff between two installed permission versions; the record of each installed update stays for the audit trail. */
|
|
4854
|
+
async addpermdiff(diff) {
|
|
4855
|
+
await this.adapter.set("permdiffs", [diff, ...await this.adapter.get("permdiffs") ?? []].slice(0, 500));
|
|
4856
|
+
}
|
|
4857
|
+
/** Returns the recorded permdiffs of each installed update, newest first. */
|
|
4858
|
+
async getpermdiffs() {
|
|
4859
|
+
return await this.adapter.get("permdiffs") ?? [];
|
|
4860
|
+
}
|
|
4861
|
+
/** Stores the last installed permission set the permdiff of the next update compares against. */
|
|
4862
|
+
async setlastpermissions(permissions, version) {
|
|
4863
|
+
await this.adapter.set("lastpermissions", { permissions, version });
|
|
4864
|
+
}
|
|
4865
|
+
/** Returns the last installed permission set with its version; an absent record returns undefined. */
|
|
4866
|
+
async getlastpermissions() {
|
|
4867
|
+
return this.adapter.get("lastpermissions");
|
|
4868
|
+
}
|
|
4869
|
+
/** Records one safedefaults application with its first seen origin; the first visit of an unknown origin stays visible. */
|
|
4870
|
+
async addsafedefaultapplication(application) {
|
|
4871
|
+
const applications = await this.adapter.get("safedefaults") ?? [];
|
|
4872
|
+
if (applications.some((candidate) => candidate.origin === application.origin)) return;
|
|
4873
|
+
await this.adapter.set("safedefaults", [...applications, application]);
|
|
4874
|
+
}
|
|
4875
|
+
/** Returns the recorded safedefaults applications with their first seen origins, oldest first. */
|
|
4876
|
+
async getsafedefaultapplications() {
|
|
4877
|
+
return await this.adapter.get("safedefaults") ?? [];
|
|
4878
|
+
}
|
|
4879
|
+
/** Records one deferred command event with the reset time it waits for. */
|
|
4880
|
+
async adddeferredevent(event) {
|
|
4881
|
+
await this.adapter.set("deferredevents", [event, ...await this.adapter.get("deferredevents") ?? []].slice(0, 500));
|
|
4882
|
+
}
|
|
4883
|
+
/** Returns the recorded deferred command events, newest first. */
|
|
4884
|
+
async getdeferredevents() {
|
|
4885
|
+
return await this.adapter.get("deferredevents") ?? [];
|
|
4886
|
+
}
|
|
4887
|
+
/** Serves the transparency data of the transparencypage in one read: every active grant with its origin, scope and boundary, every consent window ever granted with its expiry, the connectallow entries with their senders, the permdiff records of each installed update, the safedefaults applications and the secretvault metadata with labels and scopes only. */
|
|
4888
|
+
async gettransparencyview() {
|
|
4889
|
+
return {
|
|
4890
|
+
allowlist: await this.getautomationallowlist(),
|
|
4891
|
+
profiles: await this.getoriginprofiles(),
|
|
4892
|
+
windows: await this.getconsentwindows(),
|
|
4893
|
+
connectallow: await this.getconnectallow(),
|
|
4894
|
+
permdiffs: await this.getpermdiffs(),
|
|
4895
|
+
safedefaults: await this.getsafedefaultapplications(),
|
|
4896
|
+
vault: await this.getsecretvault(),
|
|
4897
|
+
gates: await this.getgates(),
|
|
4898
|
+
resolutions: await this.getgateresolutions(),
|
|
4899
|
+
deferred: await this.getdeferredevents(),
|
|
4900
|
+
phishverdicts: await this.getphishverdicts()
|
|
4901
|
+
};
|
|
4902
|
+
}
|
|
4740
4903
|
};
|
|
4741
4904
|
function mediakindof(record2) {
|
|
4742
4905
|
if ("pages" in record2) return "pdf";
|
|
@@ -6673,6 +6836,226 @@ function consolediff(input) {
|
|
|
6673
6836
|
return { base: input.baseid, target: input.targetid, lines, added: added.length, removed: removed.length, repeated: repeated.length, at: input.now };
|
|
6674
6837
|
}
|
|
6675
6838
|
|
|
6839
|
+
// inboundguard.ts
|
|
6840
|
+
function shapeof(value) {
|
|
6841
|
+
if (typeof value === "string") return "string";
|
|
6842
|
+
if (typeof value === "number") return "number";
|
|
6843
|
+
if (typeof value === "boolean") return "boolean";
|
|
6844
|
+
if (Array.isArray(value)) return "array";
|
|
6845
|
+
return "object";
|
|
6846
|
+
}
|
|
6847
|
+
function schemacheck(input) {
|
|
6848
|
+
const errors = [];
|
|
6849
|
+
for (const [field, value] of Object.entries(input.command)) {
|
|
6850
|
+
const expected = input.schema[field];
|
|
6851
|
+
if (expected === void 0) {
|
|
6852
|
+
errors.push({ path: field, expected: "absent", found: shapeof(value), reason: `The ${field} field sits absent from the declared grammar of the command; schemastrict refuses unknown fields before dispatch.` });
|
|
6853
|
+
continue;
|
|
6854
|
+
}
|
|
6855
|
+
if (expected === "absent") {
|
|
6856
|
+
errors.push({ path: field, expected: "absent", found: shapeof(value), reason: `The ${field} field carries no value under the declared grammar; schemastrict refuses it before dispatch.` });
|
|
6857
|
+
continue;
|
|
6858
|
+
}
|
|
6859
|
+
if (shapeof(value) !== expected) errors.push({ path: field, expected, found: shapeof(value), reason: `The ${field} field expects a ${expected} while the command carries a ${shapeof(value)}; schemastrict refuses the shape mismatch before dispatch.` });
|
|
6860
|
+
}
|
|
6861
|
+
for (const field of input.required ?? []) {
|
|
6862
|
+
if (input.command[field] === void 0) errors.push({ path: field, expected: input.schema[field] ?? "string", found: "absent", reason: `The ${field} field is required by the declared grammar and the command carries no value; schemastrict refuses the incomplete command before dispatch.` });
|
|
6863
|
+
}
|
|
6864
|
+
return { valid: errors.length === 0, errors };
|
|
6865
|
+
}
|
|
6866
|
+
function origincheckof(input) {
|
|
6867
|
+
const sender = input.senderid ?? "an unknown sender";
|
|
6868
|
+
const origin = input.senderorigin ?? "";
|
|
6869
|
+
if (input.senderid === input.extensionid) return { accepted: true, sender, origin, reason: "The sender is this extension itself; the internal surface accepts." };
|
|
6870
|
+
if (input.senderid !== void 0 && input.connectallow.some((entry) => entry.senderid === input.senderid && (entry.origin === void 0 || entry.origin === origin))) {
|
|
6871
|
+
return { accepted: true, sender, origin, reason: `The sender ${sender} sits in the connectallow list the user manages${origin !== "" ? ` for ${origin}` : ""}; the message accepts.` };
|
|
6872
|
+
}
|
|
6873
|
+
if (input.senderid === void 0) return { accepted: false, sender, origin, reason: "The message carries no sender identity; the guard drops it before any handler runs." };
|
|
6874
|
+
return { accepted: false, sender, origin, reason: `The sender ${sender} sits absent from the connectallow list; the guard drops the message without handler execution.` };
|
|
6875
|
+
}
|
|
6876
|
+
function portaccept(input) {
|
|
6877
|
+
const verdict = origincheckof(input);
|
|
6878
|
+
if (!verdict.accepted) return { ...verdict, reason: `The port ${input.portname} closes at its handshake: ${verdict.reason}` };
|
|
6879
|
+
return { ...verdict, reason: `The port ${input.portname} accepted its handshake: ${verdict.reason}` };
|
|
6880
|
+
}
|
|
6881
|
+
function connectallowentryof(input) {
|
|
6882
|
+
if (input.senderid.trim() === "") throw new Error("The connectallow entry needs its sender id.");
|
|
6883
|
+
if (input.displayname.trim() === "") throw new Error("The connectallow entry needs its display name.");
|
|
6884
|
+
return { senderid: input.senderid.trim(), displayname: input.displayname.trim(), ...input.origin !== void 0 && input.origin.trim() !== "" ? { origin: input.origin.trim() } : {}, addedat: input.now };
|
|
6885
|
+
}
|
|
6886
|
+
function bucketboundsvalid(limit, window2) {
|
|
6887
|
+
if (!Number.isFinite(limit) || limit <= 0) return { valid: false, reason: "The ratelimit bucket limit stays a positive user value; no hidden ceiling exists." };
|
|
6888
|
+
if (!Number.isFinite(window2) || window2 <= 0) return { valid: false, reason: "The ratelimit bucket window stays a positive user value in milliseconds; the window reset stays the user's choice." };
|
|
6889
|
+
return { valid: true, reason: `The bucket bound of ${limit} commands per ${window2} milliseconds stays the user configured choice with no hidden ceiling.` };
|
|
6890
|
+
}
|
|
6891
|
+
function bucketof(input) {
|
|
6892
|
+
const bounds = bucketboundsvalid(input.limit, input.window);
|
|
6893
|
+
if (!bounds.valid) throw new Error(bounds.reason);
|
|
6894
|
+
return { origin: input.origin, sessionid: input.sessionid, limit: input.limit, window: input.window, used: 0, windowstartedat: input.now, resetsat: input.now + input.window };
|
|
6895
|
+
}
|
|
6896
|
+
function bucketconsume(input) {
|
|
6897
|
+
if (input.now >= input.bucket.resetsat) {
|
|
6898
|
+
const fresh = { ...input.bucket, used: 0, windowstartedat: input.now, resetsat: input.now + input.bucket.window };
|
|
6899
|
+
return { allowed: true, deferred: false, bucket: { ...fresh, used: 1 }, resetsat: fresh.resetsat, reason: `The bucket window of ${input.bucket.origin} reset and the command consumes the first slot of ${fresh.limit}.` };
|
|
6900
|
+
}
|
|
6901
|
+
if (input.bucket.used < input.bucket.limit) {
|
|
6902
|
+
return { allowed: true, deferred: false, bucket: { ...input.bucket, used: input.bucket.used + 1 }, resetsat: input.bucket.resetsat, reason: `The command consumes slot ${input.bucket.used + 1} of ${input.bucket.limit} in the bucket of ${input.bucket.origin}.` };
|
|
6903
|
+
}
|
|
6904
|
+
return { allowed: false, deferred: true, bucket: input.bucket, resetsat: input.bucket.resetsat, reason: `The bucket of ${input.bucket.origin} holds its ${input.bucket.limit} command bound; the command defers until the window resets at ${input.bucket.resetsat}.` };
|
|
6905
|
+
}
|
|
6906
|
+
function deferredeventof(input) {
|
|
6907
|
+
if (input.stepid.trim() === "" || input.kind.trim() === "") throw new Error("The deferred event needs its step and kind.");
|
|
6908
|
+
return { id: input.id ?? randomid(), stepid: input.stepid, kind: input.kind, origin: input.origin, reason: input.reason, resetsat: input.resetsat, at: input.now };
|
|
6909
|
+
}
|
|
6910
|
+
|
|
6911
|
+
// confirmgates.ts
|
|
6912
|
+
function stepoptions2(step) {
|
|
6913
|
+
if (!step.options) return {};
|
|
6914
|
+
try {
|
|
6915
|
+
const parsed = JSON.parse(step.options);
|
|
6916
|
+
return Boolean(parsed) && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
6917
|
+
} catch {
|
|
6918
|
+
return {};
|
|
6919
|
+
}
|
|
6920
|
+
}
|
|
6921
|
+
function gatekindfor(classes) {
|
|
6922
|
+
if (classes.includes("payment")) return "confirmpay";
|
|
6923
|
+
if (classes.includes("delete")) return "confirmdelete";
|
|
6924
|
+
if (classes.includes("credential")) return "confirmcreds";
|
|
6925
|
+
return void 0;
|
|
6926
|
+
}
|
|
6927
|
+
function paypayload(input) {
|
|
6928
|
+
const payload = { payeeorigin: input.payeeorigin };
|
|
6929
|
+
if (input.amount !== void 0 && input.amount.trim() !== "") payload.amount = input.amount.trim();
|
|
6930
|
+
if (input.target !== void 0 && input.target.trim() !== "") payload.target = input.target.trim();
|
|
6931
|
+
return payload;
|
|
6932
|
+
}
|
|
6933
|
+
function deletepayload(input) {
|
|
6934
|
+
const payload = { scope: input.scope, irreversibility: input.irreversibility };
|
|
6935
|
+
if (input.target !== void 0 && input.target.trim() !== "") payload.target = input.target.trim();
|
|
6936
|
+
return payload;
|
|
6937
|
+
}
|
|
6938
|
+
function credspayload(label) {
|
|
6939
|
+
if (label.trim() === "") throw new Error("The confirmcreds gate names its credential label; the value never appears.");
|
|
6940
|
+
return { label: label.trim() };
|
|
6941
|
+
}
|
|
6942
|
+
function opengate(input) {
|
|
6943
|
+
if (input.stepid.trim() === "" || input.runid.trim() === "" || input.origin.trim() === "") throw new Error("The confirm gate needs its step, run and origin.");
|
|
6944
|
+
if (Object.keys(input.payload).length === 0) throw new Error("The confirm gate carries the payload the human reviews.");
|
|
6945
|
+
return { gateid: input.gateid ?? randomid(), kind: input.kind, stepid: input.stepid, runid: input.runid, origin: input.origin, payload: { ...input.payload }, state: "open", openedat: input.now };
|
|
6946
|
+
}
|
|
6947
|
+
function gatestateof(gates, stepid) {
|
|
6948
|
+
const gate = [...gates].reverse().find((candidate) => candidate.stepid === stepid);
|
|
6949
|
+
if (gate === void 0) return { state: "none" };
|
|
6950
|
+
return { state: gate.state, gate };
|
|
6951
|
+
}
|
|
6952
|
+
function resolvegate(input) {
|
|
6953
|
+
if (input.actor.trim() === "") throw new Error("The gate resolution names its acting user; only a human resolves a gate.");
|
|
6954
|
+
const gate = input.gates.find((candidate) => candidate.gateid === input.gateid);
|
|
6955
|
+
if (gate === void 0) return { gates: input.gates };
|
|
6956
|
+
if (gate.state !== "open") return { gates: input.gates };
|
|
6957
|
+
const resolution = { gateid: gate.gateid, kind: gate.kind, stepid: gate.stepid, decision: input.decision, actor: input.actor, at: input.now };
|
|
6958
|
+
return { gates: input.gates.map((candidate) => candidate.gateid === input.gateid ? { ...candidate, state: input.decision, resolvedat: input.now, actor: input.actor } : candidate), resolution };
|
|
6959
|
+
}
|
|
6960
|
+
function gateprompttext(gate) {
|
|
6961
|
+
if (gate.kind === "confirmpay") {
|
|
6962
|
+
const amount = gate.payload.amount !== void 0 ? `the amount ${gate.payload.amount}` : "an amount the step options name";
|
|
6963
|
+
const target = gate.payload.target !== void 0 ? ` on ${gate.payload.target}` : "";
|
|
6964
|
+
return `Approve the payment of ${amount} to ${gate.payload.payeeorigin}${target}? The step dispatches only after this distinct human action.`;
|
|
6965
|
+
}
|
|
6966
|
+
if (gate.kind === "confirmdelete") {
|
|
6967
|
+
const target = gate.payload.target !== void 0 ? ` on ${gate.payload.target}` : "";
|
|
6968
|
+
return `Approve the destructive delete${target} scoped to ${gate.payload.scope}? ${gate.payload.irreversibility} The step dispatches only after this distinct human action.`;
|
|
6969
|
+
}
|
|
6970
|
+
return `Approve the use of the credential ${gate.payload.label} on ${gate.origin}? The value stays behind the vault; the label is everything this prompt shows.`;
|
|
6971
|
+
}
|
|
6972
|
+
function gateforstep(input) {
|
|
6973
|
+
const kind = gatekindfor(input.classes);
|
|
6974
|
+
if (kind === void 0) return void 0;
|
|
6975
|
+
const options = stepoptions2(input.step);
|
|
6976
|
+
if (kind === "confirmpay") {
|
|
6977
|
+
const amount = typeof options.amount === "string" ? options.amount : typeof options.value === "string" ? options.value : void 0;
|
|
6978
|
+
return opengate({ kind, stepid: input.step.id, runid: input.runid, origin: input.origin, payload: paypayload({ ...amount !== void 0 && amount !== "" ? { amount } : {}, payeeorigin: String(options.payeeorigin ?? input.origin), ...input.step.target !== void 0 && input.step.target !== "" ? { target: input.step.target } : {} }), now: input.now });
|
|
6979
|
+
}
|
|
6980
|
+
if (kind === "confirmdelete") {
|
|
6981
|
+
return opengate({ kind, stepid: input.step.id, runid: input.runid, origin: input.origin, payload: deletepayload({ ...input.step.target !== void 0 && input.step.target !== "" ? { target: input.step.target } : {}, scope: String(options.scope ?? input.origin), irreversibility: String(options.irreversibility ?? "A destructive delete destroys state the page cannot restore.") }), now: input.now });
|
|
6982
|
+
}
|
|
6983
|
+
if (input.credentiallabel === void 0 || input.credentiallabel.trim() === "") return void 0;
|
|
6984
|
+
return opengate({ kind, stepid: input.step.id, runid: input.runid, origin: input.origin, payload: credspayload(input.credentiallabel), now: input.now });
|
|
6985
|
+
}
|
|
6986
|
+
|
|
6987
|
+
// phishguard.ts
|
|
6988
|
+
function stepoptions3(step) {
|
|
6989
|
+
if (!step.options) return {};
|
|
6990
|
+
try {
|
|
6991
|
+
const parsed = JSON.parse(step.options);
|
|
6992
|
+
return Boolean(parsed) && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
6993
|
+
} catch {
|
|
6994
|
+
return {};
|
|
6995
|
+
}
|
|
6996
|
+
}
|
|
6997
|
+
function credentialstep(step) {
|
|
6998
|
+
const credentialkinds2 = /* @__PURE__ */ new Set(["consentpassword", "saveapikey", "handleauth", "authflow", "fillcard", "fillcode"]);
|
|
6999
|
+
if (credentialkinds2.has(step.kind)) return true;
|
|
7000
|
+
const options = stepoptions3(step);
|
|
7001
|
+
const fields = Array.isArray(options.fields) ? options.fields.filter((item) => Boolean(item) && typeof item === "object") : [];
|
|
7002
|
+
const names = [...fields.map((field) => typeof field.name === "string" ? field.name : ""), typeof options.field === "string" ? options.field : "", step.target ?? ""].map((name) => name.toLowerCase());
|
|
7003
|
+
return names.some((name) => name.includes("password") || name.includes("passwd") || name.includes("passphrase") || name.includes("token") || name.includes("secret") || name.includes("apikey"));
|
|
7004
|
+
}
|
|
7005
|
+
function originlabels(origin) {
|
|
7006
|
+
const host = origin.trim().replace(/^[a-z][a-z0-9+.-]*:\/\//i, "").split("/")[0] ?? "";
|
|
7007
|
+
return host.split(".").filter((label) => label !== "").reverse();
|
|
7008
|
+
}
|
|
7009
|
+
function labeldistance(one, two) {
|
|
7010
|
+
const rows = one.length + 1;
|
|
7011
|
+
const columns = two.length + 1;
|
|
7012
|
+
let previous = Array.from({ length: columns }, (_, index) => index);
|
|
7013
|
+
for (let row = 1; row < rows; row += 1) {
|
|
7014
|
+
const current = [row, ...Array.from({ length: columns - 1 }, () => 0)];
|
|
7015
|
+
for (let column = 1; column < columns; column += 1) {
|
|
7016
|
+
const substitution = (previous[column - 1] ?? 0) + (one[row - 1] === two[column - 1] ? 0 : 1);
|
|
7017
|
+
current[column] = Math.min((previous[column] ?? 0) + 1, (current[column - 1] ?? 0) + 1, substitution);
|
|
7018
|
+
}
|
|
7019
|
+
previous = current;
|
|
7020
|
+
}
|
|
7021
|
+
return previous[columns - 1] ?? Math.max(one.length, two.length);
|
|
7022
|
+
}
|
|
7023
|
+
function lookalikedistance(one, two) {
|
|
7024
|
+
if (one.trim() === "" || two.trim() === "") return 1;
|
|
7025
|
+
if (one === two) return 0;
|
|
7026
|
+
const first = originlabels(one);
|
|
7027
|
+
const second = originlabels(two);
|
|
7028
|
+
const edits = labeldistance(first, second);
|
|
7029
|
+
const longest = Math.max(first.length, second.length);
|
|
7030
|
+
if (longest === 0) return 1;
|
|
7031
|
+
const distance = edits / longest;
|
|
7032
|
+
return Math.min(1, Math.max(0, distance));
|
|
7033
|
+
}
|
|
7034
|
+
function phishthresholdvalid(threshold) {
|
|
7035
|
+
if (!Number.isFinite(threshold) || threshold <= 0 || threshold >= 1) return { valid: false, reason: "The phishguard threshold stays a user choice between zero and one; the lookalike line never defaults." };
|
|
7036
|
+
return { valid: true, reason: `The lookalike threshold ${threshold} stays the user configured line a login origin crosses at its own risk.` };
|
|
7037
|
+
}
|
|
7038
|
+
function phishverdictof(input) {
|
|
7039
|
+
const threshold = phishthresholdvalid(input.threshold);
|
|
7040
|
+
if (!threshold.valid) throw new Error(threshold.reason);
|
|
7041
|
+
if (input.granted.includes(input.origin)) {
|
|
7042
|
+
return { origin: input.origin, distance: 0, threshold: input.threshold, blocked: false, reason: `The login origin ${input.origin} sits among the granted origins; no lookalike watch applies.`, at: input.now };
|
|
7043
|
+
}
|
|
7044
|
+
let matchedorigin;
|
|
7045
|
+
let distance = 1;
|
|
7046
|
+
for (const granted of input.granted) {
|
|
7047
|
+
const candidate = lookalikedistance(input.origin, granted);
|
|
7048
|
+
if (candidate < distance) {
|
|
7049
|
+
distance = candidate;
|
|
7050
|
+
matchedorigin = granted;
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
if (matchedorigin !== void 0 && distance <= input.threshold) {
|
|
7054
|
+
return { origin: input.origin, matchedorigin, distance, threshold: input.threshold, blocked: true, reason: `The login origin ${input.origin} sits ${distance} away from the granted origin ${matchedorigin} and crosses the user threshold ${input.threshold}; the credential step blocks and the deny event names ${matchedorigin}.`, at: input.now };
|
|
7055
|
+
}
|
|
7056
|
+
return { origin: input.origin, ...matchedorigin !== void 0 ? { matchedorigin } : {}, distance, threshold: input.threshold, blocked: false, reason: matchedorigin !== void 0 ? `The login origin ${input.origin} sits ${distance} away from its closest granted origin ${matchedorigin} and stays under the user threshold ${input.threshold}.` : `The login origin ${input.origin} carries no granted origin to resemble; the watch records the first visit.`, at: input.now };
|
|
7057
|
+
}
|
|
7058
|
+
|
|
6676
7059
|
// policy.ts
|
|
6677
7060
|
var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab", "fillform", "filllabel", "fillplaceholder", "submitform", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcard", "fillcode", "consentpassword", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk", "paginateextract", "resumeextract", "batchdownload", "pausedownload", "resumedownload", "interceptmime", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "cleanupartifacts", "recordscreen", "captureaudio", "downloadimages", "callrest", "callgraphql", "sendmessage", "blockrequest", "mockresponse", "rewriteheaders", "setcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles", "attachcdp", "detachcdp", "cdpcmd", "overridescript", "heapshot", "profilecpu", "capturesourcemaps", "emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "restoresession", "exportsessions", "importsessions", "runworkflow", "visitrule", "urlrule", "menurule", "keyrule", "buttonrule", "cronrule", "intervalrule", "urllistrule", "webhookrule", "eventrule"]);
|
|
6678
7061
|
var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction", "capturebodies", "setbreakpoint", "stepcode", "watchexpr", "loop", "repeatuntil", "whileloop", "foreach", "parallel", "trycatch"]);
|
|
@@ -9923,6 +10306,67 @@ function logreadgate(input) {
|
|
|
9923
10306
|
if (!input.valid) return { allowed: false, reason: input.brokenat !== void 0 ? `The log chain breaks at entry ${input.brokenat}; the audit accessor refuses the read of a forged record.` : "The log chain fails its verification; the audit accessor refuses the read of a forged record." };
|
|
9924
10307
|
return { allowed: true, reason: "The log chain verifies from the genesis hash to the last entry; the audit accessor serves the entries." };
|
|
9925
10308
|
}
|
|
10309
|
+
function schemaguardgate(input) {
|
|
10310
|
+
if (input.errors.length === 0) return { allowed: true, reason: "The inbound command matches its declared schemastrict grammar field by field." };
|
|
10311
|
+
const first = input.errors[0];
|
|
10312
|
+
return { allowed: false, reason: `${input.errors.length} schema error${input.errors.length === 1 ? "" : "s"} refuse the command before dispatch: ${input.errors.map((error) => error.reason).join(" ")}${first !== void 0 ? ` The first error sits at ${first.path} expecting ${first.expected}.` : ""}` };
|
|
10313
|
+
}
|
|
10314
|
+
function origincheckgate(input) {
|
|
10315
|
+
if (!input.verdict.accepted) return { allowed: false, reason: input.verdict.reason };
|
|
10316
|
+
return { allowed: true, reason: input.verdict.reason };
|
|
10317
|
+
}
|
|
10318
|
+
function ratelimitboundsvalid(limit, window2) {
|
|
10319
|
+
const bounds = bucketboundsvalid(limit, window2);
|
|
10320
|
+
if (!bounds.valid) return { allowed: false, reason: bounds.reason };
|
|
10321
|
+
return { allowed: true, reason: bounds.reason };
|
|
10322
|
+
}
|
|
10323
|
+
function confirmpaygate(input) {
|
|
10324
|
+
const kind = gatekindfor(input.classes);
|
|
10325
|
+
if (kind !== "confirmpay") return { allowed: true, reason: "The step carries no payment class and needs no confirmpay gate." };
|
|
10326
|
+
if (input.state === "resolved") return { allowed: true, reason: "The human resolved the confirmpay gate of the payment step; the step dispatches with its reviewed amount, payee origin and target." };
|
|
10327
|
+
if (input.state === "refused") return { allowed: false, reason: "The human refused the confirmpay gate of the payment step; the payment never dispatches." };
|
|
10328
|
+
if (input.state === "open") return { allowed: false, reason: "The confirmpay gate of the payment step stays open with the amount, the payee origin and the target element; the executor pauses until the human resolves it and no timeout ever resolves a gate." };
|
|
10329
|
+
return { allowed: false, reason: "The payment step opens its confirmpay gate with the amount, the payee origin and the target element; the executor pauses until one distinct human action resolves it." };
|
|
10330
|
+
}
|
|
10331
|
+
function confirmdeletegate(input) {
|
|
10332
|
+
const kind = gatekindfor(input.classes);
|
|
10333
|
+
if (kind !== "confirmdelete") return { allowed: true, reason: "The step carries no delete class and needs no confirmdelete gate." };
|
|
10334
|
+
if (input.state === "resolved") return { allowed: true, reason: "The human resolved the confirmdelete gate of the destructive step; the step dispatches with its reviewed target, scope and irreversibility." };
|
|
10335
|
+
if (input.state === "refused") return { allowed: false, reason: "The human refused the confirmdelete gate of the destructive step; the deletion never dispatches." };
|
|
10336
|
+
if (input.state === "open") return { allowed: false, reason: "The confirmdelete gate of the destructive step stays open with the target, the scope and the irreversibility; the executor pauses until the human resolves it and no timeout ever resolves a gate." };
|
|
10337
|
+
return { allowed: false, reason: "The destructive step opens its confirmdelete gate with the target, the scope and the irreversibility; the executor pauses until one distinct human action resolves it." };
|
|
10338
|
+
}
|
|
10339
|
+
function confirmcredsgate(input) {
|
|
10340
|
+
const kind = gatekindfor(input.classes);
|
|
10341
|
+
if (kind !== "confirmcreds") return { allowed: true, reason: "The step carries no credential class and needs no confirmcreds gate." };
|
|
10342
|
+
if (input.state === "resolved") return { allowed: true, reason: "The human resolved the confirmcreds gate of the credential step; the step reads its value from the vault at the last possible moment and no log records it." };
|
|
10343
|
+
if (input.state === "refused") return { allowed: false, reason: "The human refused the confirmcreds gate of the credential step; the credential never dispatches." };
|
|
10344
|
+
if (input.state === "open") return { allowed: false, reason: "The confirmcreds gate of the credential step stays open with its credential label only; the executor pauses until the human resolves it and no timeout ever resolves a gate." };
|
|
10345
|
+
return { allowed: false, reason: "The credential step opens its confirmcreds gate with its credential label only; the executor pauses until one distinct human action resolves it." };
|
|
10346
|
+
}
|
|
10347
|
+
function phishthresholdgate(threshold) {
|
|
10348
|
+
const verdict = phishthresholdvalid(threshold);
|
|
10349
|
+
if (!verdict.valid) return { allowed: false, reason: verdict.reason };
|
|
10350
|
+
return { allowed: true, reason: verdict.reason };
|
|
10351
|
+
}
|
|
10352
|
+
function phishguardgate(input) {
|
|
10353
|
+
if (input.verdict.blocked) return { allowed: false, reason: input.verdict.reason };
|
|
10354
|
+
return { allowed: true, reason: input.verdict.reason };
|
|
10355
|
+
}
|
|
10356
|
+
function safedefaultsgate(input) {
|
|
10357
|
+
if (input.profile !== void 0) return { allowed: true, reason: `The origin profile of ${input.profile.origin} exists; the safedefaults posture stays out of the decision.` };
|
|
10358
|
+
if (!input.sensitive) return { allowed: true, reason: "The non-sensitive step rides the reads only baseline of the safedefaults posture; the first visit grants reads alone." };
|
|
10359
|
+
return { allowed: false, reason: `No origin profile exists and the safedefaults posture denies the sensitive ${input.classes.length > 0 ? input.classes.join(" and ") : "by default"} step; open the originprofile editor to widen the profile the user controls.` };
|
|
10360
|
+
}
|
|
10361
|
+
function vaultsecretgate(input) {
|
|
10362
|
+
if (input.leaks.length > 0) return { allowed: false, reason: `The plan carries ${input.leaks.length} plaintext secret value${input.leaks.length === 1 ? "" : "s"} that digest to vault records; secrets never ride step options, variables or plan texts, only the vault holds them.` };
|
|
10363
|
+
if (input.carries) return { allowed: false, reason: "The step types a raw value into a masked field shape; credential steps read their value from the vault at the last possible moment and never carry it in the options." };
|
|
10364
|
+
return { allowed: true, reason: "The step and the plan carry no secret outside the vault; the values stay behind the seam." };
|
|
10365
|
+
}
|
|
10366
|
+
function untrustedrendergate(input) {
|
|
10367
|
+
if (input.environment === "sandboxframe") return { allowed: true, reason: "The extracted markup renders inside the sandboxframe under its nonce with scripts and handlers stripped; the untrusted content never reenters the page context." };
|
|
10368
|
+
return { allowed: false, reason: `The extracted markup grades untrusted and refuses to render inside the ${input.environment}; every untrusted render routes through the sandboxframe.` };
|
|
10369
|
+
}
|
|
9926
10370
|
|
|
9927
10371
|
// progress.ts
|
|
9928
10372
|
function emptyprogress(planid, now) {
|
|
@@ -9945,6 +10389,10 @@ function recordturnaround2(progress, planid, stepid, milliseconds, now) {
|
|
|
9945
10389
|
const base = progress && progress.planid === planid ? progress : emptyprogress(planid, now);
|
|
9946
10390
|
return { ...base, turnarounds: { ...base.turnarounds ?? {}, [stepid]: milliseconds }, updatedat: now };
|
|
9947
10391
|
}
|
|
10392
|
+
function recordgatewait(progress, planid, stepid, entry, now) {
|
|
10393
|
+
const base = progress && progress.planid === planid ? progress : emptyprogress(planid, now);
|
|
10394
|
+
return { ...base, gatewaits: { ...base.gatewaits ?? {}, [stepid]: entry }, updatedat: now };
|
|
10395
|
+
}
|
|
9948
10396
|
function iscomplete(progress, plan) {
|
|
9949
10397
|
if (!progress || progress.planid !== plan.id) return false;
|
|
9950
10398
|
const required = plan.steps.map((step) => step.id);
|
|
@@ -10169,7 +10617,7 @@ function maskexport(record2, shapes) {
|
|
|
10169
10617
|
}
|
|
10170
10618
|
|
|
10171
10619
|
// version.ts
|
|
10172
|
-
var packageversion = "1.1.
|
|
10620
|
+
var packageversion = "1.1.62";
|
|
10173
10621
|
|
|
10174
10622
|
// types.ts
|
|
10175
10623
|
var protocolversion = packageversion;
|
|
@@ -11143,6 +11591,9 @@ function environmentreport(input) {
|
|
|
11143
11591
|
...input.keepalive !== void 0 ? { keepalive: input.keepalive } : {}
|
|
11144
11592
|
};
|
|
11145
11593
|
}
|
|
11594
|
+
function transparencyreport(input) {
|
|
11595
|
+
return { version: protocolversion, posture: "denydefault", grants: input.grants, windows: input.windows, connectallow: input.connectallow, permdiffs: input.permdiffs, safedefaults: input.safedefaults, vault: input.vault };
|
|
11596
|
+
}
|
|
11146
11597
|
|
|
11147
11598
|
// capture.ts
|
|
11148
11599
|
var capturekinds = ["shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet"];
|
|
@@ -11646,7 +12097,7 @@ async function readcapabilities() {
|
|
|
11646
12097
|
]);
|
|
11647
12098
|
return { tabs, downloads, clipboardread, clipboardwrite, reportedat: Date.now() };
|
|
11648
12099
|
}
|
|
11649
|
-
function
|
|
12100
|
+
function stepoptions4(step) {
|
|
11650
12101
|
if (!step.options) return {};
|
|
11651
12102
|
try {
|
|
11652
12103
|
const parsed = JSON.parse(step.options);
|
|
@@ -11659,7 +12110,7 @@ function tabid(step) {
|
|
|
11659
12110
|
return Number.parseInt(step.value ?? "", 10);
|
|
11660
12111
|
}
|
|
11661
12112
|
async function runbrowseraction(step, sessiontabid, windowid) {
|
|
11662
|
-
const options =
|
|
12113
|
+
const options = stepoptions4(step);
|
|
11663
12114
|
switch (step.kind) {
|
|
11664
12115
|
case "tablist": {
|
|
11665
12116
|
const tabs = await chrome.tabs.query({});
|
|
@@ -13119,6 +13570,144 @@ function acceptrenderresult(input) {
|
|
|
13119
13570
|
return { accepted: true, result, reason: `The render result of the step ${render.stepid} answers the nonce of its render; the text stays inside the frame.` };
|
|
13120
13571
|
}
|
|
13121
13572
|
|
|
13573
|
+
// secretvault.ts
|
|
13574
|
+
var vaultdigestprefix = "sha256:";
|
|
13575
|
+
async function vaultdigestof(value) {
|
|
13576
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
|
|
13577
|
+
return vaultdigestprefix + [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
13578
|
+
}
|
|
13579
|
+
function vaultentryof(input) {
|
|
13580
|
+
if (input.label.trim() === "") throw new Error("The vault record needs its label; the surfaces show the label only.");
|
|
13581
|
+
if (input.scope.trim() === "") throw new Error("The vault record needs its exact origin scope; a secret never rides every origin.");
|
|
13582
|
+
if (!input.digest.startsWith(vaultdigestprefix)) throw new Error("The vault record carries its sha-256 digest, never its value.");
|
|
13583
|
+
return { vaultid: input.vaultid ?? randomid(), label: input.label.trim(), scope: input.scope.trim(), profileid: input.profileid, provenance: input.provenance, algorithm: "sha-256", digest: input.digest, createdat: input.now };
|
|
13584
|
+
}
|
|
13585
|
+
function inmemoryvault() {
|
|
13586
|
+
const values = /* @__PURE__ */ new Map();
|
|
13587
|
+
return {
|
|
13588
|
+
put: async (vaultid, value) => {
|
|
13589
|
+
values.set(vaultid, value);
|
|
13590
|
+
},
|
|
13591
|
+
fetch: async (vaultid) => values.get(vaultid),
|
|
13592
|
+
drop: async (vaultid) => {
|
|
13593
|
+
values.delete(vaultid);
|
|
13594
|
+
}
|
|
13595
|
+
};
|
|
13596
|
+
}
|
|
13597
|
+
async function vaultstore(input) {
|
|
13598
|
+
if (input.value === "") throw new Error("The vault stores a secret value the user supplied; an empty value stores nothing.");
|
|
13599
|
+
const entry = vaultentryof({ label: input.label, scope: input.scope, profileid: input.profileid, provenance: input.provenance, digest: await vaultdigestof(input.value), now: input.now });
|
|
13600
|
+
await input.seam.put(entry.vaultid, input.value);
|
|
13601
|
+
return entry;
|
|
13602
|
+
}
|
|
13603
|
+
async function vaultvaluefor(input) {
|
|
13604
|
+
const value = await input.seam.fetch(input.entry.vaultid);
|
|
13605
|
+
if (value === void 0) return { ok: false, reason: `The vault holds no value behind the label ${input.entry.label}; add the secret again.` };
|
|
13606
|
+
return { ok: true, value, reason: `The vault released the value behind the label ${input.entry.label} at the last possible moment; the value reaches the credential field only and no log records it.` };
|
|
13607
|
+
}
|
|
13608
|
+
async function vaultdelete(input) {
|
|
13609
|
+
await input.seam.drop(input.entry.vaultid);
|
|
13610
|
+
return { dropped: true, label: input.entry.label, reason: `The vault dropped the secret ${input.entry.label} of ${input.entry.scope}; no value and no copy remains behind the seam.` };
|
|
13611
|
+
}
|
|
13612
|
+
async function secretleakscan(input) {
|
|
13613
|
+
const leaks = [];
|
|
13614
|
+
for (const candidate of input.candidates) {
|
|
13615
|
+
if (candidate.trim() === "") continue;
|
|
13616
|
+
const digest = await vaultdigestof(candidate);
|
|
13617
|
+
if (input.entries.some((entry) => entry.digest === digest)) leaks.push(candidate);
|
|
13618
|
+
}
|
|
13619
|
+
if (leaks.length > 0) return { leaks, reason: `The plan carries ${leaks.length} plaintext value${leaks.length === 1 ? "" : "s"} that digest to vault records; secrets never ride step options, variables or plan texts, only the vault holds them.` };
|
|
13620
|
+
return { leaks: [], reason: "No candidate value digests to a vault record; the plan carries no leaked secret." };
|
|
13621
|
+
}
|
|
13622
|
+
function stepoptions5(step) {
|
|
13623
|
+
if (!step.options) return {};
|
|
13624
|
+
try {
|
|
13625
|
+
const parsed = JSON.parse(step.options);
|
|
13626
|
+
return Boolean(parsed) && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
13627
|
+
} catch {
|
|
13628
|
+
return {};
|
|
13629
|
+
}
|
|
13630
|
+
}
|
|
13631
|
+
function secretshapecarrying(step) {
|
|
13632
|
+
const options = stepoptions5(step);
|
|
13633
|
+
const fields = Array.isArray(options.fields) ? options.fields.filter((item) => Boolean(item) && typeof item === "object") : [];
|
|
13634
|
+
const rawfield = fields.find((field) => typeof field.name === "string" && typeof field.value === "string" && field.value !== "" && maskingfield(field.name, []));
|
|
13635
|
+
if (rawfield !== void 0) return { carries: true, reason: `The ${step.kind} step types a raw value into the ${String(rawfield.name)} field; credential steps read their value from the vault at the last possible moment and never carry it in the options.` };
|
|
13636
|
+
if (typeof options.field === "string" && maskingfield(options.field, []) && step.value !== void 0 && step.value !== "") return { carries: true, reason: `The ${step.kind} step types a raw value into the ${options.field} field; credential steps read their value from the vault at the last possible moment and never carry it in the options.` };
|
|
13637
|
+
return { carries: false, reason: "The step carries no raw value behind a masked field shape." };
|
|
13638
|
+
}
|
|
13639
|
+
function vaultview(entries) {
|
|
13640
|
+
return entries.map((entry) => ({ vaultid: entry.vaultid, label: entry.label, scope: entry.scope, provenance: entry.provenance, createdat: entry.createdat, ...entry.lastusedat !== void 0 ? { lastusedat: entry.lastusedat } : {} }));
|
|
13641
|
+
}
|
|
13642
|
+
|
|
13643
|
+
// redactshots.ts
|
|
13644
|
+
function regionof(input) {
|
|
13645
|
+
if (input.origin.trim() === "" || input.template.trim() === "") throw new Error("The redact region needs its origin and its page template.");
|
|
13646
|
+
for (const value of [input.x, input.y, input.width, input.height]) {
|
|
13647
|
+
if (!Number.isFinite(value) || value < 0) throw new Error("The redact region needs finite, non-negative geometry in css pixels.");
|
|
13648
|
+
}
|
|
13649
|
+
if (input.width <= 0 || input.height <= 0) throw new Error("The redact region needs a positive width and height so the mask covers a real area.");
|
|
13650
|
+
if (input.reason.trim() === "") throw new Error("The redact region names its reason in plain language.");
|
|
13651
|
+
return { id: input.id ?? randomid(), origin: input.origin.trim(), template: input.template.trim(), x: input.x, y: input.y, width: input.width, height: input.height, reason: input.reason.trim(), source: input.source, createdat: input.now };
|
|
13652
|
+
}
|
|
13653
|
+
function regionsfor(regions, origin, template) {
|
|
13654
|
+
return regions.filter((region) => region.origin === origin && region.template === template);
|
|
13655
|
+
}
|
|
13656
|
+
function templateof(step) {
|
|
13657
|
+
if (step.options) {
|
|
13658
|
+
try {
|
|
13659
|
+
const parsed = JSON.parse(step.options);
|
|
13660
|
+
if (Boolean(parsed) && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
13661
|
+
const template = parsed.template;
|
|
13662
|
+
if (typeof template === "string" && template.trim() !== "") return template.trim();
|
|
13663
|
+
}
|
|
13664
|
+
} catch {
|
|
13665
|
+
}
|
|
13666
|
+
}
|
|
13667
|
+
return step.kind;
|
|
13668
|
+
}
|
|
13669
|
+
function redactedshot(record2, regions) {
|
|
13670
|
+
if (regions.length === 0) return record2;
|
|
13671
|
+
return { ...record2, redacted: true, redactedregions: regions.length };
|
|
13672
|
+
}
|
|
13673
|
+
function redactionsummary(regions) {
|
|
13674
|
+
if (regions.length === 0) return "No redact region covered the capture; the stored bytes carry everything the surface saw.";
|
|
13675
|
+
const sources = { fieldshape: 0, userdrawn: 0 };
|
|
13676
|
+
for (const region of regions) sources[region.source] += 1;
|
|
13677
|
+
return `${regions.length} redact region${regions.length === 1 ? "" : "s"} covered the capture before storage: ${sources.fieldshape} derived from sensitive field shapes and ${sources.userdrawn} drawn by the user (${regions.map((region) => region.reason).join("; ")}).`;
|
|
13678
|
+
}
|
|
13679
|
+
|
|
13680
|
+
// transparency.ts
|
|
13681
|
+
function permissiondiff(input) {
|
|
13682
|
+
if (input.fromversion.trim() === "" || input.toversion.trim() === "") throw new Error("The permdiff names the two versions it compares.");
|
|
13683
|
+
const added = [...new Set(input.to.filter((permission) => !input.from.includes(permission)))];
|
|
13684
|
+
const removed = [...new Set(input.from.filter((permission) => !input.to.includes(permission)))];
|
|
13685
|
+
return { fromversion: input.fromversion, toversion: input.toversion, added, removed, computedat: input.now };
|
|
13686
|
+
}
|
|
13687
|
+
function permdiffchanged(diff) {
|
|
13688
|
+
return diff.added.length > 0 || diff.removed.length > 0;
|
|
13689
|
+
}
|
|
13690
|
+
function permdiffsummary(diff) {
|
|
13691
|
+
if (!permdiffchanged(diff)) return `The update from ${diff.fromversion} to ${diff.toversion} changed no permission.`;
|
|
13692
|
+
const parts = [];
|
|
13693
|
+
if (diff.added.length > 0) parts.push(`added ${diff.added.join(", ")}`);
|
|
13694
|
+
if (diff.removed.length > 0) parts.push(`removed ${diff.removed.join(", ")}`);
|
|
13695
|
+
return `The update from ${diff.fromversion} to ${diff.toversion} ${parts.join(" and ")}.`;
|
|
13696
|
+
}
|
|
13697
|
+
function transparencygrants(input) {
|
|
13698
|
+
const grants = input.allowlist.map((entry) => ({ origin: entry.origin, scope: `automation allowlist of the profile workspace ${entry.profileid}`, boundary: "the user revokes the entry or the profile workspace", grantedat: entry.grantedat }));
|
|
13699
|
+
for (const profile of input.profiles) {
|
|
13700
|
+
grants.push({ origin: profile.origin, scope: `origin profile with ${profile.grants.length} granted and ${profile.denials.length} denied kinds`, boundary: "the user edits or revokes the profile", grantedat: profile.createdat });
|
|
13701
|
+
}
|
|
13702
|
+
return grants;
|
|
13703
|
+
}
|
|
13704
|
+
function windowhistory(windows) {
|
|
13705
|
+
return windows.map((window2) => ({ id: window2.id, origin: window2.origin, state: window2.state, boundary: window2.boundary, startedat: window2.startedat, expiresat: window2.expiresat }));
|
|
13706
|
+
}
|
|
13707
|
+
function connectallowlist(entries) {
|
|
13708
|
+
return entries.map((entry) => ({ senderid: entry.senderid, displayname: entry.displayname, ...entry.origin !== void 0 ? { origin: entry.origin } : {}, addedat: entry.addedat }));
|
|
13709
|
+
}
|
|
13710
|
+
|
|
13122
13711
|
// modelroute.ts
|
|
13123
13712
|
function routevalid(route) {
|
|
13124
13713
|
if (route.kind.trim() === "") return { allowed: false, reason: "The model route needs its task kind." };
|
|
@@ -14325,13 +14914,28 @@ var chromestorage = {
|
|
|
14325
14914
|
}
|
|
14326
14915
|
};
|
|
14327
14916
|
var memory = new sessionmemory(chromestorage);
|
|
14917
|
+
var vaultseamstore = (() => {
|
|
14918
|
+
const session = chrome.storage?.session;
|
|
14919
|
+
if (session) {
|
|
14920
|
+
return {
|
|
14921
|
+
put: async (vaultid, value) => {
|
|
14922
|
+
await session.set({ [`vault:${vaultid}`]: value });
|
|
14923
|
+
},
|
|
14924
|
+
fetch: async (vaultid) => (await session.get(`vault:${vaultid}`))[`vault:${vaultid}`],
|
|
14925
|
+
drop: async (vaultid) => {
|
|
14926
|
+
await session.remove(`vault:${vaultid}`);
|
|
14927
|
+
}
|
|
14928
|
+
};
|
|
14929
|
+
}
|
|
14930
|
+
return inmemoryvault();
|
|
14931
|
+
})();
|
|
14328
14932
|
function extensionpage(sender) {
|
|
14329
14933
|
return sender.id === chrome.runtime.id && Boolean(sender.url?.startsWith(chrome.runtime.getURL("")));
|
|
14330
14934
|
}
|
|
14331
14935
|
async function audit(kind, summary, extra = {}) {
|
|
14332
14936
|
await memory.addaudi({ id: randomid(), kind, at: Date.now(), summary, ...extra });
|
|
14333
14937
|
}
|
|
14334
|
-
function
|
|
14938
|
+
function stepoptions6(step) {
|
|
14335
14939
|
try {
|
|
14336
14940
|
return parseoptions(step);
|
|
14337
14941
|
} catch {
|
|
@@ -14556,6 +15160,12 @@ async function securitystepgate(step, session, origin, settings) {
|
|
|
14556
15160
|
const allowverdict = automationallowlistgate({ origin, allowlist: await memory.getautomationallowlist(), session });
|
|
14557
15161
|
if (!allowverdict.allowed) return { allowed: false, suspended: false, reason: allowverdict.reason ?? "", classification };
|
|
14558
15162
|
const profile = (await memory.getoriginprofiles()).find((candidate) => candidate.origin === origin);
|
|
15163
|
+
if (profile === void 0) {
|
|
15164
|
+
await memory.addsafedefaultapplication({ origin, firstseenat: now }).catch(() => {
|
|
15165
|
+
});
|
|
15166
|
+
const safedefaultverdict = safedefaultsgate({ profile, classes: classification.classes, sensitive: classification.sensitive });
|
|
15167
|
+
if (!safedefaultverdict.allowed) return { allowed: false, suspended: false, reason: safedefaultverdict.reason ?? "", classification };
|
|
15168
|
+
}
|
|
14559
15169
|
const profileverdict = originprofilegate({ profile, kind: step.kind, sensitive: classification.sensitive });
|
|
14560
15170
|
if (!profileverdict.allowed) return { allowed: false, suspended: false, reason: profileverdict.reason ?? "", classification };
|
|
14561
15171
|
const windows = await memory.expireconsentwindows(now);
|
|
@@ -14568,8 +15178,115 @@ async function securitystepgate(step, session, origin, settings) {
|
|
|
14568
15178
|
const revocation = plan === void 0 ? void 0 : (await memory.getrevocations()).find((candidate) => candidate.sessionid === session.id && candidate.runid === plan.id);
|
|
14569
15179
|
const revokeverdict = revokerungate({ revocation, sessionid: session.id, runid: plan?.id ?? "" });
|
|
14570
15180
|
if (!revokeverdict.allowed) return { allowed: false, suspended: false, reason: revokeverdict.reason ?? "", classification };
|
|
15181
|
+
const confirmverdict = await confirmgatechain(step, session, plan, origin, classification, now);
|
|
15182
|
+
if (confirmverdict !== void 0) return { allowed: confirmverdict.allowed, suspended: false, reason: confirmverdict.reason, classification };
|
|
14571
15183
|
return { allowed: true, suspended: false, reason: `${classification.reason} ${allowverdict.reason ?? ""} ${windowverdict.reason ?? ""} ${consentverdict.reason ?? ""}`, classification };
|
|
14572
15184
|
}
|
|
15185
|
+
async function confirmgatechain(step, session, plan, origin, classification, now) {
|
|
15186
|
+
if (!session || !plan) return void 0;
|
|
15187
|
+
const kind = gatekindfor(classification.classes);
|
|
15188
|
+
if (kind !== void 0) {
|
|
15189
|
+
const gates = await memory.getgates();
|
|
15190
|
+
const state = gatestateof(gates, step.id);
|
|
15191
|
+
if (state.state === "none") {
|
|
15192
|
+
const vaultentries2 = await memory.getsecretvault();
|
|
15193
|
+
const vaultlabel = vaultentries2.find((entry) => entry.scope === origin)?.label;
|
|
15194
|
+
const gate = gateforstep({ step, classes: classification.classes, runid: plan.id, origin, credentiallabel: vaultlabel ?? `the credential the ${step.kind} step reviews`, now });
|
|
15195
|
+
if (gate) {
|
|
15196
|
+
await memory.savegate(gate);
|
|
15197
|
+
await appendrunevent("gate", `The ${gate.kind} gate opened for the ${step.kind} step ${step.id} on ${origin}: ${gateprompttext(gate)}`, session, origin, step.id).catch(() => {
|
|
15198
|
+
});
|
|
15199
|
+
await audit("gate", `The ${gate.kind} gate opened for the ${step.kind} step ${step.id} on ${origin}; the executor pauses until one distinct human action resolves it and no timeout ever resolves a gate.`, { sessionid: session.id, planid: plan.id, stepid: step.id });
|
|
15200
|
+
return { allowed: false, reason: `The ${gate.kind} gate opened for the ${step.kind} step ${step.id} on ${origin}: ${gateprompttext(gate)} The executor pauses until the human resolves it.` };
|
|
15201
|
+
}
|
|
15202
|
+
}
|
|
15203
|
+
const gateverdict = kind === "confirmpay" ? confirmpaygate({ classes: classification.classes, state: state.state }) : kind === "confirmdelete" ? confirmdeletegate({ classes: classification.classes, state: state.state }) : confirmcredsgate({ classes: classification.classes, state: state.state });
|
|
15204
|
+
if (!gateverdict.allowed) return { allowed: false, reason: gateverdict.reason ?? "" };
|
|
15205
|
+
if (state.state === "resolved" && state.gate !== void 0 && state.gate.resolvedat !== void 0) {
|
|
15206
|
+
await memory.setprogress(recordgatewait(await memory.getprogress(), plan.id, step.id, { gateid: state.gate.gateid, kind: state.gate.kind, openedat: state.gate.openedat, resolvedat: state.gate.resolvedat, waitedms: Math.max(0, state.gate.resolvedat - state.gate.openedat) }, now)).catch(() => {
|
|
15207
|
+
});
|
|
15208
|
+
}
|
|
15209
|
+
}
|
|
15210
|
+
if (credentialstep(step)) {
|
|
15211
|
+
const settings = await memory.getsettings();
|
|
15212
|
+
const threshold = settings?.phishdistance;
|
|
15213
|
+
if (threshold !== void 0) {
|
|
15214
|
+
const thresholdgate = phishthresholdgate(threshold);
|
|
15215
|
+
if (!thresholdgate.allowed) return { allowed: false, reason: thresholdgate.reason ?? "" };
|
|
15216
|
+
const live = await memory.expirephishverdicts(settings?.phishfreshness, now);
|
|
15217
|
+
const stored = live.find((verdict2) => verdict2.origin === origin);
|
|
15218
|
+
const verdict = stored ?? phishverdictof({ origin, granted: [.../* @__PURE__ */ new Set([...(await memory.getautomationallowlist()).map((entry) => entry.origin), session.origin])], threshold, now });
|
|
15219
|
+
if (stored === void 0) await memory.addphishverdict(verdict);
|
|
15220
|
+
const phishgate = phishguardgate({ verdict });
|
|
15221
|
+
if (!phishgate.allowed) {
|
|
15222
|
+
await appendrunevent("phish", `The phishguard blocked the credential step ${step.id} on ${origin}: ${verdict.reason}`, session, origin, step.id).catch(() => {
|
|
15223
|
+
});
|
|
15224
|
+
await audit("phish", `The phishguard blocked the ${step.kind} step ${step.id} on ${origin}: ${verdict.reason}`, { sessionid: session.id, planid: plan.id, stepid: step.id });
|
|
15225
|
+
return { allowed: false, reason: phishgate.reason ?? "" };
|
|
15226
|
+
}
|
|
15227
|
+
}
|
|
15228
|
+
}
|
|
15229
|
+
const buckets = await memory.getratelimitbuckets();
|
|
15230
|
+
const bucket = buckets.find((candidate) => candidate.origin === origin && candidate.sessionid === session.id);
|
|
15231
|
+
if (bucket !== void 0) {
|
|
15232
|
+
const consumed = bucketconsume({ bucket, now });
|
|
15233
|
+
if (!consumed.allowed) {
|
|
15234
|
+
const deferred = deferredeventof({ stepid: step.id, kind: step.kind, origin, reason: consumed.reason, resetsat: consumed.resetsat, now });
|
|
15235
|
+
await memory.adddeferredevent(deferred);
|
|
15236
|
+
await appendrunevent("suspend", `The ratelimit bucket of ${origin} deferred the ${step.kind} step ${step.id} until the window resets at ${deferred.resetsat}: ${consumed.reason}`, session, origin, step.id).catch(() => {
|
|
15237
|
+
});
|
|
15238
|
+
await audit("defer", `The ratelimit bucket of ${origin} deferred the ${step.kind} step ${step.id} until the window resets at ${deferred.resetsat}; the bounds stay user configured choices with no hidden ceiling.`, { sessionid: session.id, planid: plan.id, stepid: step.id });
|
|
15239
|
+
return { allowed: false, reason: consumed.reason };
|
|
15240
|
+
}
|
|
15241
|
+
await memory.saveratelimitbucket(consumed.bucket);
|
|
15242
|
+
}
|
|
15243
|
+
const vaultentries = await memory.getsecretvault();
|
|
15244
|
+
const options = stepoptions6(step);
|
|
15245
|
+
const candidates = [step.value ?? "", ...Object.values(options).filter((value) => typeof value === "string")];
|
|
15246
|
+
const leakscan = await secretleakscan({ candidates, entries: vaultentries });
|
|
15247
|
+
const secretverdict = vaultsecretgate({ leaks: leakscan.leaks, carries: secretshapecarrying(step).carries });
|
|
15248
|
+
if (!secretverdict.allowed) {
|
|
15249
|
+
await audit("vault", `The vault secret scan refused the ${step.kind} step ${step.id} on ${origin}: ${secretverdict.reason}`, { sessionid: session.id, planid: plan.id, stepid: step.id });
|
|
15250
|
+
return { allowed: false, reason: secretverdict.reason ?? "" };
|
|
15251
|
+
}
|
|
15252
|
+
return void 0;
|
|
15253
|
+
}
|
|
15254
|
+
async function resolvevaultvalues(step, session) {
|
|
15255
|
+
void session;
|
|
15256
|
+
const marker = /^vault:[A-Za-z0-9-]+$/;
|
|
15257
|
+
if (step.options === void 0 || !step.options.includes("vault:")) return step;
|
|
15258
|
+
const entries = await memory.getsecretvault();
|
|
15259
|
+
let options = step.options;
|
|
15260
|
+
try {
|
|
15261
|
+
const parsed = JSON.parse(step.options);
|
|
15262
|
+
if (Boolean(parsed) && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
15263
|
+
const record2 = parsed;
|
|
15264
|
+
const resolvevalue = async (value) => {
|
|
15265
|
+
if (!marker.test(value)) return value;
|
|
15266
|
+
const entry = entries.find((candidate) => candidate.vaultid === value.slice("vault:".length));
|
|
15267
|
+
if (!entry) return value;
|
|
15268
|
+
const fetched = await vaultvaluefor({ seam: vaultseamstore, entry });
|
|
15269
|
+
if (fetched.ok && fetched.value !== void 0) {
|
|
15270
|
+
await memory.stampsecretuse(entry.vaultid, Date.now());
|
|
15271
|
+
return fetched.value;
|
|
15272
|
+
}
|
|
15273
|
+
return value;
|
|
15274
|
+
};
|
|
15275
|
+
for (const [key, value] of Object.entries(record2)) if (typeof value === "string") record2[key] = await resolvevalue(value);
|
|
15276
|
+
if (Array.isArray(record2.fields)) {
|
|
15277
|
+
for (const field of record2.fields) {
|
|
15278
|
+
if (!Boolean(field) || typeof field !== "object" || Array.isArray(field)) continue;
|
|
15279
|
+
const fieldrecord = field;
|
|
15280
|
+
if (typeof fieldrecord.value === "string") fieldrecord.value = await resolvevalue(fieldrecord.value);
|
|
15281
|
+
}
|
|
15282
|
+
}
|
|
15283
|
+
options = JSON.stringify(record2);
|
|
15284
|
+
}
|
|
15285
|
+
} catch {
|
|
15286
|
+
}
|
|
15287
|
+
if (options === step.options) return step;
|
|
15288
|
+
return { ...step, options };
|
|
15289
|
+
}
|
|
14573
15290
|
async function sealsessionrunlog(sessionid) {
|
|
14574
15291
|
const log = await memory.getimmutablelog(sessionid);
|
|
14575
15292
|
if (!log || log.seal !== void 0 || log.entries.length === 0) return;
|
|
@@ -14593,10 +15310,19 @@ async function securityviewof() {
|
|
|
14593
15310
|
maskrules: await memory.getmaskrules(),
|
|
14594
15311
|
chain,
|
|
14595
15312
|
posture: "denydefault",
|
|
15313
|
+
gates: await memory.getgates(),
|
|
15314
|
+
resolutions: await memory.getgateresolutions(),
|
|
15315
|
+
deferred: await memory.getdeferredevents(),
|
|
15316
|
+
phishverdicts: await memory.getphishverdicts(),
|
|
15317
|
+
vault: await memory.getsecretvault(),
|
|
15318
|
+
connectallow: await memory.getconnectallow(),
|
|
15319
|
+
safedefaults: await memory.getsafedefaultapplications(),
|
|
15320
|
+
redactregions: await memory.getredactregions(),
|
|
14596
15321
|
...session ? { sessionorigin: session.origin } : {},
|
|
14597
15322
|
...settings?.consentduration !== void 0 ? { promptduration: settings.consentduration } : {},
|
|
14598
15323
|
...settings?.logretention !== void 0 ? { logretention: settings.logretention } : {},
|
|
14599
|
-
...settings?.maskshapes !== void 0 ? { maskshapes: settings.maskshapes } : {}
|
|
15324
|
+
...settings?.maskshapes !== void 0 ? { maskshapes: settings.maskshapes } : {},
|
|
15325
|
+
...settings?.phishdistance !== void 0 ? { phishdistance: settings.phishdistance } : {}
|
|
14600
15326
|
};
|
|
14601
15327
|
}
|
|
14602
15328
|
async function executeisolatedevaluate(step, tabid2, origin) {
|
|
@@ -14618,9 +15344,11 @@ async function executeisolatedevaluate(step, tabid2, origin) {
|
|
|
14618
15344
|
return result[0]?.result ?? { ok: false, summary: "The isolated world returned no result." };
|
|
14619
15345
|
}
|
|
14620
15346
|
async function executesandboxrender(step, session, plan, origin) {
|
|
14621
|
-
const options =
|
|
15347
|
+
const options = stepoptions6(step);
|
|
14622
15348
|
const markup = typeof options.markup === "string" ? options.markup : "";
|
|
14623
15349
|
const sourceorigin = typeof options.sourceorigin === "string" ? options.sourceorigin : origin;
|
|
15350
|
+
const rendergate = untrustedrendergate({ environment: "sandboxframe" });
|
|
15351
|
+
if (!rendergate.allowed) throw new Error(rendergate.reason);
|
|
14624
15352
|
const settings = await memory.getsettings();
|
|
14625
15353
|
const origingate = sandboxorigingate({ origin: sourceorigin, allowed: settings?.sandboxorigins ?? [] });
|
|
14626
15354
|
if (!origingate.allowed) throw new Error(origingate.reason);
|
|
@@ -14652,7 +15380,7 @@ async function offloadparsetoworker(step, output, session, plan, origin) {
|
|
|
14652
15380
|
const ready = await ensureoffscreendocument(runid);
|
|
14653
15381
|
if (!ready) return { output, turnaround: void 0 };
|
|
14654
15382
|
const payload = JSON.stringify({ summary: output?.summary ?? "", details: output?.details ?? {} });
|
|
14655
|
-
const request = workerrequestof({ id: randomid(), runid, stepid: step.id, kind: step.kind, payload, options:
|
|
15383
|
+
const request = workerrequestof({ id: randomid(), runid, stepid: step.id, kind: step.kind, payload, options: stepoptions6(step), sentat: Date.now() });
|
|
14656
15384
|
const started = Date.now();
|
|
14657
15385
|
let answer;
|
|
14658
15386
|
try {
|
|
@@ -14855,7 +15583,7 @@ function stepauditkind(step, ok) {
|
|
|
14855
15583
|
return ok ? "action" : "error";
|
|
14856
15584
|
}
|
|
14857
15585
|
function resolvedinnerstep(step, plan) {
|
|
14858
|
-
const options =
|
|
15586
|
+
const options = stepoptions6(step);
|
|
14859
15587
|
if (typeof options.stepid === "string" && options.stepid.trim()) {
|
|
14860
15588
|
return plan.steps.find((candidate) => candidate.id === options.stepid) ?? null;
|
|
14861
15589
|
}
|
|
@@ -14864,7 +15592,7 @@ function resolvedinnerstep(step, plan) {
|
|
|
14864
15592
|
async function executekeyhold(step, session, plan, tabid2, origin) {
|
|
14865
15593
|
const output = await dispatchpagestep(step, tabid2, origin, plan);
|
|
14866
15594
|
if (!output?.ok) return output ?? { ok: false, summary: "The key hold was not delivered." };
|
|
14867
|
-
const options =
|
|
15595
|
+
const options = stepoptions6(step);
|
|
14868
15596
|
const holdid = typeof options.holdid === "string" && options.holdid.trim() ? options.holdid : randomid();
|
|
14869
15597
|
const modifiers = Array.isArray(options.modifiers) ? options.modifiers.filter((item) => typeof item === "string") : [];
|
|
14870
15598
|
const hold = { holdid, key: step.value ?? "", ...modifiers.length > 0 ? { modifiers } : {}, tabid: tabid2, stepid: step.id, pressedat: Date.now() };
|
|
@@ -14897,7 +15625,7 @@ async function executedismissdialog(step, session, plan, tabid2, origin) {
|
|
|
14897
15625
|
return { ok: true, summary: `Dialog handler armed${answer} for the next confirm, alert or prompt.` };
|
|
14898
15626
|
}
|
|
14899
15627
|
async function executeretryaction(step, session, plan, tabid2, origin) {
|
|
14900
|
-
const rule =
|
|
15628
|
+
const rule = stepoptions6(step).retryrule;
|
|
14901
15629
|
const inner = resolvedinnerstep(step, plan);
|
|
14902
15630
|
if (!inner) throw new Error("The reviewed wrapper step could not be resolved.");
|
|
14903
15631
|
const innergate = validatestep(inner, origin);
|
|
@@ -14933,8 +15661,8 @@ async function executeenterframe(step, plan, tabid2, origin) {
|
|
|
14933
15661
|
if (!inner) throw new Error("The reviewed frame wrapper step could not be resolved.");
|
|
14934
15662
|
const innergate = validatestep(inner, origin);
|
|
14935
15663
|
if (!innergate.allowed) throw new Error(`The wrapped step is not allowed: ${innergate.reason}`);
|
|
14936
|
-
const options =
|
|
14937
|
-
const inneroptions = inner.options ?
|
|
15664
|
+
const options = stepoptions6(step);
|
|
15665
|
+
const inneroptions = inner.options ? stepoptions6(inner) : void 0;
|
|
14938
15666
|
const derived = { ...step, options: JSON.stringify({ ...options, kind: inner.kind, ...inner.target ? { target: inner.target } : {}, ...inner.value ? { value: inner.value } : {}, ...inneroptions ? { options: inneroptions } : {} }) };
|
|
14939
15667
|
return dispatchpagestep(derived, tabid2, origin, plan);
|
|
14940
15668
|
}
|
|
@@ -14946,7 +15674,7 @@ function detailarray(details, key) {
|
|
|
14946
15674
|
return Array.isArray(value) ? value : [];
|
|
14947
15675
|
}
|
|
14948
15676
|
async function executediffsnapshots(step, session, plan, tabid2, origin) {
|
|
14949
|
-
const options =
|
|
15677
|
+
const options = stepoptions6(step);
|
|
14950
15678
|
const versions = Array.isArray(options.versions) ? options.versions.filter((item) => typeof item === "number") : [];
|
|
14951
15679
|
const baseversion = versions[0];
|
|
14952
15680
|
const targetversion = versions[1];
|
|
@@ -14969,7 +15697,7 @@ async function executediffsnapshots(step, session, plan, tabid2, origin) {
|
|
|
14969
15697
|
return { ok: Boolean(output.ok), summary: output.summary, details: { ...output.details ?? {}, versions: [baseversion, targetversion] } };
|
|
14970
15698
|
}
|
|
14971
15699
|
async function executewatchstep(step, session, plan, tabid2, origin) {
|
|
14972
|
-
const options =
|
|
15700
|
+
const options = stepoptions6(step);
|
|
14973
15701
|
const watchid = typeof options.watchid === "string" && options.watchid.trim() ? options.watchid : randomid();
|
|
14974
15702
|
const scopes = Array.isArray(options.scopes) ? options.scopes.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
|
|
14975
15703
|
const events = Array.isArray(options.events) ? options.events.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
|
|
@@ -15651,7 +16379,7 @@ function commandtabids(step, options) {
|
|
|
15651
16379
|
return listed.length > 0 ? listed : single;
|
|
15652
16380
|
}
|
|
15653
16381
|
async function executetabscommand(step, session, plan, sessiontabid) {
|
|
15654
|
-
const options =
|
|
16382
|
+
const options = stepoptions6(step);
|
|
15655
16383
|
const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
|
|
15656
16384
|
const windowid = step.value && /^\d+$/.test(step.value) ? Number.parseInt(step.value, 10) : 0;
|
|
15657
16385
|
const layoutgate = layoutmutationgranted(session, Date.now());
|
|
@@ -15927,7 +16655,7 @@ async function executetabscommand(step, session, plan, sessiontabid) {
|
|
|
15927
16655
|
}
|
|
15928
16656
|
}
|
|
15929
16657
|
async function executesaveprofiles(step, session, origin) {
|
|
15930
|
-
const options =
|
|
16658
|
+
const options = stepoptions6(step);
|
|
15931
16659
|
const record2 = parseformrecord(options.formrecord);
|
|
15932
16660
|
const name = typeof options.name === "string" ? options.name : "";
|
|
15933
16661
|
if (!name || !record2) throw new Error("A reviewed profile name and form record are required.");
|
|
@@ -15947,7 +16675,7 @@ async function executeasksubmit(step, session, plan, tabid2, origin) {
|
|
|
15947
16675
|
return { ok: true, summary: `Asksubmit prompt opened for form ${ticket.form || "the reviewed form"}; the submission waits for your approval.`, details: { ticket, values } };
|
|
15948
16676
|
}
|
|
15949
16677
|
async function executesubmitform(step, session, plan, tabid2, origin) {
|
|
15950
|
-
const consentref = typeof
|
|
16678
|
+
const consentref = typeof stepoptions6(step).consentref === "string" ? stepoptions6(step).consentref : "";
|
|
15951
16679
|
const ticket = (await memory.gettickets()).find((item) => item.approved === true && (item.consentref === consentref || item.id === consentref));
|
|
15952
16680
|
if (!ticket) throw new Error("No approved asksubmit ticket matches the reviewed consent ref; approve the submission in the review panel first.");
|
|
15953
16681
|
const output = await dispatchpagestep(step, tabid2, origin, plan) ?? { ok: false, summary: "The form submission returned no result." };
|
|
@@ -15971,7 +16699,7 @@ async function executeretryform(step, session, plan, tabid2, origin) {
|
|
|
15971
16699
|
return { ok: Boolean(output?.ok), summary: output?.summary ?? "The retried submission returned no result.", details: { attempts, windows, ok: Boolean(output?.ok) } };
|
|
15972
16700
|
}
|
|
15973
16701
|
async function executeconsentpassword(step, session, plan, tabid2, origin) {
|
|
15974
|
-
const consentref = typeof
|
|
16702
|
+
const consentref = typeof stepoptions6(step).consentref === "string" ? stepoptions6(step).consentref : "";
|
|
15975
16703
|
const gate = passwordconsentgranted(step);
|
|
15976
16704
|
if (!gate.allowed) throw new Error(gate.reason ?? "A password fill requires a reviewed consent ref.");
|
|
15977
16705
|
const output = await dispatchpagestep(step, tabid2, origin, plan);
|
|
@@ -15983,7 +16711,7 @@ async function executeattachfile(step, session, plan, tabid2, origin) {
|
|
|
15983
16711
|
const artifacts = await memory.getartifacts();
|
|
15984
16712
|
const artifact = artifacts.find((item) => item.name === name || item.id === name);
|
|
15985
16713
|
if (!artifact) throw new Error(`No generated artifact named ${name} exists in the run store yet.`);
|
|
15986
|
-
const derived = { ...step, options: JSON.stringify({ ...
|
|
16714
|
+
const derived = { ...step, options: JSON.stringify({ ...stepoptions6(step), artifact: artifact.id, artifactname: artifact.name }) };
|
|
15987
16715
|
const output = await dispatchpagestep(derived, tabid2, origin, plan);
|
|
15988
16716
|
await audit("fill", `Artifact ${artifact.name} of kind ${artifact.kind} attached to the reviewed file input inside the form submission.`, { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id });
|
|
15989
16717
|
return { ...output ?? { ok: false, summary: "The artifact attachment returned no result." }, details: { ...output?.details ?? {}, artifact } };
|
|
@@ -16016,7 +16744,7 @@ async function executeformstep(step, session, plan, tabid2, origin) {
|
|
|
16016
16744
|
return executecaptchahandoff(step, session, plan, tabid2, origin);
|
|
16017
16745
|
case "fillcode": {
|
|
16018
16746
|
const stored = await memory.getcodevalue();
|
|
16019
|
-
const source = typeof
|
|
16747
|
+
const source = typeof stepoptions6(step).source === "string" ? stepoptions6(step).source : "";
|
|
16020
16748
|
const derived = stored !== void 0 && source === "reviewed" ? { ...step, value: stored } : step;
|
|
16021
16749
|
const output = await dispatchpagestep(derived, tabid2, origin, plan);
|
|
16022
16750
|
await audit("fill", `One time code typed from the reviewed source ${source}${stored !== void 0 ? " through the consent gated code entry" : ""}.`, { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id });
|
|
@@ -16087,7 +16815,7 @@ async function storeexport(stepid, datasetvalue, format, delimiter, session, pla
|
|
|
16087
16815
|
return artifact;
|
|
16088
16816
|
}
|
|
16089
16817
|
async function executedatastep(step, session, plan, tabid2, origin) {
|
|
16090
|
-
const options =
|
|
16818
|
+
const options = stepoptions6(step);
|
|
16091
16819
|
const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
|
|
16092
16820
|
switch (step.kind) {
|
|
16093
16821
|
case "scrapetable": {
|
|
@@ -16317,7 +17045,7 @@ async function verifyonerecord(record2, expected, extra) {
|
|
|
16317
17045
|
return { ok: verification.ok, summary: verification.summary, details: { verification: { ...verification.matches, state: record2.state, path: record2.path, checksum: record2.checksum, bytes: record2.bytes } } };
|
|
16318
17046
|
}
|
|
16319
17047
|
async function executefilesstep(step, session, plan, tabid2, origin) {
|
|
16320
|
-
const options =
|
|
17048
|
+
const options = stepoptions6(step);
|
|
16321
17049
|
const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
|
|
16322
17050
|
switch (step.kind) {
|
|
16323
17051
|
case "batchdownload": {
|
|
@@ -16546,7 +17274,7 @@ reconcilmimefilter().catch(() => {
|
|
|
16546
17274
|
});
|
|
16547
17275
|
var stitchprogress = /* @__PURE__ */ new Map();
|
|
16548
17276
|
function stepcaptureoptions(step) {
|
|
16549
|
-
return captureoptionsof(
|
|
17277
|
+
return captureoptionsof(stepoptions6(step).capture);
|
|
16550
17278
|
}
|
|
16551
17279
|
async function blobtodataurl(blob) {
|
|
16552
17280
|
const buffer = new Uint8Array(await blob.arrayBuffer());
|
|
@@ -16670,7 +17398,7 @@ async function encodecanvas(width, height, draw, options) {
|
|
|
16670
17398
|
return canvasdataurl(canvas, options.format, options.quality);
|
|
16671
17399
|
}
|
|
16672
17400
|
async function capturenamefor(step, plan, kind, format) {
|
|
16673
|
-
const naming =
|
|
17401
|
+
const naming = stepoptions6(step).naming;
|
|
16674
17402
|
const rule = naming && typeof naming === "object" && !Array.isArray(naming) ? naming : { run: true, step: true, sequence: true, kind: true };
|
|
16675
17403
|
const counters = (await memory.getcapturecounters()).find((item) => item.taskid === plan.id);
|
|
16676
17404
|
const advanced = advancecounter(counters?.counters ?? {}, step.id);
|
|
@@ -16710,13 +17438,62 @@ async function grabstateshot(step, session, plan, tabid2, phase) {
|
|
|
16710
17438
|
return record2;
|
|
16711
17439
|
}
|
|
16712
17440
|
async function storecapture(record2, session, plan, step, origin) {
|
|
17441
|
+
const template = templateof(step);
|
|
17442
|
+
const regions = regionsfor(await memory.getredactregions(), origin, template);
|
|
17443
|
+
record2 = redactedshot(record2, regions);
|
|
16713
17444
|
await memory.addcapture(record2);
|
|
17445
|
+
if (regions.length > 0) await audit("capture", `The capture of ${origin} on the template ${template} stored with its sensitive regions masked: ${redactionsummary(regions)}`, { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id });
|
|
16714
17446
|
const routed = await routecapture(record2, session, plan, step, origin);
|
|
16715
17447
|
await memory.setprogress(recordcapture(await memory.getprogress(), plan.id, step.id, record2, Date.now()));
|
|
16716
17448
|
await refreshbadge();
|
|
16717
17449
|
return { record: record2, routed };
|
|
16718
17450
|
}
|
|
17451
|
+
var activeredactregions = [];
|
|
17452
|
+
async function drawredactoverlays(tabid2) {
|
|
17453
|
+
if (activeredactregions.length === 0) return;
|
|
17454
|
+
const rects = activeredactregions.map((region) => ({ x: region.x, y: region.y, width: region.width, height: region.height }));
|
|
17455
|
+
await chrome.scripting.executeScript({ target: { tabId: tabid2 }, func: (overlays) => {
|
|
17456
|
+
let host = document.getElementById("devthinkredacthost");
|
|
17457
|
+
if (!host) {
|
|
17458
|
+
host = document.createElement("div");
|
|
17459
|
+
host.id = "devthinkredacthost";
|
|
17460
|
+
host.style.position = "fixed";
|
|
17461
|
+
host.style.inset = "0";
|
|
17462
|
+
host.style.zIndex = "2147483647";
|
|
17463
|
+
host.style.pointerEvents = "none";
|
|
17464
|
+
document.documentElement.appendChild(host);
|
|
17465
|
+
}
|
|
17466
|
+
for (const overlay of overlays) {
|
|
17467
|
+
const rect = document.createElement("div");
|
|
17468
|
+
rect.style.position = "fixed";
|
|
17469
|
+
rect.style.left = `${overlay.x}px`;
|
|
17470
|
+
rect.style.top = `${overlay.y}px`;
|
|
17471
|
+
rect.style.width = `${overlay.width}px`;
|
|
17472
|
+
rect.style.height = `${overlay.height}px`;
|
|
17473
|
+
rect.style.background = "#000";
|
|
17474
|
+
host.appendChild(rect);
|
|
17475
|
+
}
|
|
17476
|
+
}, args: [rects] }).catch(() => {
|
|
17477
|
+
});
|
|
17478
|
+
}
|
|
17479
|
+
async function clearredactoverlays(tabid2) {
|
|
17480
|
+
if (activeredactregions.length === 0) return;
|
|
17481
|
+
await chrome.scripting.executeScript({ target: { tabId: tabid2 }, func: () => {
|
|
17482
|
+
document.getElementById("devthinkredacthost")?.remove();
|
|
17483
|
+
} }).catch(() => {
|
|
17484
|
+
});
|
|
17485
|
+
}
|
|
16719
17486
|
async function executecapturestep(step, session, plan, tabid2, origin) {
|
|
17487
|
+
activeredactregions = regionsfor(await memory.getredactregions(), origin, templateof(step));
|
|
17488
|
+
await drawredactoverlays(tabid2);
|
|
17489
|
+
try {
|
|
17490
|
+
return await executecapturestepinner(step, session, plan, tabid2, origin);
|
|
17491
|
+
} finally {
|
|
17492
|
+
await clearredactoverlays(tabid2);
|
|
17493
|
+
activeredactregions = [];
|
|
17494
|
+
}
|
|
17495
|
+
}
|
|
17496
|
+
async function executecapturestepinner(step, session, plan, tabid2, origin) {
|
|
16720
17497
|
const options = stepcaptureoptions(step);
|
|
16721
17498
|
const format = options.format ?? "png";
|
|
16722
17499
|
const ratio = options.pixelratio ?? 1;
|
|
@@ -16739,7 +17516,7 @@ async function executecapturestep(step, session, plan, tabid2, origin) {
|
|
|
16739
17516
|
return { ok: true, summary: `Captured the visible viewport at ${record2.width} by ${record2.height} pixels.`, details: { capture: { id: record2.id, kind: record2.kind, format: record2.format, width: record2.width, height: record2.height, bytes: (record2.bytes ?? "").length, exporttarget: stored.routed.target } } };
|
|
16740
17517
|
}
|
|
16741
17518
|
if (step.kind === "shotfullpage") {
|
|
16742
|
-
const rawoptions =
|
|
17519
|
+
const rawoptions = stepoptions6(step);
|
|
16743
17520
|
const settle2 = typeof rawoptions.settle === "number" ? rawoptions.settle : 150;
|
|
16744
17521
|
const overlap = typeof rawoptions.overlap === "number" ? rawoptions.overlap : 0;
|
|
16745
17522
|
const wait = typeof rawoptions.wait === "number" ? rawoptions.wait : void 0;
|
|
@@ -16776,7 +17553,7 @@ async function executecapturestep(step, session, plan, tabid2, origin) {
|
|
|
16776
17553
|
}
|
|
16777
17554
|
if (step.kind === "shotelement") {
|
|
16778
17555
|
const selector = step.target ?? "";
|
|
16779
|
-
const settle2 = typeof
|
|
17556
|
+
const settle2 = typeof stepoptions6(step).settle === "number" ? stepoptions6(step).settle : 150;
|
|
16780
17557
|
const measured = await bridgecall(tabid2, "measurepage");
|
|
16781
17558
|
const targetinfo = await bridgecall(tabid2, "elementrect", selector);
|
|
16782
17559
|
if (!targetinfo.ok || !targetinfo.rect) throw new Error(targetinfo.summary);
|
|
@@ -16817,7 +17594,7 @@ async function executecapturestep(step, session, plan, tabid2, origin) {
|
|
|
16817
17594
|
}
|
|
16818
17595
|
}
|
|
16819
17596
|
if (step.kind === "shotregion") {
|
|
16820
|
-
const rawoptions =
|
|
17597
|
+
const rawoptions = stepoptions6(step);
|
|
16821
17598
|
const rect = rawoptions.regionrect;
|
|
16822
17599
|
if (!rect) throw new Error("A reviewed regionrect is required in options.");
|
|
16823
17600
|
const container = typeof rawoptions.container === "string" ? rawoptions.container : void 0;
|
|
@@ -16858,7 +17635,7 @@ async function executecapturestep(step, session, plan, tabid2, origin) {
|
|
|
16858
17635
|
}
|
|
16859
17636
|
}
|
|
16860
17637
|
if (step.kind === "contactsheet") {
|
|
16861
|
-
const rawoptions =
|
|
17638
|
+
const rawoptions = stepoptions6(step);
|
|
16862
17639
|
const elements = (Array.isArray(rawoptions.elements) ? rawoptions.elements : []).filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
16863
17640
|
const layout = rawoptions.sheet && typeof rawoptions.sheet === "object" && !Array.isArray(rawoptions.sheet) ? rawoptions.sheet : { cellsize: 240, columns: 3, label: "both" };
|
|
16864
17641
|
const measured = await bridgecall(tabid2, "measurepage");
|
|
@@ -16969,7 +17746,7 @@ async function thumbonecapture(source, directive, plan, step) {
|
|
|
16969
17746
|
return { id: randomid(), runid: plan.id, stepid: step.id, kind: "makethumbs", format, width: geometry.width, height: geometry.height, capturedat: Date.now(), bytes: dataurl, name, target: source.id };
|
|
16970
17747
|
}
|
|
16971
17748
|
async function executemediastep(step, session, plan, tabid2, origin) {
|
|
16972
|
-
const options =
|
|
17749
|
+
const options = stepoptions6(step);
|
|
16973
17750
|
const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
|
|
16974
17751
|
const gate = mediagate(session, tabid2, origin, Date.now());
|
|
16975
17752
|
if (!gate.allowed) throw new Error(gate.reason ?? "The media capture needs the active session tab grant.");
|
|
@@ -17228,7 +18005,7 @@ async function attachapikeys(names, origin) {
|
|
|
17228
18005
|
return { headers, keys: attached };
|
|
17229
18006
|
}
|
|
17230
18007
|
async function executehttpstep(step, session, plan, tabid2, origin) {
|
|
17231
|
-
const options =
|
|
18008
|
+
const options = stepoptions6(step);
|
|
17232
18009
|
const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
|
|
17233
18010
|
if (step.kind === "fetchurl") {
|
|
17234
18011
|
const request = fetchrequestof(options.fetch);
|
|
@@ -17493,7 +18270,7 @@ async function closechannelsforrun(runid) {
|
|
|
17493
18270
|
channelbuses.clear();
|
|
17494
18271
|
}
|
|
17495
18272
|
async function executesocketstep(step, session, plan, tabid2, origin) {
|
|
17496
|
-
const options =
|
|
18273
|
+
const options = stepoptions6(step);
|
|
17497
18274
|
const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
|
|
17498
18275
|
if (step.kind === "opensocket") {
|
|
17499
18276
|
const channel = channeloptionsof(options.socket);
|
|
@@ -17627,7 +18404,7 @@ async function executesocketstep(step, session, plan, tabid2, origin) {
|
|
|
17627
18404
|
throw new Error("Unsupported socket observation kind.");
|
|
17628
18405
|
}
|
|
17629
18406
|
async function executenetwatchstep(step, session, plan, tabid2, origin) {
|
|
17630
|
-
const options =
|
|
18407
|
+
const options = stepoptions6(step);
|
|
17631
18408
|
const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
|
|
17632
18409
|
if (step.kind === "watchrequests") {
|
|
17633
18410
|
const watch = options.watch && typeof options.watch === "object" && !Array.isArray(options.watch) ? options.watch : {};
|
|
@@ -17779,7 +18556,7 @@ function timelinedetail(entry, runid) {
|
|
|
17779
18556
|
return { id: randomid(), runid, stepid: record2.stepid, time: record2.time, level: record2.level, source: record2.source, message: record2.message };
|
|
17780
18557
|
}
|
|
17781
18558
|
async function executetimelinestep(step, session, plan, tabid2, origin) {
|
|
17782
|
-
const options =
|
|
18559
|
+
const options = stepoptions6(step);
|
|
17783
18560
|
const watch = options.watch && typeof options.watch === "object" && !Array.isArray(options.watch) ? options.watch : {};
|
|
17784
18561
|
const watchwindow = typeof watch.window === "number" && Number.isFinite(watch.window) && watch.window >= 0 ? watch.window : 0;
|
|
17785
18562
|
const extra = { sessionid: session.id, planid: plan.id, stepid: step.id };
|
|
@@ -17934,7 +18711,7 @@ function pauseframes(entry) {
|
|
|
17934
18711
|
});
|
|
17935
18712
|
}
|
|
17936
18713
|
async function executecdpstep(step, session, plan, tabid2, origin) {
|
|
17937
|
-
const options =
|
|
18714
|
+
const options = stepoptions6(step);
|
|
17938
18715
|
const extra = { sessionid: session.id, planid: plan.id, stepid: step.id };
|
|
17939
18716
|
const debuggatecheck = debuggate(session, tabid2, origin, Date.now());
|
|
17940
18717
|
if (!debuggatecheck.allowed) throw new Error(debuggatecheck.reason ?? "The devtools protocol step stays outside the debug gate.");
|
|
@@ -18168,7 +18945,7 @@ async function sampleheapforstep(tracker, stepid, tabid2, origin, plan) {
|
|
|
18168
18945
|
if (trend.flaggedsteps.includes(stepid)) await memory.addtimelineentry({ id: randomid(), runid: tracker.runid, stepid, time: now, level: "warn", source: "longtask", message: `Heap growth of step ${stepid} exceeds the reviewed slope of ${tracker.slope} bytes per millisecond; the step is flagged in the memory trend.` });
|
|
18169
18946
|
}
|
|
18170
18947
|
async function executeprofilestep(step, session, plan, tabid2, origin) {
|
|
18171
|
-
const options =
|
|
18948
|
+
const options = stepoptions6(step);
|
|
18172
18949
|
const extra = { sessionid: session.id, planid: plan.id, stepid: step.id };
|
|
18173
18950
|
const targets = profiletargetsof(options);
|
|
18174
18951
|
const grants = await memory.getdebuggergrants();
|
|
@@ -18497,7 +19274,7 @@ async function controlledfetch(runid, url, init, controller, window2, streamstat
|
|
|
18497
19274
|
return response;
|
|
18498
19275
|
}
|
|
18499
19276
|
async function executenetcontrolstep(step, session, plan, tabid2, origin) {
|
|
18500
|
-
const options =
|
|
19277
|
+
const options = stepoptions6(step);
|
|
18501
19278
|
const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
|
|
18502
19279
|
const ruleset = rulesetof(plan.id);
|
|
18503
19280
|
if (step.kind === "blockrequest") {
|
|
@@ -18744,7 +19521,7 @@ async function enforcewindowreview(step, session, plan) {
|
|
|
18744
19521
|
const progress = plan ? await memory.getprogress() : void 0;
|
|
18745
19522
|
const tasktabids = plan ? trackedtasktabs(progress, plan.id) : [];
|
|
18746
19523
|
const count = tasktabsinwindow(await livetabs(), windowid, tasktabids);
|
|
18747
|
-
const gate = windowclosegate(count,
|
|
19524
|
+
const gate = windowclosegate(count, stepoptions6(step).reviewed === true);
|
|
18748
19525
|
if (!gate.allowed) throw new Error(gate.reason ?? "The window close needs explicit review.");
|
|
18749
19526
|
if (session && count > 0) await audit("window", `Window ${windowid} closes while holding ${count} task tab${count === 1 ? "" : "s"} under the explicit reviewed flag.`, { ...session ? { sessionid: session.id } : {}, ...plan ? { planid: plan.id } : {}, stepid: step.id });
|
|
18750
19527
|
}
|
|
@@ -18830,7 +19607,7 @@ async function revertemulationforrun(runid, reason, tabid2) {
|
|
|
18830
19607
|
}
|
|
18831
19608
|
}
|
|
18832
19609
|
async function executeemulationstep(step, session, plan, tabid2, origin) {
|
|
18833
|
-
const options =
|
|
19610
|
+
const options = stepoptions6(step);
|
|
18834
19611
|
const extra = { sessionid: session.id, planid: plan.id, stepid: step.id };
|
|
18835
19612
|
const revertplan = revertplanof(options.revertplan) ?? [];
|
|
18836
19613
|
const family = familyofkind(step.kind) ?? "device";
|
|
@@ -18962,7 +19739,7 @@ async function performrestore(record2, restore, session) {
|
|
|
18962
19739
|
return { restored, skippedorigins: grantscheck.skippedorigins };
|
|
18963
19740
|
}
|
|
18964
19741
|
async function executesessionstep(step, session, plan, tabid2, origin) {
|
|
18965
|
-
const options =
|
|
19742
|
+
const options = stepoptions6(step);
|
|
18966
19743
|
const extra = { sessionid: session.id, planid: plan.id, stepid: step.id };
|
|
18967
19744
|
if (step.kind === "persiststate") {
|
|
18968
19745
|
const progress = await memory.getprogress();
|
|
@@ -19107,7 +19884,7 @@ async function dispatchworkflowstep(step, context) {
|
|
|
19107
19884
|
return { ok: Boolean(output.ok), summary: output.summary, ...output.details !== void 0 ? { details: output.details } : {} };
|
|
19108
19885
|
}
|
|
19109
19886
|
async function executedelaystep(step) {
|
|
19110
|
-
const options =
|
|
19887
|
+
const options = stepoptions6({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.options !== void 0 ? { options: step.options } : {} });
|
|
19111
19888
|
const delay = delayof(options.delay);
|
|
19112
19889
|
const sampled = delayjitter(delay, hashseed(`${step.id}:${Date.now()}`));
|
|
19113
19890
|
const transport = await sleepreviewed(sampled, step.id);
|
|
@@ -19154,7 +19931,7 @@ async function sleepreviewed(sampled, stepid) {
|
|
|
19154
19931
|
return "timer";
|
|
19155
19932
|
}
|
|
19156
19933
|
async function executewaitelement(step, tabid2) {
|
|
19157
|
-
const options =
|
|
19934
|
+
const options = stepoptions6({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.target !== void 0 ? { target: step.target } : {}, ...step.options !== void 0 ? { options: step.options } : {} });
|
|
19158
19935
|
const wait = waitof(options.wait, step.target);
|
|
19159
19936
|
const startedat = Date.now();
|
|
19160
19937
|
const starttab = await chrome.tabs.get(tabid2).catch(() => void 0);
|
|
@@ -19182,7 +19959,7 @@ function waitof(value, target) {
|
|
|
19182
19959
|
return { selector, timeout, poll };
|
|
19183
19960
|
}
|
|
19184
19961
|
async function executecomputestep(step, session) {
|
|
19185
|
-
const options =
|
|
19962
|
+
const options = stepoptions6({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.options !== void 0 ? { options: step.options } : {} });
|
|
19186
19963
|
const expression = options.expression;
|
|
19187
19964
|
if (!expression || typeof expression !== "object") throw new Error("The compute step needs a reviewed expression.");
|
|
19188
19965
|
const scopes = runscopes(options.variables);
|
|
@@ -19191,7 +19968,7 @@ async function executecomputestep(step, session) {
|
|
|
19191
19968
|
return { ok: true, summary: `Computed ${expression.result} = ${typeof value === "string" ? `"${value}"` : String(value)} through the ${expression.operator} operator.`, details: { result: expression.result, kind: expression.resultkind, value } };
|
|
19192
19969
|
}
|
|
19193
19970
|
async function executeextractvarsstep(step, session) {
|
|
19194
|
-
const options =
|
|
19971
|
+
const options = stepoptions6({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.value !== void 0 ? { value: step.value } : {}, ...step.options !== void 0 ? { options: step.options } : {} });
|
|
19195
19972
|
const rule = options.rule;
|
|
19196
19973
|
if (!rule || typeof rule !== "object" || typeof rule.pattern !== "string") throw new Error("The variable extraction needs a reviewed regex rule.");
|
|
19197
19974
|
const text2 = typeof options.text === "string" ? options.text : step.value ?? "";
|
|
@@ -19204,7 +19981,7 @@ async function executeextractvarsstep(step, session) {
|
|
|
19204
19981
|
return { ok: true, summary: `Captured ${extraction.variables.length} variable${extraction.variables.length === 1 ? "" : "s"} from the reviewed text.`, details: { matched: true, variables: extraction.variables } };
|
|
19205
19982
|
}
|
|
19206
19983
|
async function executeworkflowstep(step, session, plan, tabid2, origin) {
|
|
19207
|
-
const options =
|
|
19984
|
+
const options = stepoptions6(step);
|
|
19208
19985
|
if (step.kind === "composeworkflow") {
|
|
19209
19986
|
const payload = options.workflow;
|
|
19210
19987
|
if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new Error("The workflow composition needs the reviewed workflow payload.");
|
|
@@ -19260,7 +20037,7 @@ function workflowstepofentry(value) {
|
|
|
19260
20037
|
return blockinvocationof(value);
|
|
19261
20038
|
}
|
|
19262
20039
|
async function executeworkflowrun(step, session, plan, tabid2, origin, dry) {
|
|
19263
|
-
const options =
|
|
20040
|
+
const options = stepoptions6(step);
|
|
19264
20041
|
const workflowid = typeof options.workflowid === "string" ? options.workflowid : "";
|
|
19265
20042
|
const storedrecord = await memory.getworkflowrecord(workflowid);
|
|
19266
20043
|
if (!storedrecord) throw new Error(`No composed workflow matches ${workflowid || "the reviewed id"}.`);
|
|
@@ -19423,7 +20200,7 @@ async function storetimeoutabort(run, step, message, budget) {
|
|
|
19423
20200
|
return { run: aborted, log: [entry] };
|
|
19424
20201
|
}
|
|
19425
20202
|
async function executetriggerstep(step, session, plan, tabid2, origin) {
|
|
19426
|
-
const options =
|
|
20203
|
+
const options = stepoptions6(step);
|
|
19427
20204
|
const family = triggerfamilyof(step.kind);
|
|
19428
20205
|
if (!family) throw new Error(`The ${step.kind} step is not a reviewed trigger kind.`);
|
|
19429
20206
|
const workflowid = typeof options.workflowid === "string" ? options.workflowid : "";
|
|
@@ -19649,6 +20426,7 @@ async function executeaction(step, session, plan, tabid2, origin, settings, verd
|
|
|
19649
20426
|
}
|
|
19650
20427
|
throw new Error(securityverdict.reason);
|
|
19651
20428
|
}
|
|
20429
|
+
step = await resolvevaultvalues(step, session);
|
|
19652
20430
|
if (session && plan && plan.state === "approved" && mode === "plan") await openplanrun(session, plan);
|
|
19653
20431
|
if (plan && plan.state === "approved") await markpendingstep(plan, step.id);
|
|
19654
20432
|
if (routing.environment === "sandboxframe") return executesandboxrender(step, session, plan, origin);
|
|
@@ -19825,7 +20603,7 @@ async function previewstep(stepid) {
|
|
|
19825
20603
|
if (!step) throw new Error("Reviewed step was not found.");
|
|
19826
20604
|
const gate = canpreview({ session, plan, step, tabid: tab.id, origin });
|
|
19827
20605
|
if (!gate.allowed) throw new Error(gate.reason);
|
|
19828
|
-
if (!step.target && !
|
|
20606
|
+
if (!step.target && !stepoptions6(step).targetref) throw new Error("Only a target-based step can be previewed.");
|
|
19829
20607
|
const result = await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: (action, expectedorigin) => {
|
|
19830
20608
|
const bridge = globalThis.devthinkbridge;
|
|
19831
20609
|
if (!bridge) throw new Error("Devthink page bridge is unavailable.");
|
|
@@ -19876,8 +20654,37 @@ async function extractionreportValue() {
|
|
|
19876
20654
|
async function provenancereportValue() {
|
|
19877
20655
|
return provenancereport({ records: await memory.getprovenances() });
|
|
19878
20656
|
}
|
|
20657
|
+
var commandschemas = {
|
|
20658
|
+
security: { allowlist: "object", profile: "object", consent: "object", revoke: "object", mask: "object", read: "object", export: "object", settings: "object", gate: "object", vault: "object", connectallow: "object", ratelimit: "object", redact: "object" },
|
|
20659
|
+
environments: { action: "string", grants: "array", requestcapability: "boolean", pool: "object", offscreenclose: "boolean", sandbox: "object", settings: "object", render: "object", sandboxhost: "object" },
|
|
20660
|
+
transparency: {},
|
|
20661
|
+
execute: { stepid: "string" },
|
|
20662
|
+
configure: { endpoint: "string" }
|
|
20663
|
+
};
|
|
20664
|
+
function schemavalidation(message) {
|
|
20665
|
+
if (!Boolean(message) || typeof message !== "object" || Array.isArray(message)) return [{ path: "message", expected: "object", found: Array.isArray(message) ? "array" : typeof message, reason: "Every inbound command travels as one plain object; schemastrict refuses the carrier before dispatch." }];
|
|
20666
|
+
const command = message;
|
|
20667
|
+
if (typeof command.kind !== "string" || command.kind.trim() === "") return [{ path: "kind", expected: "string", found: typeof command.kind, reason: "Every inbound command names its kind as a non-empty string; a kindless command never dispatches." }];
|
|
20668
|
+
const schema = commandschemas[command.kind];
|
|
20669
|
+
if (schema === void 0) return [];
|
|
20670
|
+
return schemacheck({ command, schema }).errors;
|
|
20671
|
+
}
|
|
19879
20672
|
async function handlerequest(message, sender) {
|
|
19880
|
-
|
|
20673
|
+
const originverdict = origincheckof({ ...sender.id !== void 0 ? { senderid: sender.id } : {}, ...sender.origin !== void 0 ? { senderorigin: sender.origin } : {}, extensionid: chrome.runtime.id, connectallow: await memory.getconnectallow() });
|
|
20674
|
+
const inboundgate = origincheckgate({ verdict: originverdict });
|
|
20675
|
+
if (!inboundgate.allowed) {
|
|
20676
|
+
await audit("inbound", `The origincheck dropped an inbound message from ${originverdict.sender}${originverdict.origin !== "" ? ` of ${originverdict.origin}` : ""} without handler execution: ${inboundgate.reason}`, {}).catch(() => {
|
|
20677
|
+
});
|
|
20678
|
+
throw new Error(inboundgate.reason);
|
|
20679
|
+
}
|
|
20680
|
+
if (sender.id === chrome.runtime.id && !extensionpage(sender)) throw new Error("Requests are accepted only from Devthink extension pages.");
|
|
20681
|
+
const schemaerrors = schemavalidation(message);
|
|
20682
|
+
const schemagate = schemaguardgate({ errors: schemaerrors });
|
|
20683
|
+
if (!schemagate.allowed) {
|
|
20684
|
+
await audit("schema", `The schemastrict validation refused an inbound command with ${schemaerrors.length} schema error${schemaerrors.length === 1 ? "" : "s"} at ${schemaerrors.map((error) => error.path).join(", ")}; the refusal echoes no payload.`, {}).catch(() => {
|
|
20685
|
+
});
|
|
20686
|
+
throw new Error(schemagate.reason);
|
|
20687
|
+
}
|
|
19881
20688
|
const input = message;
|
|
19882
20689
|
switch (input.kind) {
|
|
19883
20690
|
case "configure": {
|
|
@@ -23048,6 +23855,12 @@ async function handlerequest(message, sender) {
|
|
|
23048
23855
|
}
|
|
23049
23856
|
throw new Error("The swarm merge request carries no merge, report, export, compare, lesson, costs, timeline, replay or snapshot action.");
|
|
23050
23857
|
}
|
|
23858
|
+
case "transparency": {
|
|
23859
|
+
const view = await memory.gettransparencyview();
|
|
23860
|
+
const report = transparencyreport({ grants: transparencygrants({ allowlist: view.allowlist, profiles: view.profiles }), windows: windowhistory(view.windows), connectallow: connectallowlist(view.connectallow), permdiffs: view.permdiffs, safedefaults: view.safedefaults, vault: vaultview(view.vault) });
|
|
23861
|
+
await audit("transparency", `The transparencypage read its transparency report in one memory read: ${report.grants.length} grant row${report.grants.length === 1 ? "" : "s"} with revoke actions, ${report.windows.length} consent window${report.windows.length === 1 ? "" : "s"}, ${report.connectallow.length} connectallow entr${report.connectallow.length === 1 ? "y" : "ies"}, ${report.permdiffs.length} permdiff record${report.permdiffs.length === 1 ? "" : "s"} and ${report.vault.length} vault label${report.vault.length === 1 ? "" : "s"}.`, {});
|
|
23862
|
+
return report;
|
|
23863
|
+
}
|
|
23051
23864
|
case "security": {
|
|
23052
23865
|
const input2 = message;
|
|
23053
23866
|
const now = Date.now();
|
|
@@ -23185,10 +23998,103 @@ async function handlerequest(message, sender) {
|
|
|
23185
23998
|
}
|
|
23186
23999
|
if (input2.settings.logretention !== void 0) patch.logretention = input2.settings.logretention;
|
|
23187
24000
|
if (input2.settings.maskshapes !== void 0) patch.maskshapes = input2.settings.maskshapes.map((shape) => shape.trim().toLowerCase()).filter((shape) => shape !== "");
|
|
24001
|
+
if (input2.settings.phishdistance !== void 0) {
|
|
24002
|
+
const thresholdgate = phishthresholdgate(input2.settings.phishdistance);
|
|
24003
|
+
if (!thresholdgate.allowed) throw new Error(thresholdgate.reason);
|
|
24004
|
+
patch.phishdistance = input2.settings.phishdistance;
|
|
24005
|
+
}
|
|
24006
|
+
if (input2.settings.phishfreshness !== void 0) patch.phishfreshness = input2.settings.phishfreshness;
|
|
23188
24007
|
await memory.setsettings(patch);
|
|
23189
24008
|
await audit("configure", `The user updated the security settings: consent duration ${patch.consentduration !== void 0 ? `${patch.consentduration} milliseconds` : "the prompt asks every time"}, log retention ${patch.logretention !== void 0 ? `${patch.logretention} milliseconds` : "every sealed log stays"}, mask shapes ${patch.maskshapes?.length ?? 0} configured.`, {});
|
|
23190
24009
|
return { ...await securityviewof(), configured: true };
|
|
23191
24010
|
}
|
|
24011
|
+
if (input2.gate !== void 0 && input2.gate.resolve !== void 0) {
|
|
24012
|
+
const gateid = input2.gate.resolve.gateid?.trim() ?? "";
|
|
24013
|
+
const decision = input2.gate.resolve.decision === "refused" ? "refused" : "resolved";
|
|
24014
|
+
if (gateid === "") throw new Error("The gate resolution names its single gate.");
|
|
24015
|
+
const resolved = resolvegate({ gates: await memory.getgates(), gateid, decision, actor: "user", now });
|
|
24016
|
+
if (resolved.resolution === void 0 || resolved.gates === void 0) throw new Error(`No open gate ${gateid} exists to resolve; a gate resolution stays a distinct human action on one gate.`);
|
|
24017
|
+
await memory.setgates(resolved.gates);
|
|
24018
|
+
await memory.addgateresolution(resolved.resolution);
|
|
24019
|
+
const gateplan = await memory.getplan();
|
|
24020
|
+
const gate = resolved.gates.find((candidate) => candidate.gateid === gateid);
|
|
24021
|
+
if (gateplan && gate?.resolvedat !== void 0) await memory.setprogress(recordgatewait(await memory.getprogress(), gateplan.id, gate.stepid, { gateid: gate.gateid, kind: gate.kind, openedat: gate.openedat, resolvedat: gate.resolvedat, waitedms: Math.max(0, gate.resolvedat - gate.openedat) }, now)).catch(() => {
|
|
24022
|
+
});
|
|
24023
|
+
if (session) await appendrunevent("gate", `The user ${decision === "resolved" ? "resolved" : "refused"} the ${resolved.resolution.kind} gate ${gateid} of the step ${resolved.resolution.stepid} through one distinct human action; no timeout resolved it and no batch approved it.`, session, gate?.origin ?? session.origin, resolved.resolution.stepid).catch(() => {
|
|
24024
|
+
});
|
|
24025
|
+
await audit("gate", `The user ${decision === "resolved" ? "resolved" : "refused"} the ${resolved.resolution.kind} gate ${gateid} of the step ${resolved.resolution.stepid} through one distinct human action; no timeout resolved it and no batch approved it.`, { ...session ? { sessionid: session.id } : {}, ...gateplan ? { planid: gateplan.id } : {}, stepid: resolved.resolution.stepid });
|
|
24026
|
+
return { ...await securityviewof(), gate };
|
|
24027
|
+
}
|
|
24028
|
+
if (input2.vault !== void 0) {
|
|
24029
|
+
if (input2.vault.add !== void 0) {
|
|
24030
|
+
const label = input2.vault.add.label?.trim() ?? "";
|
|
24031
|
+
const scope = input2.vault.add.scope?.trim() !== "" && input2.vault.add.scope !== void 0 ? input2.vault.add.scope.trim() : session?.origin ?? "";
|
|
24032
|
+
const value = input2.vault.add.value ?? "";
|
|
24033
|
+
if (label === "" || scope === "" || value === "") throw new Error("The vault entry needs its label, its exact origin scope and its value; the value stays behind the vault seam.");
|
|
24034
|
+
const entry = await vaultstore({ seam: vaultseamstore, label, scope, profileid: runstateprofile, provenance: input2.vault.add.provenance === "session" ? "session" : "user", value, now });
|
|
24035
|
+
await memory.addsecret(entry);
|
|
24036
|
+
await audit("vault", `The user stored the secret ${entry.label} for ${entry.scope} behind the vault seam; the metadata keeps the label, the scope, the provenance and the digest while no plaintext value persists anywhere.`, { ...session ? { sessionid: session.id } : {} });
|
|
24037
|
+
return { ...await securityviewof(), secret: { vaultid: entry.vaultid, label: entry.label, scope: entry.scope } };
|
|
24038
|
+
}
|
|
24039
|
+
if (input2.vault.delete !== void 0) {
|
|
24040
|
+
const vaultid = input2.vault.delete.vaultid?.trim() ?? "";
|
|
24041
|
+
const entry = (await memory.getsecretvault()).find((candidate) => candidate.vaultid === vaultid);
|
|
24042
|
+
if (!entry) throw new Error(`No vault entry ${vaultid} exists.`);
|
|
24043
|
+
const dropped = await vaultdelete({ seam: vaultseamstore, entry });
|
|
24044
|
+
await memory.removesecret(vaultid);
|
|
24045
|
+
await audit("vault", `The user deleted the secret ${dropped.label} of ${entry.scope}: ${dropped.reason}`, { ...session ? { sessionid: session.id } : {} });
|
|
24046
|
+
return { ...await securityviewof(), removedsecret: vaultid };
|
|
24047
|
+
}
|
|
24048
|
+
}
|
|
24049
|
+
if (input2.connectallow !== void 0) {
|
|
24050
|
+
if (input2.connectallow.add !== void 0) {
|
|
24051
|
+
const entry = connectallowentryof({ senderid: input2.connectallow.add.senderid?.trim() ?? "", displayname: input2.connectallow.add.displayname?.trim() ?? "", ...input2.connectallow.add.origin !== void 0 && input2.connectallow.add.origin.trim() !== "" ? { origin: input2.connectallow.add.origin.trim() } : {}, now });
|
|
24052
|
+
await memory.addconnectallow(entry);
|
|
24053
|
+
await audit("inbound", `The user allowed the external sender ${entry.displayname} (${entry.senderid})${entry.origin !== void 0 ? ` of ${entry.origin}` : ""}; the connectallow list ships empty by default and holds user managed entries only.`, { ...session ? { sessionid: session.id } : {} });
|
|
24054
|
+
return { ...await securityviewof(), allowedsender: entry };
|
|
24055
|
+
}
|
|
24056
|
+
if (input2.connectallow.remove !== void 0) {
|
|
24057
|
+
const senderid = input2.connectallow.remove.senderid?.trim() ?? "";
|
|
24058
|
+
await memory.removeconnectallow(senderid);
|
|
24059
|
+
await audit("inbound", `The user removed the external sender ${senderid} from the connectallow list; the origincheck drops its messages and ports again.`, { ...session ? { sessionid: session.id } : {} });
|
|
24060
|
+
return { ...await securityviewof(), removedsender: senderid };
|
|
24061
|
+
}
|
|
24062
|
+
}
|
|
24063
|
+
if (input2.ratelimit !== void 0) {
|
|
24064
|
+
if (input2.ratelimit.set !== void 0) {
|
|
24065
|
+
const origin = input2.ratelimit.set.origin?.trim() ?? "";
|
|
24066
|
+
const limit = input2.ratelimit.set.limit ?? 0;
|
|
24067
|
+
const window2 = input2.ratelimit.set.window ?? 0;
|
|
24068
|
+
if (origin === "") throw new Error("The ratelimit bucket needs its exact origin.");
|
|
24069
|
+
const bounds = ratelimitboundsvalid(limit, window2);
|
|
24070
|
+
if (!bounds.allowed) throw new Error(bounds.reason);
|
|
24071
|
+
const bucket = bucketof({ origin, sessionid: session?.id ?? "global", limit, window: window2, now });
|
|
24072
|
+
await memory.saveratelimitbucket(bucket);
|
|
24073
|
+
await audit("rate", `The user configured the ratelimit bucket of ${origin} at ${limit} command${limit === 1 ? "" : "s"} per ${window2} milliseconds; the bounds stay user choices with no hidden ceiling.`, { ...session ? { sessionid: session.id } : {} });
|
|
24074
|
+
return { ...await securityviewof(), bucket };
|
|
24075
|
+
}
|
|
24076
|
+
if (input2.ratelimit.remove !== void 0) {
|
|
24077
|
+
const origin = input2.ratelimit.remove.origin?.trim() ?? "";
|
|
24078
|
+
const buckets = await memory.getratelimitbuckets();
|
|
24079
|
+
for (const bucket of buckets.filter((candidate) => candidate.origin === origin)) await memory.removeratelimitbucket(bucket.origin, bucket.sessionid);
|
|
24080
|
+
await audit("rate", `The user removed the ratelimit bucket of ${origin}; the origin runs without a bucket because the bounds stay user choices only.`, { ...session ? { sessionid: session.id } : {} });
|
|
24081
|
+
return { ...await securityviewof(), removedbucket: origin };
|
|
24082
|
+
}
|
|
24083
|
+
}
|
|
24084
|
+
if (input2.redact !== void 0) {
|
|
24085
|
+
if (input2.redact.add !== void 0) {
|
|
24086
|
+
const region = regionof({ origin: input2.redact.add.origin?.trim() !== "" && input2.redact.add.origin !== void 0 ? input2.redact.add.origin.trim() : session?.origin ?? "", template: input2.redact.add.template?.trim() !== "" && input2.redact.add.template !== void 0 ? input2.redact.add.template.trim() : "page", x: input2.redact.add.x ?? 0, y: input2.redact.add.y ?? 0, width: input2.redact.add.width ?? 0, height: input2.redact.add.height ?? 0, reason: input2.redact.add.reason?.trim() !== "" && input2.redact.add.reason !== void 0 ? input2.redact.add.reason.trim() : "The user drew the mask on the capture surface.", source: "userdrawn", now });
|
|
24087
|
+
await memory.addredactregion(region);
|
|
24088
|
+
await audit("capture", `The user drew the redact region ${region.id} at ${region.x},${region.y} of ${region.width}x${region.height} on ${region.origin}/${region.template}: ${region.reason}`, { ...session ? { sessionid: session.id } : {} });
|
|
24089
|
+
return { ...await securityviewof(), region };
|
|
24090
|
+
}
|
|
24091
|
+
if (input2.redact.remove !== void 0) {
|
|
24092
|
+
const id = input2.redact.remove.id?.trim() ?? "";
|
|
24093
|
+
await memory.removeredactregion(id);
|
|
24094
|
+
await audit("capture", `The user removed the redact region ${id}.`, { ...session ? { sessionid: session.id } : {} });
|
|
24095
|
+
return { ...await securityviewof(), removedregion: id };
|
|
24096
|
+
}
|
|
24097
|
+
}
|
|
23192
24098
|
const plan = await memory.getplan();
|
|
23193
24099
|
const pending = [];
|
|
23194
24100
|
if (session && plan && ["pending", "approved"].includes(plan.state)) {
|
|
@@ -23646,7 +24552,7 @@ async function raiseremoteapproval(clientid, toolname, params, step) {
|
|
|
23646
24552
|
return { content: `The approval gate ${request.id} holds the ${toolname} call; it executes once the user approves it in the panel.`, payload: { approvalid: request.id, state: "pending", ...request.timeoutat !== void 0 ? { timeoutat: request.timeoutat } : {} }, iserror: false };
|
|
23647
24553
|
}
|
|
23648
24554
|
async function executelistruns(step, session) {
|
|
23649
|
-
const options =
|
|
24555
|
+
const options = stepoptions6(step);
|
|
23650
24556
|
const statefilter = typeof options.state === "string" && options.state.trim() !== "" ? options.state : void 0;
|
|
23651
24557
|
const runs = await memory.listworkflowruns();
|
|
23652
24558
|
const selected = statefilter !== void 0 ? runs.filter((run) => run.state === statefilter) : runs;
|
|
@@ -24021,7 +24927,7 @@ async function maybeautosnapshot() {
|
|
|
24021
24927
|
await audit("session", `The reviewed auto snapshot interval stopped after ${state.interval.maxsnapshots} snapshot${state.interval.maxsnapshots === 1 ? "" : "s"}; the retention window of ${state.interval.expiry} millisecond${state.interval.expiry === 1 ? "" : "s"} expires them by user choice.`, { sessionid: session.id, planid: plan.id });
|
|
24022
24928
|
return;
|
|
24023
24929
|
}
|
|
24024
|
-
const options =
|
|
24930
|
+
const options = stepoptions6(step);
|
|
24025
24931
|
const snapshot2 = snapshotplanof(options.snapshot);
|
|
24026
24932
|
if (!snapshot2) return;
|
|
24027
24933
|
const record2 = await capturesessionrecord({ ...snapshot2, ...snapshot2.auto !== void 0 ? { auto: snapshot2.auto } : {} }, session, plan.id).catch(() => void 0);
|
|
@@ -24066,10 +24972,22 @@ async function restoreemulationstate() {
|
|
|
24066
24972
|
restoreemulationstate().catch(() => {
|
|
24067
24973
|
});
|
|
24068
24974
|
chrome.runtime.onConnect.addListener((port) => {
|
|
24069
|
-
|
|
24070
|
-
|
|
24071
|
-
|
|
24072
|
-
|
|
24975
|
+
void (async () => {
|
|
24976
|
+
const handshake = portaccept({ portname: port.name, ...port.sender?.id !== void 0 ? { senderid: port.sender.id } : {}, ...port.sender?.origin !== void 0 ? { senderorigin: port.sender.origin } : {}, extensionid: chrome.runtime.id, connectallow: await memory.getconnectallow() });
|
|
24977
|
+
if (!handshake.accepted) {
|
|
24978
|
+
await audit("inbound", `The port ${port.name} closed at its handshake: ${handshake.reason}`, {}).catch(() => {
|
|
24979
|
+
});
|
|
24980
|
+
port.disconnect();
|
|
24981
|
+
return;
|
|
24982
|
+
}
|
|
24983
|
+
if (port.name !== "devthinksidepanel" || port.sender?.id !== chrome.runtime.id || !port.sender.url?.startsWith(chrome.runtime.getURL(""))) {
|
|
24984
|
+
port.disconnect();
|
|
24985
|
+
return;
|
|
24986
|
+
}
|
|
24987
|
+
port.onMessage.addListener((message) => {
|
|
24988
|
+
handlerequest(message, port.sender ?? {}).then((value) => port.postMessage({ ok: true, value })).catch((error) => port.postMessage({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
24989
|
+
});
|
|
24990
|
+
})();
|
|
24073
24991
|
});
|
|
24074
24992
|
{
|
|
24075
24993
|
const webnavigation = chrome.webNavigation;
|
|
@@ -24155,4 +25073,16 @@ restoretriggers().catch(() => {
|
|
|
24155
25073
|
});
|
|
24156
25074
|
restorerunstates().catch(() => {
|
|
24157
25075
|
});
|
|
25076
|
+
async function recordinstalledpermdiff() {
|
|
25077
|
+
const manifest = chrome.runtime.getManifest();
|
|
25078
|
+
const permissions = [...(manifest.permissions ?? []).map((permission) => `required:${permission}`), ...(manifest.optional_permissions ?? []).map((permission) => `optional:${permission}`), ...(manifest.optional_host_permissions ?? []).map((host) => `optionalhost:${host}`)];
|
|
25079
|
+
const last = await memory.getlastpermissions();
|
|
25080
|
+
if (last !== void 0 && last.version === manifest.version) return;
|
|
25081
|
+
const diff = permissiondiff({ from: last?.permissions ?? [], to: permissions, fromversion: last?.version ?? "none", toversion: manifest.version, now: Date.now() });
|
|
25082
|
+
await memory.addpermdiff(diff);
|
|
25083
|
+
await memory.setlastpermissions(permissions, manifest.version);
|
|
25084
|
+
await audit("transparency", `The installed update to ${manifest.version} recorded its permdiff: ${permdiffsummary(diff)}`, {});
|
|
25085
|
+
}
|
|
25086
|
+
recordinstalledpermdiff().catch(() => {
|
|
25087
|
+
});
|
|
24158
25088
|
//# sourceMappingURL=background.js.map
|