@sema-agent/client-core 0.94.0 → 0.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +521 -0
- package/README.md +104 -57
- package/dist/adapt/arms.js +12 -7
- package/dist/adapt/panelTasks.js +4 -10
- package/dist/adapt/toolCards.d.ts +1 -0
- package/dist/adapt/toolCards.js +18 -5
- package/dist/adapt/wireShapes.js +5 -24
- package/dist/adapter/activeRunSelfHeal.d.ts +12 -3
- package/dist/adapter/activeRunSelfHeal.js +50 -16
- package/dist/adapter/downstream/eventToSdkMessage.js +33 -18
- package/dist/adapter/downstream/terminalToSdkResult.js +19 -12
- package/dist/adapter/runStream.js +30 -46
- package/dist/adapter/types.d.ts +7 -0
- package/dist/adapter/types.js +15 -0
- package/dist/agentSession/backgroundView.js +5 -1
- package/dist/agentSession/engineAgentRegistryRead.js +7 -5
- package/dist/agentSession/engineSessionBackgroundStop.js +25 -17
- package/dist/agentsWireCaps.d.ts +2 -0
- package/dist/agentsWireCaps.js +13 -2
- package/dist/approvalDecidedByCapability.d.ts +0 -1
- package/dist/approvalDecidedByCapability.js +2 -7
- package/dist/approvalsStreamLiveCapability.d.ts +0 -1
- package/dist/approvalsStreamLiveCapability.js +2 -6
- package/dist/atMostOnce.d.ts +8 -0
- package/dist/atMostOnce.js +36 -0
- package/dist/attachmentSeatCapability.d.ts +0 -1
- package/dist/attachmentSeatCapability.js +0 -3
- package/dist/attachmentsWireCaps.js +11 -6
- package/dist/bashExitReading.d.ts +10 -0
- package/dist/bashExitReading.js +12 -0
- package/dist/callerCwdCapability.d.ts +0 -5
- package/dist/callerCwdCapability.js +2 -13
- package/dist/centerWiringCapability.d.ts +1 -7
- package/dist/centerWiringCapability.js +18 -27
- package/dist/classifierStatus.js +4 -4
- package/dist/classifierVerdictWire.js +4 -16
- package/dist/clientSlice.js +1 -1
- package/dist/cloudConfigWireCaps.d.ts +3 -3
- package/dist/cloudConfigWireCaps.js +85 -43
- package/dist/compensations.js +1 -1
- package/dist/coreValuePorts.d.ts +11 -7
- package/dist/coreValuePorts.js +5 -8
- package/dist/credentialProvenance.d.ts +28 -0
- package/dist/credentialProvenance.js +76 -0
- package/dist/cycleOrder.d.ts +15 -0
- package/dist/cycleOrder.js +45 -0
- package/dist/decideFailureNote.js +7 -2
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/decideReceipt.js +39 -14
- package/dist/declared/supportFloorDeclared.d.ts +1 -0
- package/dist/declared/supportFloorDeclared.js +5 -0
- package/dist/deviceExecutorManagementCapability.d.ts +0 -1
- package/dist/deviceExecutorManagementCapability.js +7 -16
- package/dist/deviceRebind.d.ts +88 -0
- package/dist/deviceRebind.js +242 -0
- package/dist/displayUntrusted.d.ts +8 -3
- package/dist/displayUntrusted.js +661 -63
- package/dist/engineAgentAbsence.d.ts +2 -2
- package/dist/engineAgentPanelStore.d.ts +8 -18
- package/dist/engineAgentPanelStore.js +19 -537
- package/dist/engineCapReader.d.ts +6 -6
- package/dist/engineCapReader.js +30 -43
- package/dist/engineCapsCache.d.ts +13 -2
- package/dist/engineCapsCache.js +276 -44
- package/dist/engineCredentialRequirement.d.ts +9 -0
- package/dist/engineCredentialRequirement.js +23 -0
- package/dist/engineDirectory.d.ts +79 -0
- package/dist/engineDirectory.js +186 -0
- package/dist/engineEnvSourcing.d.ts +53 -0
- package/dist/engineEnvSourcing.js +81 -0
- package/dist/engineErrorCodes.d.ts +28 -4
- package/dist/engineErrorCodes.js +68 -25
- package/dist/engineIdentity.js +2 -0
- package/dist/engineNoticeCodes.d.ts +17 -0
- package/dist/engineNoticeCodes.js +57 -3
- package/dist/engineWireSdk.js +2 -2
- package/dist/engineWordRenames.d.ts +8 -0
- package/dist/engineWordRenames.js +13 -0
- package/dist/executionLaneCapability.d.ts +2 -3
- package/dist/executionLaneCapability.js +18 -23
- package/dist/fileHistoryCaptureCapability.d.ts +14 -1
- package/dist/fileHistoryCaptureCapability.js +72 -6
- package/dist/fileHistoryLegNotice.d.ts +3 -2
- package/dist/fileHistoryLegNotice.js +51 -2
- package/dist/fleet/bgSubagentRow.d.ts +15 -0
- package/dist/fleet/bgSubagentRow.js +67 -0
- package/dist/fleet/fleetLedger.d.ts +3 -0
- package/dist/fleet/fleetLedger.js +153 -122
- package/dist/fleet/fleetProjection.d.ts +1 -3
- package/dist/fleet/fleetProjection.js +19 -19
- package/dist/fleetAgentPanelProjection.d.ts +4 -17
- package/dist/fleetAgentPanelProjection.js +7 -197
- package/dist/fleetAgentRowLike.d.ts +16 -0
- package/dist/fleetAgentRowLike.js +1 -0
- package/dist/fleetTaskDesc.js +4 -17
- package/dist/gateOutcome.d.ts +12 -1
- package/dist/gateOutcome.js +87 -18
- package/dist/gateVocabulary.d.ts +7 -2
- package/dist/gateVocabulary.js +5 -1
- package/dist/generated/engineAskFaceTables.js +1 -1
- package/dist/generated/engineFactTables.d.ts +5 -3
- package/dist/generated/engineFactTables.js +17 -4
- package/dist/generated/engineNoticeTables.js +12 -3
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +17 -0
- package/dist/generated/settingsSchemaFns.d.ts +13 -0
- package/dist/generated/settingsSchemaFns.js +75 -0
- package/dist/generated/toolNameTables.d.ts +1 -0
- package/dist/generated/toolNameTables.js +1 -0
- package/dist/headlessPermissionModeWire.d.ts +1 -1
- package/dist/headlessPermissionModeWire.js +1 -1
- package/dist/headlessReconnectWire.js +49 -20
- package/dist/hitl/allowRuleShadow.d.ts +1 -1
- package/dist/hitl/allowRuleShadow.js +49 -8
- package/dist/hitl/approvalCompleteParked.d.ts +1 -0
- package/dist/hitl/approvalCompleteParked.js +14 -0
- package/dist/hitl/approvalEndingCause.d.ts +7 -0
- package/dist/hitl/approvalEndingCause.js +71 -0
- package/dist/hitl/approvalHolds.d.ts +12 -2
- package/dist/hitl/approvalHolds.js +53 -2
- package/dist/hitl/approvalsFeed.js +23 -11
- package/dist/hitl/askGateWire.d.ts +2 -1
- package/dist/hitl/askGateWire.js +26 -1
- package/dist/hitl/askParkRowRouting.js +1 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/automaticAnswerVerdict.js +15 -10
- package/dist/hitl/crashConverged.js +2 -0
- package/dist/hitl/decisionConflict.d.ts +3 -0
- package/dist/hitl/decisionConflict.js +41 -0
- package/dist/hitl/decisionRefusal.d.ts +12 -0
- package/dist/hitl/decisionRefusal.js +63 -4
- package/dist/hitl/frameRouter.d.ts +0 -1
- package/dist/hitl/frameRouter.js +32 -57
- package/dist/hitl/gateLedger.d.ts +5 -0
- package/dist/hitl/gateLedger.js +21 -0
- package/dist/hitl/hitlBridge.d.ts +17 -2
- package/dist/hitl/hitlBridge.js +91 -55
- package/dist/hitl/hitlHostSurface.js +3 -11
- package/dist/hitl/livePendingAsk.d.ts +16 -6
- package/dist/hitl/livePendingAsk.js +36 -4
- package/dist/hitl/localAllowRule.d.ts +1 -0
- package/dist/hitl/localAllowRule.js +2 -2
- package/dist/hitl/noAllowCause.d.ts +2 -1
- package/dist/hitl/noAllowCause.js +3 -2
- package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
- package/dist/hitl/parkExpiryJudgements.js +46 -0
- package/dist/hitl/parkResolver.d.ts +4 -7
- package/dist/hitl/parkResolver.js +12 -34
- package/dist/hitl/parkRowBirthWait.d.ts +1 -0
- package/dist/hitl/parkRowBirthWait.js +2 -2
- package/dist/hitl/persistedRulesWire.js +5 -1
- package/dist/hitl/planReviewWire.d.ts +3 -2
- package/dist/hitl/planReviewWire.js +154 -50
- package/dist/hitl/replayedApproval.d.ts +9 -0
- package/dist/hitl/replayedApproval.js +139 -10
- package/dist/hitl/resumeRunningCard.d.ts +2 -0
- package/dist/hitl/resumeRunningCard.js +15 -4
- package/dist/hitl/sessionPolicyDeliverable.js +8 -6
- package/dist/hitl/standingRows.d.ts +18 -0
- package/dist/hitl/standingRows.js +127 -0
- package/dist/hitl/toolApprovalWire.d.ts +39 -7
- package/dist/hitl/toolApprovalWire.js +351 -61
- package/dist/hookMatcherVerdict.d.ts +1 -9
- package/dist/hookMatcherVerdict.js +21 -61
- package/dist/hooksWireCaps.js +40 -8
- package/dist/host.d.ts +5 -0
- package/dist/host.js +3 -1
- package/dist/hostCallbackGuard.d.ts +2 -0
- package/dist/hostCallbackGuard.js +31 -0
- package/dist/index.d.ts +48 -17
- package/dist/index.js +36 -15
- package/dist/interactiveInterrupt.d.ts +8 -0
- package/dist/interactiveInterrupt.js +54 -0
- package/dist/limitsWire.d.ts +5 -0
- package/dist/limitsWire.js +49 -3
- package/dist/liveModelCatalog.d.ts +95 -0
- package/dist/liveModelCatalog.js +297 -32
- package/dist/mcpEngineLeg.d.ts +25 -0
- package/dist/mcpEngineLeg.js +71 -15
- package/dist/mcpPanel.js +2 -1
- package/dist/mcpProbeCapability.d.ts +0 -5
- package/dist/mcpProbeCapability.js +2 -12
- package/dist/mcpReconnect.d.ts +1 -3
- package/dist/mcpReconnect.js +10 -5
- package/dist/memoryComplianceCapability.d.ts +0 -5
- package/dist/memoryComplianceCapability.js +2 -12
- package/dist/memoryOriginCapability.d.ts +0 -5
- package/dist/memoryOriginCapability.js +2 -12
- package/dist/memorySpecWire.js +2 -2
- package/dist/memoryVerbsWire.d.ts +1 -1
- package/dist/memoryVerbsWire.js +4 -0
- package/dist/model/liveCatalogShape.d.ts +14 -0
- package/dist/model/liveCatalogShape.js +71 -0
- package/dist/model/modelSupplyRules.d.ts +1 -0
- package/dist/model/modelSupplyRules.js +30 -9
- package/dist/model/modelsPolicy.d.ts +21 -0
- package/dist/model/modelsPolicy.js +90 -0
- package/dist/modelIdentityResolvability.d.ts +2 -2
- package/dist/modelIdentityResolvability.js +14 -12
- package/dist/modelSwitchFallback.d.ts +69 -0
- package/dist/modelSwitchFallback.js +206 -0
- package/dist/noticePresentation.d.ts +68 -0
- package/dist/noticePresentation.js +247 -0
- package/dist/notifications.js +12 -11
- package/dist/outputStyleSeatCapability.d.ts +0 -2
- package/dist/outputStyleSeatCapability.js +2 -10
- package/dist/ownKey.d.ts +8 -0
- package/dist/ownKey.js +66 -0
- package/dist/panelReduce.d.ts +114 -0
- package/dist/panelReduce.js +1135 -0
- package/dist/panelStateHolder.d.ts +17 -0
- package/dist/panelStateHolder.js +201 -0
- package/dist/peerFrames.js +13 -9
- package/dist/peerLaneCapability.d.ts +0 -1
- package/dist/peerLaneCapability.js +2 -6
- package/dist/permissionModesCapability.d.ts +0 -5
- package/dist/permissionModesCapability.js +5 -16
- package/dist/permissionRuleIssue.js +0 -3
- package/dist/permissionRulesWriteCapability.d.ts +0 -1
- package/dist/permissionRulesWriteCapability.js +2 -6
- package/dist/permissionsAllowGrantCapability.d.ts +0 -1
- package/dist/permissionsAllowGrantCapability.js +3 -9
- package/dist/permissionsDeclaration.d.ts +8 -0
- package/dist/permissionsDeclaration.js +101 -41
- package/dist/printPermissionOutcome.d.ts +12 -0
- package/dist/printPermissionOutcome.js +50 -0
- package/dist/printToolResultFrame.d.ts +1 -0
- package/dist/printToolResultFrame.js +5 -17
- package/dist/promptBlockedCopy.d.ts +5 -0
- package/dist/promptBlockedCopy.js +35 -0
- package/dist/promptDelivery.js +0 -8
- package/dist/protocolSegment.d.ts +9 -6
- package/dist/protocolSegment.js +31 -21
- package/dist/providerRejection.d.ts +4 -0
- package/dist/providerRejection.js +75 -14
- package/dist/replayBody.d.ts +12 -0
- package/dist/replayBody.js +25 -0
- package/dist/resumeRefusalCopy.d.ts +18 -1
- package/dist/resumeRefusalCopy.js +127 -32
- package/dist/retryStatus.d.ts +9 -1
- package/dist/retryStatus.js +9 -2
- package/dist/rewindArchiveCapability.d.ts +5 -14
- package/dist/rewindArchiveCapability.js +18 -61
- package/dist/rewindArchiveReading.d.ts +15 -0
- package/dist/rewindArchiveReading.js +56 -0
- package/dist/rewindEngineAction.d.ts +21 -0
- package/dist/rewindEngineAction.js +36 -0
- package/dist/rewindWireCaps.d.ts +2 -1
- package/dist/rewindWireCaps.js +1 -0
- package/dist/ruleCompileVerdict.d.ts +9 -1
- package/dist/ruleCompileVerdict.js +29 -4
- package/dist/runTerminal.d.ts +15 -12
- package/dist/runTerminal.js +60 -35
- package/dist/sandboxWire.js +13 -0
- package/dist/sdkRegistryTransit.d.ts +2 -1
- package/dist/sdkRegistryTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +0 -5
- package/dist/sealedKeyCapability.js +3 -15
- package/dist/seam.js +4 -2
- package/dist/seatContract.d.ts +125 -34
- package/dist/seatContract.js +583 -179
- package/dist/sessionIdSegment.d.ts +1 -0
- package/dist/sessionIdSegment.js +11 -0
- package/dist/sessionMemoryErase.d.ts +1 -1
- package/dist/sessionMemoryErase.js +6 -1
- package/dist/sessionMemoryStatus.js +3 -2
- package/dist/sessionPolicyCapability.d.ts +0 -1
- package/dist/sessionPolicyCapability.js +2 -6
- package/dist/sessionReadRedactionCapability.d.ts +0 -5
- package/dist/sessionReadRedactionCapability.js +2 -13
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +66 -0
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -2
- package/dist/sessionSyncFileHistoryCapability.js +2 -9
- package/dist/skillToolListsCapability.d.ts +0 -2
- package/dist/skillToolListsCapability.js +2 -9
- package/dist/skillsWireCaps.d.ts +4 -0
- package/dist/skillsWireCaps.js +66 -1
- package/dist/sqlEngineCapability.d.ts +0 -1
- package/dist/sqlEngineCapability.js +9 -14
- package/dist/steerPriorityCapability.d.ts +0 -2
- package/dist/steerPriorityCapability.js +3 -12
- package/dist/storePostureCapability.d.ts +1 -5
- package/dist/storePostureCapability.js +16 -22
- package/dist/streamDrainingLegs.d.ts +6 -0
- package/dist/streamDrainingLegs.js +23 -0
- package/dist/subagent/engineCompactWire.js +13 -38
- package/dist/subagent/engineDelegatedPrompt.js +10 -6
- package/dist/subagent/engineSubagentOutput.d.ts +0 -1
- package/dist/subagent/engineSubagentOutput.js +5 -20
- package/dist/subagent/engineSubagentSteer.js +7 -5
- package/dist/subagent/engineSubagentTail.d.ts +0 -1
- package/dist/subagent/engineSubagentTail.js +7 -32
- package/dist/subagentContentStore.js +7 -18
- package/dist/supportFloor.d.ts +1 -0
- package/dist/supportFloor.js +15 -14
- package/dist/systemReminderTag.d.ts +1 -0
- package/dist/systemReminderTag.js +8 -0
- package/dist/terminalStatuses.d.ts +30 -0
- package/dist/terminalStatuses.js +67 -0
- package/dist/toolHistoryMismatch.d.ts +0 -3
- package/dist/toolHistoryMismatch.js +3 -7
- package/dist/toolResult.d.ts +6 -1
- package/dist/toolResult.js +90 -37
- package/dist/toolResultContent.d.ts +2 -0
- package/dist/toolResultContent.js +63 -0
- package/dist/types/engineState.d.ts +2 -1
- package/dist/usageAnalytics.d.ts +146 -0
- package/dist/usageAnalytics.js +335 -0
- package/dist/userInvokedSkillsCapability.d.ts +0 -2
- package/dist/userInvokedSkillsCapability.js +2 -9
- package/dist/webSearchBackendCapability.d.ts +0 -1
- package/dist/webSearchBackendCapability.js +3 -7
- package/dist/webSearchWireCaps.js +3 -11
- package/dist/wireErrorTriage.d.ts +2 -0
- package/dist/wireErrorTriage.js +34 -5
- package/dist/wireFailureShape.d.ts +23 -2
- package/dist/wireFailureShape.js +88 -43
- package/dist/wireRefusalCopy.js +2 -18
- package/dist/workflowClient.js +7 -11
- package/dist/workflowsJournalCapability.d.ts +0 -1
- package/dist/workflowsJournalCapability.js +2 -6
- package/dist/writeProtectionCapability.d.ts +0 -1
- package/dist/writeProtectionCapability.js +5 -10
- package/docs/INTEGRATION-CLIENTS.md +2279 -27
- package/package.json +5 -5
- package/dist/engineCapsGenerationGuard.d.ts +0 -4
- package/dist/engineCapsGenerationGuard.js +0 -19
- package/dist/panelRunningHistory.d.ts +0 -22
- package/dist/panelRunningHistory.js +0 -82
- package/dist/registryConflict.d.ts +0 -3
- package/dist/registryConflict.js +0 -44
package/dist/displayUntrusted.js
CHANGED
|
@@ -38,18 +38,12 @@ function scanForSecretLiteral(s) {
|
|
|
38
38
|
return true;
|
|
39
39
|
return s.split(/[^A-Za-z0-9_-]+/).some(tok => tok !== '' && SECRET_LITERAL_RE.test(tok));
|
|
40
40
|
}
|
|
41
|
-
function decodeAsciiEscapes(s) {
|
|
42
|
-
return s.replace(/%[0-9A-Fa-f]{2}/g, esc => {
|
|
43
|
-
const code = Number.parseInt(esc.slice(1), 16);
|
|
44
|
-
return code < 0x80 ? String.fromCharCode(code) : esc;
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
41
|
export function looksLikeKnownSecret(s) {
|
|
48
42
|
let cur = s;
|
|
49
43
|
for (let layer = 0; layer < 4; layer++) {
|
|
50
44
|
if (scanForSecretLiteral(cur))
|
|
51
45
|
return true;
|
|
52
|
-
const next =
|
|
46
|
+
const next = percentDecodeForMatching(cur).decoded;
|
|
53
47
|
if (next === cur)
|
|
54
48
|
break;
|
|
55
49
|
cur = next;
|
|
@@ -103,8 +97,8 @@ function valueIsWholeMarker(S, start, end, tokenInner = true) {
|
|
|
103
97
|
return j >= end || !isKeyWordChar(text.charCodeAt(j)) || credentialWordStartsExactlyAt(text, j, tokenInner) || credentialPairAt(S, j);
|
|
104
98
|
}
|
|
105
99
|
const CREDENTIAL_NAME = /(?:(?:access|refresh|id|client|api|x[-_]api|session|auth)[-_]?)?(?:token|key|secret|password|authorization|credential)s?|bearer|basic/iy;
|
|
106
|
-
const LABEL_SEPARATOR = /(?:\\*["'])?[\s\u115F\u1160\u3164\uFFA0\u2800]*[:=\uFF1A\uFF1D]/y;
|
|
107
|
-
const SCHEME_SEPARATOR = /[\s:=\uFF1A\uFF1D\u115F\u1160\u3164\uFFA0\u2800]/y;
|
|
100
|
+
const LABEL_SEPARATOR = /(?:\\*["'])?(?:[\s\u115F\u1160\u3164\uFFA0\u2800]|\\t)*[:=\uFF1A\uFF1D]/y;
|
|
101
|
+
const SCHEME_SEPARATOR = /(?:[\s:=\uFF1A\uFF1D\u115F\u1160\u3164\uFFA0\u2800]|\\t)/y;
|
|
108
102
|
function credentialPairAt(S, at) {
|
|
109
103
|
const text = S.text;
|
|
110
104
|
const re = new RegExp(CREDENTIAL_NAME.source, 'iy');
|
|
@@ -261,21 +255,23 @@ function isKnownSecretSegment(value) {
|
|
|
261
255
|
const core = valueCoreForJudging(value);
|
|
262
256
|
return core.length > 0 && looksLikeKnownSecret(core);
|
|
263
257
|
}
|
|
264
|
-
function queryCandidates(src, base, query, edits, soft) {
|
|
258
|
+
function queryCandidates(src, base, query, edits, soft, byShape = false) {
|
|
259
|
+
const relax = byShape === 'relaxed';
|
|
265
260
|
let pos = base;
|
|
266
261
|
for (const part of query.split('&')) {
|
|
267
262
|
if (part.length > 0) {
|
|
268
263
|
const eq = part.indexOf('=');
|
|
269
264
|
if (eq === -1) {
|
|
270
265
|
const at = pos;
|
|
271
|
-
if (!slotIsWholeMarker(part, soft && ((i) => soft(at + i))))
|
|
266
|
+
if (!slotIsWholeMarker(part, soft && ((i) => soft(at + i))) && (!byShape || queryPartCarriesCredential(null, part, relax)))
|
|
272
267
|
pushEdit(edits, src, pos, pos + part.length, REDACTED_QUERY);
|
|
273
268
|
}
|
|
274
269
|
else {
|
|
275
270
|
const value = part.slice(eq + 1);
|
|
276
271
|
const at = pos + eq + 1;
|
|
277
|
-
if (value.length > 0 && !slotIsWholeMarker(value, soft && ((i) => soft(at + i))))
|
|
272
|
+
if (value.length > 0 && !slotIsWholeMarker(value, soft && ((i) => soft(at + i))) && (!byShape || queryPartCarriesCredential(part.slice(0, eq), value, relax))) {
|
|
278
273
|
pushEdit(edits, src, pos + eq + 1, pos + part.length, REDACTED_QUERY);
|
|
274
|
+
}
|
|
279
275
|
}
|
|
280
276
|
}
|
|
281
277
|
pos += part.length + 1;
|
|
@@ -286,15 +282,22 @@ function pathCandidates(src, base, path, opaqueSegments, edits, soft) {
|
|
|
286
282
|
for (const segment of path.split('/')) {
|
|
287
283
|
const semi = segment.indexOf(';');
|
|
288
284
|
const head = semi === -1 ? segment : segment.slice(0, semi);
|
|
289
|
-
if (opaqueSegments
|
|
285
|
+
if (opaqueSegments) {
|
|
290
286
|
let a = 0;
|
|
291
287
|
let b = head.length;
|
|
292
288
|
while (a < b && !isKeyWordChar(head.charCodeAt(a)))
|
|
293
289
|
a++;
|
|
294
290
|
while (b > a && !isKeyWordChar(head.charCodeAt(b - 1)))
|
|
295
291
|
b--;
|
|
296
|
-
if (
|
|
297
|
-
|
|
292
|
+
if (isKnownSecretSegment(head)) {
|
|
293
|
+
if (b > a)
|
|
294
|
+
pushEdit(edits, src, pos + a, pos + b, REDACTED_SECRET);
|
|
295
|
+
}
|
|
296
|
+
else if (b > a) {
|
|
297
|
+
const glued = gluedLiteralStart(head.slice(a, b));
|
|
298
|
+
if (glued > 0)
|
|
299
|
+
pushEdit(edits, src, pos + a + glued, pos + b, REDACTED_SECRET);
|
|
300
|
+
}
|
|
298
301
|
}
|
|
299
302
|
if (semi !== -1) {
|
|
300
303
|
let ppos = pos + semi + 1;
|
|
@@ -312,7 +315,7 @@ function pathCandidates(src, base, path, opaqueSegments, edits, soft) {
|
|
|
312
315
|
pos += segment.length + 1;
|
|
313
316
|
}
|
|
314
317
|
}
|
|
315
|
-
function urlTokenCandidatesAt(src, start, end, edits, soft) {
|
|
318
|
+
function urlTokenCandidatesAt(src, start, end, edits, soft, byShape = false) {
|
|
316
319
|
const token = src.slice(start, end);
|
|
317
320
|
const schemeEnd = token.indexOf('://') + '://'.length;
|
|
318
321
|
const scheme = token.slice(0, schemeEnd);
|
|
@@ -330,7 +333,7 @@ function urlTokenCandidatesAt(src, start, end, edits, soft) {
|
|
|
330
333
|
const path = question === -1 ? beforeHash : beforeHash.slice(0, question);
|
|
331
334
|
pathCandidates(src, start + tailStart, path, !/^file:/i.test(scheme), edits, soft);
|
|
332
335
|
if (question !== -1)
|
|
333
|
-
queryCandidates(src, start + tailStart + question + 1, beforeHash.slice(question + 1), edits, soft);
|
|
336
|
+
queryCandidates(src, start + tailStart + question + 1, beforeHash.slice(question + 1), edits, soft, byShape);
|
|
334
337
|
if (hash !== -1) {
|
|
335
338
|
const rawFragment = tail.slice(hash + 1);
|
|
336
339
|
const at = start + tailStart + hash + 1;
|
|
@@ -338,7 +341,7 @@ function urlTokenCandidatesAt(src, start, end, edits, soft) {
|
|
|
338
341
|
pushEdit(edits, src, start + tailStart + hash + 1, end, REDACTED_FRAGMENT);
|
|
339
342
|
}
|
|
340
343
|
}
|
|
341
|
-
function urlCandidates(text, out, regions, unitPos = () => false, soft) {
|
|
344
|
+
function urlCandidates(text, out, regions, unitPos = () => false, soft, byShape = false) {
|
|
342
345
|
let mark = text.indexOf('://');
|
|
343
346
|
while (mark !== -1) {
|
|
344
347
|
let start = mark;
|
|
@@ -401,8 +404,9 @@ function urlCandidates(text, out, regions, unitPos = () => false, soft) {
|
|
|
401
404
|
runStart--;
|
|
402
405
|
if (runStart < end && !VALUE_BOUNDARY_TAIL.test(text.slice(start, runStart)))
|
|
403
406
|
end = runStart;
|
|
407
|
+
end = trailingCloserEnd(text, start, mark + 3, end, unitPos);
|
|
404
408
|
const tokenEdits = [];
|
|
405
|
-
urlTokenCandidatesAt(text, start, end, tokenEdits, soft);
|
|
409
|
+
urlTokenCandidatesAt(text, start, end, tokenEdits, soft, byShape);
|
|
406
410
|
editsToCandidates(tokenEdits, 'url', out, end);
|
|
407
411
|
const token = text.slice(start, end);
|
|
408
412
|
const schemeEnd = token.indexOf('://') + 3;
|
|
@@ -420,6 +424,47 @@ function urlCandidates(text, out, regions, unitPos = () => false, soft) {
|
|
|
420
424
|
mark = text.indexOf('://', end > mark + 3 ? end : mark + 3);
|
|
421
425
|
}
|
|
422
426
|
}
|
|
427
|
+
function trailingCloserEnd(text, start, floor, end, unitPos) {
|
|
428
|
+
const opens = new Map();
|
|
429
|
+
const closes = new Map();
|
|
430
|
+
for (const [o, c] of BRACKET_PAIRS) {
|
|
431
|
+
opens.set(o, 0);
|
|
432
|
+
closes.set(c, 0);
|
|
433
|
+
}
|
|
434
|
+
for (let k = start; k < end; k++) {
|
|
435
|
+
if (unitPos(k))
|
|
436
|
+
continue;
|
|
437
|
+
const ch = text.charAt(k);
|
|
438
|
+
const o = opens.get(ch);
|
|
439
|
+
if (o !== undefined)
|
|
440
|
+
opens.set(ch, o + 1);
|
|
441
|
+
const c = closes.get(ch);
|
|
442
|
+
if (c !== undefined)
|
|
443
|
+
closes.set(ch, c + 1);
|
|
444
|
+
}
|
|
445
|
+
let e = end;
|
|
446
|
+
for (;;) {
|
|
447
|
+
if (e <= floor || unitPos(e - 1))
|
|
448
|
+
return e;
|
|
449
|
+
const ch = text.charAt(e - 1);
|
|
450
|
+
const c = closes.get(ch);
|
|
451
|
+
if (c === undefined)
|
|
452
|
+
return e;
|
|
453
|
+
let open = '';
|
|
454
|
+
for (const [o, cl] of BRACKET_PAIRS)
|
|
455
|
+
if (cl === ch)
|
|
456
|
+
open = o;
|
|
457
|
+
if (c <= (opens.get(open) ?? 0))
|
|
458
|
+
return e;
|
|
459
|
+
closes.set(ch, c - 1);
|
|
460
|
+
e--;
|
|
461
|
+
let runStart = e;
|
|
462
|
+
while (runStart > floor && TRAILING_PUNCTUATION.has(text.charAt(runStart - 1)))
|
|
463
|
+
runStart--;
|
|
464
|
+
if (runStart < e && !VALUE_BOUNDARY_TAIL.test(text.slice(start, runStart)))
|
|
465
|
+
e = runStart;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
423
468
|
function atInAuthority(text, from) {
|
|
424
469
|
for (let p = from; p < text.length; p++) {
|
|
425
470
|
const ch = text.charAt(p);
|
|
@@ -763,9 +808,17 @@ const NAME_BLANK_RANGES = [
|
|
|
763
808
|
const isNameBlank = (cp) => NAME_BLANK_RANGES.some(([a, b]) => cp >= a && cp <= b);
|
|
764
809
|
const isFoldedBlank = (c) => isNameBlank(c) && isRegexSpace(c);
|
|
765
810
|
const isUnicodeBlank = (c) => (c > 0x7f && isRegexSpace(c) && c !== 0xfeff) || isNameBlank(c);
|
|
766
|
-
const SECRET_SCHEME_WORD = /(?:\b|(?<=\\[A-Za-z"']))(bearer|basic|token)[\s:=\uFF1A\uFF1D\u115F\u1160\u3164\uFFA0\u2800]+/gi;
|
|
811
|
+
const SECRET_SCHEME_WORD = /(?:\b|(?<=\\[A-Za-z"']))(?!(?<=(?<!\\)\\)(?:bearer|basic|token)\\t)(bearer|basic|token)(?:[\s:=\uFF1A\uFF1D\u115F\u1160\u3164\uFFA0\u2800]|\\t)+/gi;
|
|
812
|
+
const SCHEME_LEFT_STRICT = String.raw `(?:\b|(?<=\\[A-Za-z"']))`;
|
|
813
|
+
const SCHEME_WORD_OUTER_SOURCE = widenLeft(SECRET_SCHEME_WORD.source, SCHEME_LEFT_STRICT, String.raw `(?=bearer|basic)`);
|
|
767
814
|
const schemeWordIsInner = (word, tokenInner) => tokenInner || word.toLowerCase() !== 'token';
|
|
768
|
-
const SECRET_LABELLED_WORD = /(?:\b|(?<=_)|(?<=\\[A-Za-z"']))((?:access[-_ ]?|refresh[-_ ]?|id[-_ ]?|client[-_ ]?|api[-_ ]?|x[-_]api[-_ ]?|session[-_ ]?|auth[-_ ]?)?(?:token|key|secret|password|authorization|credential)s?)(?:\\*["'])?[\s\u115F\u1160\u3164\uFFA0\u2800]*[:=\uFF1A\uFF1D][\s\u115F\u1160\u3164\uFFA0\u2800]*/gi;
|
|
815
|
+
const SECRET_LABELLED_WORD = /(?:\b|(?<=_)|(?<=\\[A-Za-z"']))((?:access[-_ ]?|refresh[-_ ]?|id[-_ ]?|client[-_ ]?|api[-_ ]?|x[-_]api[-_ ]?|session[-_ ]?|auth[-_ ]?)?(?:token|key|secret|password|authorization|credential)s?)(?:\\*["'])?(?:[\s\u115F\u1160\u3164\uFFA0\u2800]|\\t)*[:=\uFF1A\uFF1D](?:[\s\u115F\u1160\u3164\uFFA0\u2800]|\\t)*/gi;
|
|
816
|
+
function widenLeft(source, strictLeft, extraAlt) {
|
|
817
|
+
return source.startsWith(strictLeft) ? `${strictLeft.slice(0, -1)}|${extraAlt})${source.slice(strictLeft.length)}` : source;
|
|
818
|
+
}
|
|
819
|
+
const LABEL_LEFT_STRICT = String.raw `(?:\b|(?<=_)|(?<=\\[A-Za-z"']))`;
|
|
820
|
+
const LABEL_LEFT_GLUED_ALT = String.raw `(?<=[A-Za-z0-9])(?:(?=(?:token|secret|password|authorization|credential)(?!s))|(?<!mon|tur|don|hoc|whis|joc|lac)(?=key(?!s)))`;
|
|
821
|
+
const LABEL_WORD_OUTER_SOURCE = widenLeft(SECRET_LABELLED_WORD.source, LABEL_LEFT_STRICT, LABEL_LEFT_GLUED_ALT);
|
|
769
822
|
const DIAGNOSTIC_VALUE_WORDS = new Set([
|
|
770
823
|
'missing', 'required', 'invalid', 'expired', 'unauthorized', 'unauthenticated', 'authentication',
|
|
771
824
|
'authorization', 'credential', 'credentials', 'unsupported', 'malformed', 'rejected', 'absent',
|
|
@@ -820,18 +873,67 @@ const AUTH_SCHEME_WORDS = new Set([
|
|
|
820
873
|
const AUTH_SIGNATURE_SCHEME = /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+){2,}$/;
|
|
821
874
|
const BARE_VALUE_STOP_CHARS = new Set([',', ';', '"', "'", '\\', '(', ')', '[', ']', '{', '}', '<', '>']);
|
|
822
875
|
const isBareValueStop = (ch) => ch <= ' ' || BARE_VALUE_STOP_CHARS.has(ch);
|
|
876
|
+
function isPlainAt(S, rawUnit, k) {
|
|
877
|
+
if (S.dropped(k) || S.painted(k) || S.unitAt(k) !== UNIT_NONE)
|
|
878
|
+
return false;
|
|
879
|
+
return rawUnit === null || rawUnit[S.rawStart(k)] !== 1;
|
|
880
|
+
}
|
|
881
|
+
function codeSpanClose(text, plain) {
|
|
882
|
+
const n = text.length;
|
|
883
|
+
const close = new Int32Array(n + 1).fill(-1);
|
|
884
|
+
let openLen = 0;
|
|
885
|
+
let spanFrom = -1;
|
|
886
|
+
let k = 0;
|
|
887
|
+
while (k < n) {
|
|
888
|
+
const c = text.charCodeAt(k);
|
|
889
|
+
if (c === 0x0a || c === 0x0d || c === 0x2028 || c === 0x2029) {
|
|
890
|
+
openLen = 0;
|
|
891
|
+
spanFrom = -1;
|
|
892
|
+
k++;
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
if (c !== 0x60 || !plain(k)) {
|
|
896
|
+
k++;
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
let e = k;
|
|
900
|
+
while (e < n && text.charCodeAt(e) === 0x60 && plain(e))
|
|
901
|
+
e++;
|
|
902
|
+
const len = e - k;
|
|
903
|
+
if (openLen === 0) {
|
|
904
|
+
openLen = len;
|
|
905
|
+
spanFrom = e;
|
|
906
|
+
}
|
|
907
|
+
else if (len === openLen) {
|
|
908
|
+
for (let x = spanFrom; x < k; x++)
|
|
909
|
+
close[x] = k;
|
|
910
|
+
openLen = 0;
|
|
911
|
+
spanFrom = -1;
|
|
912
|
+
}
|
|
913
|
+
k = e;
|
|
914
|
+
}
|
|
915
|
+
return close;
|
|
916
|
+
}
|
|
917
|
+
const BRACKET_PAIRS = new Map([['(', ')'], ['[', ']']]);
|
|
823
918
|
class InnerWordIndex {
|
|
824
919
|
text;
|
|
825
920
|
tokenInner;
|
|
826
921
|
probes;
|
|
827
|
-
|
|
922
|
+
plain;
|
|
923
|
+
spanClose = null;
|
|
924
|
+
constructor(text, tokenInner = true, plain = () => true) {
|
|
828
925
|
this.text = text;
|
|
829
926
|
this.tokenInner = tokenInner;
|
|
927
|
+
this.plain = plain;
|
|
830
928
|
this.probes = [
|
|
831
929
|
{ re: new RegExp(SECRET_LABELLED_WORD.source, SECRET_LABELLED_WORD.flags), scheme: false, from: -1, hit: null },
|
|
832
930
|
{ re: new RegExp(SECRET_SCHEME_WORD.source, SECRET_SCHEME_WORD.flags), scheme: true, from: -1, hit: null },
|
|
833
931
|
];
|
|
834
932
|
}
|
|
933
|
+
closingTickFrom(i) {
|
|
934
|
+
this.spanClose ??= codeSpanClose(this.text, this.plain);
|
|
935
|
+
return this.spanClose[i] ?? -1;
|
|
936
|
+
}
|
|
835
937
|
next(q) {
|
|
836
938
|
let best = null;
|
|
837
939
|
for (const p of this.probes) {
|
|
@@ -857,6 +959,45 @@ class InnerWordIndex {
|
|
|
857
959
|
return best;
|
|
858
960
|
}
|
|
859
961
|
}
|
|
962
|
+
const WRAPPED_PLACEHOLDER = /^(?:[A-Z]{1,12}(?:_[A-Z]{1,12})*|[a-z]{1,12}(?:-[a-z]{1,12})*)$/;
|
|
963
|
+
function wrappedValueAt(text, from, idx) {
|
|
964
|
+
let k = from;
|
|
965
|
+
while (k < text.length && text[k] === VIEW_SEPARATOR)
|
|
966
|
+
k++;
|
|
967
|
+
const close = BRACKET_PAIRS.get(text.charAt(k));
|
|
968
|
+
if (close === undefined || credentialWordStartsAt(text, k + 1, idx.tokenInner))
|
|
969
|
+
return null;
|
|
970
|
+
const inner = scanSecretValue(text, k + 1, idx);
|
|
971
|
+
if (inner === null || inner.start !== k + 1)
|
|
972
|
+
return null;
|
|
973
|
+
let c = inner.end;
|
|
974
|
+
while (c < text.length && text[c] === VIEW_SEPARATOR)
|
|
975
|
+
c++;
|
|
976
|
+
if (text.charAt(c) !== close || (close === ']' && text.charAt(c + 1) === '('))
|
|
977
|
+
return null;
|
|
978
|
+
return inner;
|
|
979
|
+
}
|
|
980
|
+
function tokenSchemeValueEnd(text, start, end, idx) {
|
|
981
|
+
if (withoutSeparators(text.slice(start, end)).toLowerCase() !== 'token')
|
|
982
|
+
return -1;
|
|
983
|
+
const re = new RegExp(SECRET_SCHEME_WORD.source, 'iy');
|
|
984
|
+
re.lastIndex = start;
|
|
985
|
+
const m = re.exec(text);
|
|
986
|
+
if (m === null || (m[1] ?? '').toLowerCase() !== 'token')
|
|
987
|
+
return -1;
|
|
988
|
+
const sepEnd = start + m[0].length;
|
|
989
|
+
if (/[\n\r\u2028\u2029:=\uFF1A\uFF1D]/.test(text.slice(start + (m[1] ?? '').length, sepEnd)))
|
|
990
|
+
return -1;
|
|
991
|
+
if (credentialWordStartsAt(text, sepEnd, idx.tokenInner))
|
|
992
|
+
return -1;
|
|
993
|
+
const iv = scanSecretValue(text, sepEnd, idx);
|
|
994
|
+
if (iv === null)
|
|
995
|
+
return -1;
|
|
996
|
+
const inner = withoutSeparators(text.slice(iv.start, iv.end));
|
|
997
|
+
if (schemeFollowerReleased('token', inner, false) || isDiagnosticWord(inner))
|
|
998
|
+
return -1;
|
|
999
|
+
return iv.end;
|
|
1000
|
+
}
|
|
860
1001
|
function innerWordFits(text, w) {
|
|
861
1002
|
for (let k = w.start; k <= w.sepAt && k < text.length; k++)
|
|
862
1003
|
if (isBareValueStop(text.charAt(k)))
|
|
@@ -912,6 +1053,7 @@ function scanSecretValue(text, from, idx) {
|
|
|
912
1053
|
let pending = cuttable ? idx.next(i + 1) : null;
|
|
913
1054
|
let cut = false;
|
|
914
1055
|
let j = i;
|
|
1056
|
+
const closingTick = idx === undefined ? -1 : idx.closingTickFrom(i);
|
|
915
1057
|
while (j < text.length) {
|
|
916
1058
|
if (pending !== null && j >= pending.start) {
|
|
917
1059
|
if (j === pending.start && innerWordFits(text, pending)) {
|
|
@@ -936,6 +1078,18 @@ function scanSecretValue(text, from, idx) {
|
|
|
936
1078
|
}
|
|
937
1079
|
while (j > i && text[j - 1] === VIEW_SEPARATOR)
|
|
938
1080
|
j--;
|
|
1081
|
+
if (closingTick > i && closingTick < j) {
|
|
1082
|
+
let t = closingTick;
|
|
1083
|
+
while (t < j && text.charCodeAt(t) === 0x60)
|
|
1084
|
+
t++;
|
|
1085
|
+
while (t < j && TRAILING_PUNCTUATION.has(text.charAt(t)))
|
|
1086
|
+
t++;
|
|
1087
|
+
if (t === j && text.charCodeAt(closingTick) === 0x60) {
|
|
1088
|
+
j = closingTick;
|
|
1089
|
+
while (j > i && text[j - 1] === VIEW_SEPARATOR)
|
|
1090
|
+
j--;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
939
1093
|
if (cut) {
|
|
940
1094
|
while (j > i && isCutDelimiter(text.charAt(j - 1))) {
|
|
941
1095
|
j--;
|
|
@@ -955,6 +1109,9 @@ function isDiagnosticValue(value, raw = value) {
|
|
|
955
1109
|
return true;
|
|
956
1110
|
if (ADDRESS_SCHEME_RE.test(raw))
|
|
957
1111
|
return true;
|
|
1112
|
+
return isDiagnosticWord(value);
|
|
1113
|
+
}
|
|
1114
|
+
function isDiagnosticWord(value) {
|
|
958
1115
|
const bare = value.replace(/^\.+/, '').replace(/[.,;:!?)\]}'"]{0,8}$/, '').toLowerCase();
|
|
959
1116
|
return bare === '' || DIAGNOSTIC_VALUE_WORDS.has(bare);
|
|
960
1117
|
}
|
|
@@ -1014,6 +1171,26 @@ function isNamedNotValue(label, value) {
|
|
|
1014
1171
|
return true;
|
|
1015
1172
|
return isBacktickedCredentialName(value);
|
|
1016
1173
|
}
|
|
1174
|
+
function schemeIsLabelValue(text, at) {
|
|
1175
|
+
let k = at;
|
|
1176
|
+
while (k > 0 && text[k - 1] === VIEW_SEPARATOR)
|
|
1177
|
+
k--;
|
|
1178
|
+
if (k > 0 && isQuoteChar(text.charAt(k - 1))) {
|
|
1179
|
+
k--;
|
|
1180
|
+
while (k > 0 && text.charCodeAt(k - 1) === 0x5c)
|
|
1181
|
+
k--;
|
|
1182
|
+
}
|
|
1183
|
+
return k > 0 && labelEndsAt(text, k);
|
|
1184
|
+
}
|
|
1185
|
+
function labelQuotedAt(text, at, sep) {
|
|
1186
|
+
const q = text.charAt(at - 1);
|
|
1187
|
+
if (!isQuoteChar(q))
|
|
1188
|
+
return false;
|
|
1189
|
+
let k = 0;
|
|
1190
|
+
while (sep.charCodeAt(k) === 0x5c)
|
|
1191
|
+
k++;
|
|
1192
|
+
return sep.charAt(k) === q;
|
|
1193
|
+
}
|
|
1017
1194
|
function labelStartsAt(text, at) {
|
|
1018
1195
|
const re = new RegExp(SECRET_LABELLED_WORD.source, 'iy');
|
|
1019
1196
|
re.lastIndex = at;
|
|
@@ -1093,6 +1270,35 @@ function percentDecodeForMatching(text) {
|
|
|
1093
1270
|
offsets.push(text.length);
|
|
1094
1271
|
return { decoded: chars.join(''), offsets };
|
|
1095
1272
|
}
|
|
1273
|
+
const PERCENT_ESCAPE_ASCII = /%[0-7][0-9A-Fa-f]/;
|
|
1274
|
+
const MAX_PERCENT_VIEW_LAYERS = 3;
|
|
1275
|
+
function percentLayers(text) {
|
|
1276
|
+
const out = [];
|
|
1277
|
+
if (!PERCENT_ESCAPE_ASCII.test(text))
|
|
1278
|
+
return out;
|
|
1279
|
+
let cur = text;
|
|
1280
|
+
let ps = null;
|
|
1281
|
+
let pe = null;
|
|
1282
|
+
for (let layer = 0; layer < MAX_PERCENT_VIEW_LAYERS; layer++) {
|
|
1283
|
+
const { decoded, offsets } = percentDecodeForMatching(cur);
|
|
1284
|
+
if (decoded === cur)
|
|
1285
|
+
break;
|
|
1286
|
+
const n = decoded.length;
|
|
1287
|
+
const nps = new Int32Array(n);
|
|
1288
|
+
const npe = new Int32Array(n);
|
|
1289
|
+
for (let k = 0; k < n; k++) {
|
|
1290
|
+
const a = offsets[k] ?? 0;
|
|
1291
|
+
const b = offsets[k + 1] ?? cur.length;
|
|
1292
|
+
nps[k] = ps === null ? a : (ps[a] ?? 0);
|
|
1293
|
+
npe[k] = pe === null ? b : (pe[b - 1] ?? 0);
|
|
1294
|
+
}
|
|
1295
|
+
out.push({ text: decoded, ps: nps, pe: npe });
|
|
1296
|
+
cur = decoded;
|
|
1297
|
+
ps = nps;
|
|
1298
|
+
pe = npe;
|
|
1299
|
+
}
|
|
1300
|
+
return out;
|
|
1301
|
+
}
|
|
1096
1302
|
function firstLabelCutInPath(path) {
|
|
1097
1303
|
let cut = -1;
|
|
1098
1304
|
for (const src of [SECRET_SCHEME_WORD, SECRET_LABELLED_WORD]) {
|
|
@@ -1347,7 +1553,7 @@ function quoteSwallowedBefore(S, at) {
|
|
|
1347
1553
|
return '';
|
|
1348
1554
|
return dq === -1 ? "'" : sq === -1 ? '"' : dq < sq ? '"' : "'";
|
|
1349
1555
|
}
|
|
1350
|
-
function labelEndsAt(text, end, atLeast = false) {
|
|
1556
|
+
function labelEndsAt(text, end, atLeast = false, outer = false) {
|
|
1351
1557
|
let k = end;
|
|
1352
1558
|
while (k > 0 && isRegexSpace(text.charCodeAt(k - 1)))
|
|
1353
1559
|
k--;
|
|
@@ -1366,7 +1572,7 @@ function labelEndsAt(text, end, atLeast = false) {
|
|
|
1366
1572
|
let w = k;
|
|
1367
1573
|
while (w > 0 && isIdentOrDash(text.charAt(w - 1)))
|
|
1368
1574
|
w--;
|
|
1369
|
-
const re = new RegExp(SECRET_LABELLED_WORD.source, 'iy');
|
|
1575
|
+
const re = new RegExp(outer ? LABEL_WORD_OUTER_SOURCE : SECRET_LABELLED_WORD.source, 'iy');
|
|
1370
1576
|
for (let s = w; s < k; s++) {
|
|
1371
1577
|
re.lastIndex = s;
|
|
1372
1578
|
const m = re.exec(text);
|
|
@@ -1924,15 +2130,19 @@ function blockSeqEntries(scan, rawFrom, rawLabel) {
|
|
|
1924
2130
|
}
|
|
1925
2131
|
return out;
|
|
1926
2132
|
}
|
|
1927
|
-
function labelCandidates(S, pass, regions, out, blocks) {
|
|
2133
|
+
function labelCandidates(S, pass, regions, out, blocks, outer = false) {
|
|
1928
2134
|
const text = S.text;
|
|
1929
2135
|
const unitAt = (k) => S.unitAt(k);
|
|
1930
|
-
const
|
|
2136
|
+
const strictSource = pass === 'label' ? SECRET_LABELLED_WORD.source : SECRET_SCHEME_WORD.source;
|
|
2137
|
+
const re = new RegExp(outer ? (pass === 'label' ? LABEL_WORD_OUTER_SOURCE : SCHEME_WORD_OUTER_SOURCE) : strictSource, 'gi');
|
|
2138
|
+
const strictAt = outer ? new RegExp(strictSource, 'iy') : null;
|
|
1931
2139
|
const schemePass = pass !== 'label';
|
|
1932
2140
|
const tokenPass = pass === 'token';
|
|
1933
|
-
const
|
|
2141
|
+
const rawUnitMap = blocks?.view.rawUnit ?? null;
|
|
2142
|
+
const plainAt = (k) => isPlainAt(S, rawUnitMap, k);
|
|
2143
|
+
const idx = new InnerWordIndex(text, tokenPass, plainAt);
|
|
1934
2144
|
let listIdx = null;
|
|
1935
|
-
const listIndex = () => (listIdx ??= new InnerWordIndex(text, idx.tokenInner));
|
|
2145
|
+
const listIndex = () => (listIdx ??= new InnerWordIndex(text, idx.tokenInner, plainAt));
|
|
1936
2146
|
let skipFrom = -1;
|
|
1937
2147
|
let skipTo = -1;
|
|
1938
2148
|
const flowBudget = { left: 4 * text.length + 4096, pairs: null };
|
|
@@ -2171,6 +2381,11 @@ function labelCandidates(S, pass, regions, out, blocks) {
|
|
|
2171
2381
|
re.lastIndex = 0;
|
|
2172
2382
|
hits: for (let hit = re.exec(text); hit !== null; hit = re.exec(text)) {
|
|
2173
2383
|
const label = hit[1] ?? '';
|
|
2384
|
+
if (strictAt !== null) {
|
|
2385
|
+
strictAt.lastIndex = hit.index;
|
|
2386
|
+
if (strictAt.test(text))
|
|
2387
|
+
continue;
|
|
2388
|
+
}
|
|
2174
2389
|
if (hit.index >= skipFrom && hit.index < skipTo)
|
|
2175
2390
|
continue;
|
|
2176
2391
|
if (schemePass && (label.toLowerCase() === 'token') !== tokenPass)
|
|
@@ -2182,6 +2397,16 @@ function labelCandidates(S, pass, regions, out, blocks) {
|
|
|
2182
2397
|
if (schemePass && labelStartsAt(text, hit.index))
|
|
2183
2398
|
continue;
|
|
2184
2399
|
let from = hit.index + hit[0].length;
|
|
2400
|
+
if (!schemePass && text.charCodeAt(from) === 0x3e && text.charCodeAt(from - 1) === 0x3d && labelQuotedAt(text, hit.index, hit[0].slice(label.length))) {
|
|
2401
|
+
let k = from + 1;
|
|
2402
|
+
while (k < text.length && isInlineBlank(text.charAt(k)))
|
|
2403
|
+
k++;
|
|
2404
|
+
let q = k;
|
|
2405
|
+
while (text.charCodeAt(q) === 0x5c)
|
|
2406
|
+
q++;
|
|
2407
|
+
if (isQuoteChar(text.charAt(q)))
|
|
2408
|
+
from = k;
|
|
2409
|
+
}
|
|
2185
2410
|
const colonSep = isColonSeparator(hit[0].slice((hit[1] ?? '').length));
|
|
2186
2411
|
let bulletSkipped = false;
|
|
2187
2412
|
for (;;) {
|
|
@@ -2244,6 +2469,16 @@ function labelCandidates(S, pass, regions, out, blocks) {
|
|
|
2244
2469
|
}
|
|
2245
2470
|
}
|
|
2246
2471
|
let v0s = scanSecretValue(text, from, idx);
|
|
2472
|
+
let wrapEnd = -1;
|
|
2473
|
+
if (v0s === null) {
|
|
2474
|
+
const w = wrappedValueAt(text, from, idx);
|
|
2475
|
+
if (w !== null) {
|
|
2476
|
+
if (WRAPPED_PLACEHOLDER.test(withoutSeparators(text.slice(w.start, w.end))))
|
|
2477
|
+
continue;
|
|
2478
|
+
v0s = w;
|
|
2479
|
+
wrapEnd = w.end;
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2247
2482
|
if (v0s === null) {
|
|
2248
2483
|
let k = from;
|
|
2249
2484
|
while (k < text.length && text[k] === VIEW_SEPARATOR)
|
|
@@ -2340,6 +2575,13 @@ function labelCandidates(S, pass, regions, out, blocks) {
|
|
|
2340
2575
|
if (a !== -1)
|
|
2341
2576
|
v.end = a;
|
|
2342
2577
|
}
|
|
2578
|
+
if (wrapEnd !== -1 && v.end > wrapEnd)
|
|
2579
|
+
v.end = wrapEnd;
|
|
2580
|
+
if (!schemePass && !quoted && wrapEnd === -1 && !inQuery(v.start) && !/authorizations?$/i.test(label)) {
|
|
2581
|
+
const ext = tokenSchemeValueEnd(text, v.start, v.end, idx);
|
|
2582
|
+
if (ext > v.end)
|
|
2583
|
+
v.end = ext;
|
|
2584
|
+
}
|
|
2343
2585
|
if (!quoted) {
|
|
2344
2586
|
const trailing = trailingLabelStart(text, v.start, v.end, idx.tokenInner);
|
|
2345
2587
|
if (trailing > 0 && innerWordHasValue(text, v.start + trailing, idx)) {
|
|
@@ -2402,6 +2644,11 @@ function labelCandidates(S, pass, regions, out, blocks) {
|
|
|
2402
2644
|
const trailing = trailingLabelStart(text, v.start, end, idx.tokenInner);
|
|
2403
2645
|
if (trailing !== -1)
|
|
2404
2646
|
end = v.start + trailing;
|
|
2647
|
+
if (schemePass && schemeIsLabelValue(text, hit.index)) {
|
|
2648
|
+
push(v.start, Math.max(end, v.end), REDACTED_SECRET);
|
|
2649
|
+
re.lastIndex = quoted ? from : Math.max(end, v.end);
|
|
2650
|
+
continue;
|
|
2651
|
+
}
|
|
2405
2652
|
if (gluedToSingleUnit(v.start, hit.index, unitAt) || userinfoHostHidden(text, v.start, unitAt)) {
|
|
2406
2653
|
const cut = trailing !== -1 ? end : Math.max(end, v.end);
|
|
2407
2654
|
const schemeHit = ADDRESS_SCHEME_RE.exec(text.slice(v.start, v.start + 20))?.[0] ?? '';
|
|
@@ -2458,6 +2705,19 @@ function isAuthScheme(value) {
|
|
|
2458
2705
|
const isKeyWordChar = (c) => (c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) || c === 0x5f || c === 0x2d;
|
|
2459
2706
|
const isAlnumCode = (c) => (c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a);
|
|
2460
2707
|
const PROSE_LITERAL_MIN_RUN = 16;
|
|
2708
|
+
const PROSE_SHORT_LITERAL_MIN_TAIL = 6;
|
|
2709
|
+
function shortLiteralTail(word) {
|
|
2710
|
+
const lit = SECRET_LITERAL_RE.exec(word);
|
|
2711
|
+
if (lit === null)
|
|
2712
|
+
return false;
|
|
2713
|
+
const tail = word.slice(lit[0].length);
|
|
2714
|
+
if (tail.length < PROSE_SHORT_LITERAL_MIN_TAIL)
|
|
2715
|
+
return false;
|
|
2716
|
+
for (let k = 0; k < tail.length; k++)
|
|
2717
|
+
if (!isAlnumCode(tail.charCodeAt(k)))
|
|
2718
|
+
return false;
|
|
2719
|
+
return true;
|
|
2720
|
+
}
|
|
2461
2721
|
function longestAlnumRun(word) {
|
|
2462
2722
|
let best = 0;
|
|
2463
2723
|
let run = 0;
|
|
@@ -2799,8 +3059,112 @@ function authParamEdits(text) {
|
|
|
2799
3059
|
}
|
|
2800
3060
|
return edits;
|
|
2801
3061
|
}
|
|
3062
|
+
const LITERAL_PROBE_WINDOW = 64;
|
|
3063
|
+
function gluedLiteralStart(word) {
|
|
3064
|
+
const n = word.length;
|
|
3065
|
+
if (n < PROSE_SHORT_LITERAL_MIN_TAIL + 4)
|
|
3066
|
+
return 0;
|
|
3067
|
+
const runFrom = new Int32Array(n + 1);
|
|
3068
|
+
let best = 0;
|
|
3069
|
+
let run = 0;
|
|
3070
|
+
for (let k = n - 1; k >= 0; k--) {
|
|
3071
|
+
if (isAlnumCode(word.charCodeAt(k))) {
|
|
3072
|
+
run++;
|
|
3073
|
+
if (run > best)
|
|
3074
|
+
best = run;
|
|
3075
|
+
}
|
|
3076
|
+
else
|
|
3077
|
+
run = 0;
|
|
3078
|
+
runFrom[k] = best;
|
|
3079
|
+
}
|
|
3080
|
+
for (let k = 1; k < n; k++) {
|
|
3081
|
+
const left = word.charCodeAt(k - 1);
|
|
3082
|
+
if ((left !== 0x5f && left !== 0x2d) || !isAlnumCode(word.charCodeAt(k)))
|
|
3083
|
+
continue;
|
|
3084
|
+
const run = runFrom[k] ?? 0;
|
|
3085
|
+
if (run < PROSE_SHORT_LITERAL_MIN_TAIL)
|
|
3086
|
+
return 0;
|
|
3087
|
+
if (SECRET_LITERAL_RE.test(word.slice(k, k + LITERAL_PROBE_WINDOW)) && (run >= PROSE_LITERAL_MIN_RUN || shortLiteralTail(word.slice(k))))
|
|
3088
|
+
return k;
|
|
3089
|
+
}
|
|
3090
|
+
return 0;
|
|
3091
|
+
}
|
|
3092
|
+
const OPAQUE_MIN_LENGTH = 24;
|
|
3093
|
+
const OPAQUE_MIN_ENTROPY = 3.5;
|
|
3094
|
+
const OPAQUE_MAX_AVG_SEGMENT = 2.5;
|
|
3095
|
+
const BASE64_FILE_SIGNATURES = ['iVBORw0KGgo', 'R0lGOD', 'UklGR', 'JVBERi0', 'UEsDB', 'H4sI', 'PHN2Zy', 'PD94bWwg', 'AAABAA'];
|
|
3096
|
+
const NON_SECRET_ID_PREFIXES = new Set(['toolu', 'srvtoolu', 'msg', 'msgbatch', 'req', 'file', 'chatcmpl', 'call', 'resp']);
|
|
3097
|
+
function isOpaqueWord(text, i, end) {
|
|
3098
|
+
if (end - i < OPAQUE_MIN_LENGTH)
|
|
3099
|
+
return false;
|
|
3100
|
+
const prev = text.charAt(i - 1);
|
|
3101
|
+
const next = text.charAt(end);
|
|
3102
|
+
if (prev === '+' || prev === '@' || next === '+' || next === '/' || next === '=' || next === '@')
|
|
3103
|
+
return false;
|
|
3104
|
+
if (next === '.' && isKeyWordChar(text.charCodeAt(end + 1)))
|
|
3105
|
+
return false;
|
|
3106
|
+
if (text.slice(Math.max(0, i - 7), i).toLowerCase() === 'base64,')
|
|
3107
|
+
return false;
|
|
3108
|
+
const word = text.slice(i, end);
|
|
3109
|
+
if (/^[0-9A-Fa-f_-]+$/.test(word) || /^sha(?:1|256|384|512)-/i.test(word))
|
|
3110
|
+
return false;
|
|
3111
|
+
if (BASE64_FILE_SIGNATURES.some((sig) => word.startsWith(sig)))
|
|
3112
|
+
return false;
|
|
3113
|
+
const typed = /^([a-z]+)[_-]/.exec(word);
|
|
3114
|
+
if (typed !== null && NON_SECRET_ID_PREFIXES.has(typed[1] ?? ''))
|
|
3115
|
+
return false;
|
|
3116
|
+
let upper = false;
|
|
3117
|
+
let lower = false;
|
|
3118
|
+
let digit = false;
|
|
3119
|
+
const counts = new Map();
|
|
3120
|
+
for (let k = 0; k < word.length; k++) {
|
|
3121
|
+
const c = word.charCodeAt(k);
|
|
3122
|
+
if (c >= 0x41 && c <= 0x5a)
|
|
3123
|
+
upper = true;
|
|
3124
|
+
else if (c >= 0x61 && c <= 0x7a)
|
|
3125
|
+
lower = true;
|
|
3126
|
+
else if (c >= 0x30 && c <= 0x39)
|
|
3127
|
+
digit = true;
|
|
3128
|
+
counts.set(c, (counts.get(c) ?? 0) + 1);
|
|
3129
|
+
}
|
|
3130
|
+
if (!upper || !lower || !digit)
|
|
3131
|
+
return false;
|
|
3132
|
+
let entropy = 0;
|
|
3133
|
+
for (const n of counts.values()) {
|
|
3134
|
+
const p = n / word.length;
|
|
3135
|
+
entropy -= p * Math.log2(p);
|
|
3136
|
+
}
|
|
3137
|
+
if (entropy < OPAQUE_MIN_ENTROPY)
|
|
3138
|
+
return false;
|
|
3139
|
+
let segments = 0;
|
|
3140
|
+
let segmentChars = 0;
|
|
3141
|
+
for (const m of word.matchAll(/[A-Z]?[a-z]+|[A-Z]+(?![a-z])|[0-9]+/g)) {
|
|
3142
|
+
segments++;
|
|
3143
|
+
segmentChars += m[0].length;
|
|
3144
|
+
}
|
|
3145
|
+
return segments > 0 && segmentChars / segments <= OPAQUE_MAX_AVG_SEGMENT;
|
|
3146
|
+
}
|
|
3147
|
+
const FILE_URL_OPENERS = new Set(['(', '[', '<', "'", ',', ';']);
|
|
3148
|
+
function fileUrlPositions(text) {
|
|
3149
|
+
let marks = null;
|
|
3150
|
+
const re = /file:/gi;
|
|
3151
|
+
for (let hit = re.exec(text); hit !== null; hit = re.exec(text)) {
|
|
3152
|
+
const s = hit.index;
|
|
3153
|
+
if (s > 0 && !endsUrlFragmentAt(text, s - 1) && !FILE_URL_OPENERS.has(text.charAt(s - 1)))
|
|
3154
|
+
continue;
|
|
3155
|
+
let e = s + hit[0].length;
|
|
3156
|
+
while (e < text.length && !endsUrlFragmentAt(text, e))
|
|
3157
|
+
e++;
|
|
3158
|
+
marks ??= new Uint8Array(text.length);
|
|
3159
|
+
for (let k = s; k < e; k++)
|
|
3160
|
+
marks[k] = 1;
|
|
3161
|
+
re.lastIndex = e;
|
|
3162
|
+
}
|
|
3163
|
+
return marks;
|
|
3164
|
+
}
|
|
2802
3165
|
function proseLiteralEdits(text) {
|
|
2803
3166
|
const edits = [];
|
|
3167
|
+
let fileAt;
|
|
2804
3168
|
let i = 0;
|
|
2805
3169
|
while (i < text.length) {
|
|
2806
3170
|
const c = text.charCodeAt(i);
|
|
@@ -2811,6 +3175,7 @@ function proseLiteralEdits(text) {
|
|
|
2811
3175
|
let end = i;
|
|
2812
3176
|
while (end < text.length && isKeyWordChar(text.charCodeAt(end)))
|
|
2813
3177
|
end++;
|
|
3178
|
+
const escHead = i > 0 && text.charCodeAt(i - 1) === 0x25 && PERCENT_ESCAPE_ASCII.test(text.slice(i - 1, i + 2)) && i + 2 < end ? 2 : 0;
|
|
2814
3179
|
const word = text.slice(i, end);
|
|
2815
3180
|
if (word.startsWith('eyJ')) {
|
|
2816
3181
|
let segEnd = end;
|
|
@@ -2829,15 +3194,33 @@ function proseLiteralEdits(text) {
|
|
|
2829
3194
|
}
|
|
2830
3195
|
const prev = i > 0 ? text.charAt(i - 1) : '';
|
|
2831
3196
|
const hostSlot = prev === '/' && i > 1 && text.charAt(i - 2) === '/';
|
|
2832
|
-
const
|
|
2833
|
-
if (
|
|
2834
|
-
|
|
3197
|
+
const slashSegment = prev === '/' && !hostSlot;
|
|
3198
|
+
if (slashSegment && fileAt === undefined)
|
|
3199
|
+
fileAt = fileUrlPositions(text);
|
|
3200
|
+
const localPath = prev === '\\' || prev === '.' || (slashSegment && fileAt != null && fileAt[i] === 1);
|
|
3201
|
+
const pathish = slashSegment || localPath;
|
|
3202
|
+
if (!localPath && SECRET_LITERAL_RE.test(word) && (longestAlnumRun(word) >= PROSE_LITERAL_MIN_RUN || shortLiteralTail(word))) {
|
|
3203
|
+
pushEdit(edits, text, i + escHead, end, REDACTED_SECRET);
|
|
3204
|
+
}
|
|
3205
|
+
else if (!localPath) {
|
|
3206
|
+
const glued = gluedLiteralStart(word);
|
|
3207
|
+
if (glued > 0)
|
|
3208
|
+
pushEdit(edits, text, i + Math.max(glued, escHead), end, REDACTED_SECRET);
|
|
3209
|
+
else if (!pathish && !hostSlot && isOpaqueWord(text, i, end))
|
|
3210
|
+
pushEdit(edits, text, i + escHead, end, REDACTED_SECRET);
|
|
2835
3211
|
}
|
|
2836
3212
|
i = end;
|
|
2837
3213
|
}
|
|
2838
3214
|
return edits;
|
|
2839
3215
|
}
|
|
3216
|
+
const C0_ALL = '\\u0000-\\u001F';
|
|
3217
|
+
const C0_KEEP_LAYOUT = '\\u0000-\\u0008\\u000B-\\u001F';
|
|
3218
|
+
const DEL_C1 = '\\u007F-\\u009F';
|
|
3219
|
+
const LONE_SURROGATE = '\\uD800-\\uDFFF';
|
|
3220
|
+
const LINE_SEPARATORS = '\\u2028\\u2029';
|
|
2840
3221
|
const FORMAT_CHAR = /^\p{Cf}$/u;
|
|
3222
|
+
const FORMAT_CLASS = FORMAT_CHAR.source.slice(1, -1);
|
|
3223
|
+
const FACE_MARKED_CHAR = new RegExp(`^(?:[${C0_ALL}${DEL_C1}${LONE_SURROGATE}${LINE_SEPARATORS}]|${FORMAT_CLASS})$`, 'u');
|
|
2841
3224
|
const isStrippableControl = (c) => (c <= 0x1f && (c < 0x09 || c > 0x0d)) || (c >= 0x7f && c <= 0x9f);
|
|
2842
3225
|
class SequenceReader {
|
|
2843
3226
|
text;
|
|
@@ -2965,13 +3348,7 @@ function c1SequenceAfter(text, c1, at, seq) {
|
|
|
2965
3348
|
return null;
|
|
2966
3349
|
}
|
|
2967
3350
|
function isFaceMarkedCodePoint(cp) {
|
|
2968
|
-
|
|
2969
|
-
return true;
|
|
2970
|
-
if (cp >= 0xd800 && cp <= 0xdfff)
|
|
2971
|
-
return true;
|
|
2972
|
-
if (cp === 0x2028 || cp === 0x2029)
|
|
2973
|
-
return true;
|
|
2974
|
-
return cp >= 0xad && cp <= 0x10ffff && FORMAT_CHAR.test(String.fromCodePoint(cp));
|
|
3351
|
+
return cp >= 0 && cp <= 0x10ffff && FACE_MARKED_CHAR.test(String.fromCodePoint(cp));
|
|
2975
3352
|
}
|
|
2976
3353
|
function escapeTokenAt(text, at) {
|
|
2977
3354
|
const four = /^\\u([0-9A-Fa-f]{4})/.exec(text.slice(at, at + 6));
|
|
@@ -3287,8 +3664,39 @@ function screenSurfaces(text, o) {
|
|
|
3287
3664
|
if (joinedSpaced !== null)
|
|
3288
3665
|
out.push(joinedSpaced);
|
|
3289
3666
|
const contents = V.contents.map(([a, b]) => ({ sub: screen.slice(a, b), rawAt: (k) => M.ps[a + k] ?? 0, rawEndAt: (k) => M.pe[a + k] ?? 0 }));
|
|
3667
|
+
const decoded = percentSurfaces(text, screen, M, o);
|
|
3668
|
+
out.push(...decoded.surfaces);
|
|
3669
|
+
contents.push(...decoded.contents);
|
|
3290
3670
|
return { surfaces: out, rawSoft, rawPlain, contents };
|
|
3291
3671
|
}
|
|
3672
|
+
function percentSurfaces(raw, text, base, o) {
|
|
3673
|
+
const surfaces = [];
|
|
3674
|
+
const contents = [];
|
|
3675
|
+
for (const layer of percentLayers(text)) {
|
|
3676
|
+
const n = layer.text.length;
|
|
3677
|
+
const ps = new Int32Array(n);
|
|
3678
|
+
const pe = new Int32Array(n);
|
|
3679
|
+
const pdot = new Uint8Array(n);
|
|
3680
|
+
for (let k = 0; k < n; k++) {
|
|
3681
|
+
const a = layer.ps[k] ?? 0;
|
|
3682
|
+
const b = layer.pe[k] ?? 0;
|
|
3683
|
+
ps[k] = base === null ? a : (base.ps[a] ?? 0);
|
|
3684
|
+
pe[k] = base === null ? b : (base.pe[b - 1] ?? 0);
|
|
3685
|
+
if (base !== null && b - a === 1)
|
|
3686
|
+
pdot[k] = base.pdot[a] ?? 0;
|
|
3687
|
+
}
|
|
3688
|
+
const M = { ps, pe, pdot, rawDot: base === null ? new Uint8Array(raw.length) : base.rawDot };
|
|
3689
|
+
const VD = buildScanView(layer.text, o);
|
|
3690
|
+
const sep = separatedSurface(raw, VD, M);
|
|
3691
|
+
surfaces.push(base === null ? { ...sep, rawDot: null } : sep);
|
|
3692
|
+
const joined = joinedSurface(raw, VD, false, M);
|
|
3693
|
+
if (joined !== null)
|
|
3694
|
+
surfaces.push(base === null ? { ...joined, rawDot: null } : joined);
|
|
3695
|
+
for (const [a, b] of VD.contents)
|
|
3696
|
+
contents.push({ sub: layer.text.slice(a, b), rawAt: (k) => ps[a + k] ?? 0, rawEndAt: (k) => pe[a + k] ?? 0 });
|
|
3697
|
+
}
|
|
3698
|
+
return { surfaces, contents };
|
|
3699
|
+
}
|
|
3292
3700
|
function finalIsStructural(text, at) {
|
|
3293
3701
|
if (text.charCodeAt(at) !== 0x5c)
|
|
3294
3702
|
return false;
|
|
@@ -3557,6 +3965,9 @@ function collectCandidates(text, o, nested) {
|
|
|
3557
3965
|
surfaces.push(joinedSpaced);
|
|
3558
3966
|
const screen = screenSurfaces(text, o);
|
|
3559
3967
|
surfaces.push(...screen.surfaces);
|
|
3968
|
+
const decoded = percentSurfaces(text, text, null, o);
|
|
3969
|
+
surfaces.push(...decoded.surfaces);
|
|
3970
|
+
const decodedContents = decoded.contents;
|
|
3560
3971
|
const raw = [];
|
|
3561
3972
|
const blocks = { raw: text, view: V, out: raw, lines: [null, null], marks: null };
|
|
3562
3973
|
const regionSurface = screen.surfaces[0] ?? separated;
|
|
@@ -3566,7 +3977,7 @@ function collectCandidates(text, o, nested) {
|
|
|
3566
3977
|
const regions = [];
|
|
3567
3978
|
if (o.urls) {
|
|
3568
3979
|
const unitPos = (k) => S.dropped(k) || V.rawUnit[S.rawStart(k)] === 1;
|
|
3569
|
-
urlCandidates(S.text, cands, regions, unitPos, (k) => unitPos(k) || S.painted(k));
|
|
3980
|
+
urlCandidates(S.text, cands, regions, unitPos, (k) => unitPos(k) || S.painted(k), o.queryByShape ?? false);
|
|
3570
3981
|
userinfoCandidates(S, cands, o.words);
|
|
3571
3982
|
}
|
|
3572
3983
|
if (o.words) {
|
|
@@ -3575,6 +3986,8 @@ function collectCandidates(text, o, nested) {
|
|
|
3575
3986
|
labelCandidates(S, 'scheme', regions, cands, blocks);
|
|
3576
3987
|
labelCandidates(S, 'token', regions, cands, blocks);
|
|
3577
3988
|
labelCandidates(S, 'label', regions, cands, blocks);
|
|
3989
|
+
labelCandidates(S, 'scheme', regions, cands, blocks, true);
|
|
3990
|
+
labelCandidates(S, 'label', regions, cands, blocks, true);
|
|
3578
3991
|
editsToCandidates(authParamEdits(S.text), 'param', cands);
|
|
3579
3992
|
editsToCandidates(proseLiteralEdits(S.text), 'prose', cands);
|
|
3580
3993
|
}
|
|
@@ -3592,7 +4005,7 @@ function collectCandidates(text, o, nested) {
|
|
|
3592
4005
|
raw.push({ start: a + iv.start, end: a + iv.end, kind: iv.kind, cls: 'nested', tokenEnd: a + iv.end, pretrimmed: true });
|
|
3593
4006
|
}
|
|
3594
4007
|
}
|
|
3595
|
-
for (const c of screen.contents) {
|
|
4008
|
+
for (const c of [...screen.contents, ...decodedContents]) {
|
|
3596
4009
|
const inner = collectCandidates(c.sub, o, true);
|
|
3597
4010
|
for (const iv of resolveCandidates(c.sub, inner.cands, inner.rawUnit, inner.rawDot, o.words ? pemRegions(inner.pemBlocksSeen) : [], inner.rawSoft, inner.rawPlain)) {
|
|
3598
4011
|
const start = c.rawAt(iv.start);
|
|
@@ -3661,11 +4074,6 @@ export function washCredentials(text) {
|
|
|
3661
4074
|
return text;
|
|
3662
4075
|
return scanAndMask(text, WASH_OPTIONS, false).text;
|
|
3663
4076
|
}
|
|
3664
|
-
const C0_ALL = '\\u0000-\\u001F';
|
|
3665
|
-
const C0_KEEP_LAYOUT = '\\u0000-\\u0008\\u000B-\\u001F';
|
|
3666
|
-
const DEL_C1 = '\\u007F-\\u009F';
|
|
3667
|
-
const LONE_SURROGATE = '\\uD800-\\uDFFF';
|
|
3668
|
-
const LINE_SEPARATORS = '\\u2028\\u2029';
|
|
3669
4077
|
const NAME_BLANKS = NAME_BLANK_RANGES.map(([a, b]) => (a === b ? classEscape(a) : `${classEscape(a)}-${classEscape(b)}`)).join('');
|
|
3670
4078
|
function classEscape(cp) {
|
|
3671
4079
|
return `\\u${cp.toString(16).toUpperCase().padStart(4, '0')}`;
|
|
@@ -3770,9 +4178,7 @@ function faceHitKept(ch, at, text) {
|
|
|
3770
4178
|
const c = ch.charCodeAt(0);
|
|
3771
4179
|
return ch.length === 1 && (c === 0x200d || c === 0x200c) && joinerKept(text, at, c === 0x200d);
|
|
3772
4180
|
}
|
|
3773
|
-
const FORMAT_CLASS = '\\p{Cf}';
|
|
3774
4181
|
const RGI_TAG_FLAG = '\\u{1F3F4}\\u{E0067}\\u{E0062}(?:\\u{E0065}\\u{E006E}\\u{E0067}|\\u{E0073}\\u{E0063}\\u{E0074}|\\u{E0077}\\u{E006C}\\u{E0073})\\u{E007F}';
|
|
3775
|
-
const BIDI_REORDER = '\\u061C\\u200E\\u200F\\u2028\\u2029\\u202A-\\u202E\\u2066-\\u2069';
|
|
3776
4182
|
function unsafeClass(members, withFormatClass) {
|
|
3777
4183
|
if (members === '' && !withFormatClass)
|
|
3778
4184
|
return null;
|
|
@@ -3783,17 +4189,6 @@ function unsafeClass(members, withFormatClass) {
|
|
|
3783
4189
|
];
|
|
3784
4190
|
return new RegExp(parts.join('|'), 'gu');
|
|
3785
4191
|
}
|
|
3786
|
-
export const LEGACY_ESCAPE_FACE = Object.freeze({
|
|
3787
|
-
unsafe: unsafeClass(`${C0_ALL}${DEL_C1}${BIDI_REORDER}${LONE_SURROGATE}`, false),
|
|
3788
|
-
fold: false,
|
|
3789
|
-
mark: 'escape',
|
|
3790
|
-
});
|
|
3791
|
-
export const LEGACY_LABEL_FACE = Object.freeze({ ...LEGACY_ESCAPE_FACE, fold: true });
|
|
3792
|
-
export const LEGACY_NAME_FACE = Object.freeze({
|
|
3793
|
-
unsafe: unsafeClass(`${C0_ALL}\\u007F${LINE_SEPARATORS}`, false),
|
|
3794
|
-
fold: true,
|
|
3795
|
-
mark: 'space',
|
|
3796
|
-
});
|
|
3797
4192
|
function markOf(ch, mark) {
|
|
3798
4193
|
if (mark === 'dot')
|
|
3799
4194
|
return '.';
|
|
@@ -3971,8 +4366,11 @@ function publicFace(opts) {
|
|
|
3971
4366
|
const index = (opts.controls !== false ? 8 : 0) + (opts.bidi !== false ? 4 : 0) + (keep ? 2 : 0) + (blanks ? 1 : 0);
|
|
3972
4367
|
return { unsafe: PUBLIC_UNSAFE_BY_NETS[index] ?? null, fold, mark: opts.mark ?? 'escape', keepBlanks: blanks };
|
|
3973
4368
|
}
|
|
4369
|
+
export const ESCAPE_FACE = Object.freeze({ ...publicFace({ foldLines: false }) });
|
|
4370
|
+
export const LABEL_FACE = Object.freeze({ ...publicFace({}) });
|
|
4371
|
+
export const PEER_NAME_FACE = Object.freeze({ ...publicFace({ mark: 'space' }) });
|
|
3974
4372
|
const ESCAPE_TOKEN_AT = /^\\u(?:[0-9A-F]{4}|\{[0-9A-F]{1,6}\})/;
|
|
3975
|
-
function capDisplay(text, max, mark) {
|
|
4373
|
+
export function capDisplay(text, max, mark) {
|
|
3976
4374
|
if (typeof max !== 'number' || !Number.isFinite(max))
|
|
3977
4375
|
return text;
|
|
3978
4376
|
const limit = Math.max(0, Math.floor(max));
|
|
@@ -4011,6 +4409,14 @@ function runDisplaySteps(start, steps) {
|
|
|
4011
4409
|
}
|
|
4012
4410
|
return out;
|
|
4013
4411
|
}
|
|
4412
|
+
export function paintAndCap(text, face, max) {
|
|
4413
|
+
return runDisplaySteps(text, {
|
|
4414
|
+
wash: (s) => s,
|
|
4415
|
+
paint: (s) => applyDisplayFace(s, face),
|
|
4416
|
+
cap: (s) => capDisplay(s, max, face.mark),
|
|
4417
|
+
text: (s) => s,
|
|
4418
|
+
});
|
|
4419
|
+
}
|
|
4014
4420
|
function escapeSpacesFor(o, face) {
|
|
4015
4421
|
if (face.mark !== 'escape' || face.fold)
|
|
4016
4422
|
return null;
|
|
@@ -4029,9 +4435,10 @@ function escapeSpacesFor(o, face) {
|
|
|
4029
4435
|
}
|
|
4030
4436
|
return set.size === 0 ? null : set;
|
|
4031
4437
|
}
|
|
4032
|
-
function scanOptionsOf(o, face) {
|
|
4438
|
+
function scanOptionsOf(o, face, queryByShape = false) {
|
|
4033
4439
|
return {
|
|
4034
4440
|
urls: o.credentialUrls !== false,
|
|
4441
|
+
queryByShape,
|
|
4035
4442
|
words: o.credentialWords !== false,
|
|
4036
4443
|
blanks: face.keepBlanks === true,
|
|
4037
4444
|
fold: face.fold,
|
|
@@ -4046,11 +4453,11 @@ export function credentialWashPasses(text, opts = {}) {
|
|
|
4046
4453
|
scanAndMask(input, scan, false, stats);
|
|
4047
4454
|
return { passes: stats.passes, capped: stats.capped };
|
|
4048
4455
|
}
|
|
4049
|
-
function renderUntrusted(text, opts, ledger) {
|
|
4456
|
+
function renderUntrusted(text, opts, ledger, queryByShape = false) {
|
|
4050
4457
|
const input = typeof text === 'string' ? text : String(text ?? '');
|
|
4051
4458
|
const o = opts ?? {};
|
|
4052
4459
|
const face = publicFace(o);
|
|
4053
|
-
const scan = scanOptionsOf(o, face);
|
|
4460
|
+
const scan = scanOptionsOf(o, face, queryByShape);
|
|
4054
4461
|
const pairBackslashes = o.escapeBackslashes === true && face.mark !== 'dot' && face.mark !== 'space';
|
|
4055
4462
|
const book = ledger ?? (pairBackslashes ? { cps: [], lens: [] } : null);
|
|
4056
4463
|
if (book === null) {
|
|
@@ -4081,6 +4488,197 @@ export function displayUntrusted(text, opts = {}) {
|
|
|
4081
4488
|
const out = renderUntrusted(text, opts, null);
|
|
4082
4489
|
return typeof out === 'string' ? out : out.text;
|
|
4083
4490
|
}
|
|
4491
|
+
const NON_SECRET_FIELD_NAMES = new Set([
|
|
4492
|
+
'deployment', 'deploymentname', 'deploymentid', 'name', 'tenant', 'tenantname', 'tenantid', 'region', 'location', 'zone',
|
|
4493
|
+
'project', 'projectname', 'projectid', 'workspace', 'workspacename', 'workspaceid', 'resource', 'resourcename', 'resourcegroup',
|
|
4494
|
+
'model', 'modelname', 'modelid', 'apiversion', 'version', 'env', 'environment', 'stage', 'cluster', 'namespace', 'instance',
|
|
4495
|
+
'service', 'servicename', 'app', 'appname', 'application', 'team', 'site', 'org', 'organization',
|
|
4496
|
+
]);
|
|
4497
|
+
function isNonSecretFieldName(key) {
|
|
4498
|
+
const view = percentDecodeForMatching(key).decoded;
|
|
4499
|
+
return NON_SECRET_FIELD_NAMES.has(view.toLowerCase().replace(/[-_]/g, ''));
|
|
4500
|
+
}
|
|
4501
|
+
function isCredentialLabelName(name) {
|
|
4502
|
+
if (name.length === 0)
|
|
4503
|
+
return false;
|
|
4504
|
+
const decoded = percentDecodeForMatching(name).decoded;
|
|
4505
|
+
for (const view of decoded === name ? [name] : [name, decoded]) {
|
|
4506
|
+
const probe = `${view}=`;
|
|
4507
|
+
if (labelEndsAt(probe, probe.length, false, true))
|
|
4508
|
+
return true;
|
|
4509
|
+
}
|
|
4510
|
+
return false;
|
|
4511
|
+
}
|
|
4512
|
+
const WORD_CHAIN_MAX_SUFFIX_DIGITS = 4;
|
|
4513
|
+
const WORD_CHAIN_MAX_DIGIT_RUN = 8;
|
|
4514
|
+
function isReadableWordChain(value) {
|
|
4515
|
+
const core = valueCoreForJudging(value);
|
|
4516
|
+
if (core.length === 0 || !core.includes('-'))
|
|
4517
|
+
return false;
|
|
4518
|
+
const segments = core.split('-');
|
|
4519
|
+
if (segments.length < 2)
|
|
4520
|
+
return false;
|
|
4521
|
+
if (!segments.some((seg) => seg.length >= 3 && [...seg].every(isAlpha)))
|
|
4522
|
+
return false;
|
|
4523
|
+
if ([...core].every((ch) => ch === '-' || isHexDigit(ch)))
|
|
4524
|
+
return false;
|
|
4525
|
+
for (const seg of segments) {
|
|
4526
|
+
const letters = seg.replace(/[0-9]+$/, '').toLowerCase();
|
|
4527
|
+
if (/[bcdfghjklmnpqrstvwxz]{4,}/.test(letters))
|
|
4528
|
+
return false;
|
|
4529
|
+
if (letters.length >= 5 && !/[aeiouy]/.test(letters))
|
|
4530
|
+
return false;
|
|
4531
|
+
}
|
|
4532
|
+
for (const seg of segments) {
|
|
4533
|
+
if (seg.length === 0)
|
|
4534
|
+
return false;
|
|
4535
|
+
let i = 0;
|
|
4536
|
+
while (i < seg.length && isAlpha(seg.charAt(i)))
|
|
4537
|
+
i++;
|
|
4538
|
+
const letters = seg.slice(0, i);
|
|
4539
|
+
const digits = seg.slice(i);
|
|
4540
|
+
for (const ch of digits)
|
|
4541
|
+
if (ch < '0' || ch > '9')
|
|
4542
|
+
return false;
|
|
4543
|
+
if (letters.length === 0) {
|
|
4544
|
+
if (digits.length === 0 || digits.length > WORD_CHAIN_MAX_DIGIT_RUN)
|
|
4545
|
+
return false;
|
|
4546
|
+
continue;
|
|
4547
|
+
}
|
|
4548
|
+
const caseOk = letters === letters.toLowerCase() || letters === letters.toUpperCase() ||
|
|
4549
|
+
(letters.charAt(0) === letters.charAt(0).toUpperCase() && letters.slice(1) === letters.slice(1).toLowerCase());
|
|
4550
|
+
if (!caseOk)
|
|
4551
|
+
return false;
|
|
4552
|
+
if (digits.length > 0 && (letters.length < 2 || digits.length > WORD_CHAIN_MAX_SUFFIX_DIGITS))
|
|
4553
|
+
return false;
|
|
4554
|
+
}
|
|
4555
|
+
return true;
|
|
4556
|
+
}
|
|
4557
|
+
const OPAQUE_TOKEN_PUNCTUATION = new Set(['-', '_', '.', '~', '+', '/', '=']);
|
|
4558
|
+
const HIGH_ENTROPY_MIN_ALNUM = 20;
|
|
4559
|
+
function isHighEntropyQueryValue(value) {
|
|
4560
|
+
const { decoded } = percentDecodeForMatching(value);
|
|
4561
|
+
let alnum = 0;
|
|
4562
|
+
let mixed = 0;
|
|
4563
|
+
let run = 0;
|
|
4564
|
+
let runHasLetter = false;
|
|
4565
|
+
let runHasDigit = false;
|
|
4566
|
+
let anyLetter = false;
|
|
4567
|
+
let anyDigit = false;
|
|
4568
|
+
let allHex = true;
|
|
4569
|
+
const flush = () => {
|
|
4570
|
+
alnum += run;
|
|
4571
|
+
if (runHasLetter && runHasDigit)
|
|
4572
|
+
mixed += run;
|
|
4573
|
+
run = 0;
|
|
4574
|
+
runHasLetter = false;
|
|
4575
|
+
runHasDigit = false;
|
|
4576
|
+
};
|
|
4577
|
+
for (const ch of decoded) {
|
|
4578
|
+
if (isAlpha(ch)) {
|
|
4579
|
+
run += 1;
|
|
4580
|
+
runHasLetter = true;
|
|
4581
|
+
anyLetter = true;
|
|
4582
|
+
if (!isHexDigit(ch))
|
|
4583
|
+
allHex = false;
|
|
4584
|
+
continue;
|
|
4585
|
+
}
|
|
4586
|
+
if (ch >= '0' && ch <= '9') {
|
|
4587
|
+
run += 1;
|
|
4588
|
+
runHasDigit = true;
|
|
4589
|
+
anyDigit = true;
|
|
4590
|
+
continue;
|
|
4591
|
+
}
|
|
4592
|
+
if (!OPAQUE_TOKEN_PUNCTUATION.has(ch))
|
|
4593
|
+
return false;
|
|
4594
|
+
flush();
|
|
4595
|
+
}
|
|
4596
|
+
flush();
|
|
4597
|
+
if (alnum < HIGH_ENTROPY_MIN_ALNUM)
|
|
4598
|
+
return false;
|
|
4599
|
+
return mixed * 2 >= alnum || (allHex && anyLetter && anyDigit);
|
|
4600
|
+
}
|
|
4601
|
+
function isOpaqueSecretValue(value) {
|
|
4602
|
+
const core = valueCoreForJudging(value);
|
|
4603
|
+
return core.length > 0 && (looksLikeKnownSecret(core) || isHighEntropyQueryValue(core));
|
|
4604
|
+
}
|
|
4605
|
+
const VALUE_PIECE_SEPARATORS = new Set(['/', '\\', '?', '#', '&', '=', ';', ':', '@', ',', '+']);
|
|
4606
|
+
function hasOpaquePiece(text) {
|
|
4607
|
+
let start = 0;
|
|
4608
|
+
for (let i = 0; i <= text.length; i++) {
|
|
4609
|
+
const ch = text.charAt(i);
|
|
4610
|
+
if (i === text.length || ch <= ' ' || VALUE_PIECE_SEPARATORS.has(ch)) {
|
|
4611
|
+
if (i > start && isOpaqueSecretValue(text.slice(start, i)))
|
|
4612
|
+
return true;
|
|
4613
|
+
start = i + 1;
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
return false;
|
|
4617
|
+
}
|
|
4618
|
+
function carriesCredentialStructure(value) {
|
|
4619
|
+
const netChanges = (v) => {
|
|
4620
|
+
if (washCredentials(v) !== v || hasOpaquePiece(v))
|
|
4621
|
+
return true;
|
|
4622
|
+
if (!v.includes('+'))
|
|
4623
|
+
return false;
|
|
4624
|
+
const spaced = v.split('+').join(' ');
|
|
4625
|
+
return washCredentials(spaced) !== spaced;
|
|
4626
|
+
};
|
|
4627
|
+
let view = value;
|
|
4628
|
+
for (let layer = 0; layer < MAX_PERCENT_VIEW_LAYERS; layer++) {
|
|
4629
|
+
if (netChanges(view))
|
|
4630
|
+
return true;
|
|
4631
|
+
const next = percentDecodeForMatching(view).decoded;
|
|
4632
|
+
if (next === view)
|
|
4633
|
+
return false;
|
|
4634
|
+
view = next;
|
|
4635
|
+
}
|
|
4636
|
+
if (netChanges(view))
|
|
4637
|
+
return true;
|
|
4638
|
+
return percentDecodeForMatching(view).decoded !== view;
|
|
4639
|
+
}
|
|
4640
|
+
function queryPartCarriesCredential(key, value, relax) {
|
|
4641
|
+
if (value.length === 0 || isMarker(value))
|
|
4642
|
+
return false;
|
|
4643
|
+
if (key !== null) {
|
|
4644
|
+
if (isCredentialLabelName(key))
|
|
4645
|
+
return true;
|
|
4646
|
+
if (relax && isNonSecretFieldName(key) && isReadableWordChain(value))
|
|
4647
|
+
return isKnownSecretSegment(value);
|
|
4648
|
+
}
|
|
4649
|
+
return isOpaqueSecretValue(value) || carriesCredentialStructure(value);
|
|
4650
|
+
}
|
|
4651
|
+
const UPLOAD_PROBE_PREFIX = 'https://q.invalid/?';
|
|
4652
|
+
const UPLOAD_SCAN_OPTIONS = Object.freeze({ urls: true, queryByShape: 'strict', words: true, blanks: false, fold: false, face: null, escapeSpaces: null });
|
|
4653
|
+
export function queryCarriesCredential(query) {
|
|
4654
|
+
if (typeof query !== 'string' || query.length === 0)
|
|
4655
|
+
return false;
|
|
4656
|
+
const probe = `${UPLOAD_PROBE_PREFIX}${query}`;
|
|
4657
|
+
return scanOnce(probe, UPLOAD_SCAN_OPTIONS, false).text !== probe;
|
|
4658
|
+
}
|
|
4659
|
+
export function displayConfiguredUrl(url, opts = {}) {
|
|
4660
|
+
const out = renderUntrusted(typeof url === 'string' ? configuredUrlScannable(url) : url, opts, null, 'relaxed');
|
|
4661
|
+
return typeof out === 'string' ? out : out.text;
|
|
4662
|
+
}
|
|
4663
|
+
function configuredUrlScannable(url) {
|
|
4664
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(url) || !/^[A-Za-z][A-Za-z0-9+.-]*:/.test(url))
|
|
4665
|
+
return url;
|
|
4666
|
+
let u;
|
|
4667
|
+
try {
|
|
4668
|
+
u = new URL(url);
|
|
4669
|
+
}
|
|
4670
|
+
catch {
|
|
4671
|
+
return url;
|
|
4672
|
+
}
|
|
4673
|
+
if (u.host === '')
|
|
4674
|
+
return url;
|
|
4675
|
+
const userinfo = u.username !== '' || u.password !== '' ? `${u.username}${u.password !== '' ? `:${u.password}` : ''}@` : '';
|
|
4676
|
+
return `${u.protocol}//${userinfo}${u.host}${u.pathname}${u.search}${u.hash}`;
|
|
4677
|
+
}
|
|
4678
|
+
export function quoteUntrustedForSentence(text, max) {
|
|
4679
|
+
const shown = displayUntrusted(text, { max, blanks: true, escapeBackslashes: true });
|
|
4680
|
+
return shown.trim() === '' ? undefined : `"${shown.replace(/"/g, '\\"')}"`;
|
|
4681
|
+
}
|
|
4084
4682
|
export function displayUntrustedMarks(text, opts = {}) {
|
|
4085
4683
|
const ledger = { cps: [], lens: [] };
|
|
4086
4684
|
const out = renderUntrusted(text, opts, ledger);
|
|
@@ -4088,4 +4686,4 @@ export function displayUntrustedMarks(text, opts = {}) {
|
|
|
4088
4686
|
return { text: out, marks: [] };
|
|
4089
4687
|
return { text: out.text, marks: collectMarks(out, ledger) };
|
|
4090
4688
|
}
|
|
4091
|
-
const isQuoteChar = (c) => c.charCodeAt(0) === 0x22 || c.charCodeAt(0) === 0x27
|
|
4689
|
+
const isQuoteChar = (c) => c.charCodeAt(0) === 0x22 || c.charCodeAt(0) === 0x27;
|