@yoooclaw/phone-notifications 1.11.6 → 1.11.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +273 -15
- package/dist/index.cjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -5574,7 +5574,7 @@ function readBuildInjectedVersion() {
|
|
|
5574
5574
|
if (false) {
|
|
5575
5575
|
return void 0;
|
|
5576
5576
|
}
|
|
5577
|
-
const version = "1.11.
|
|
5577
|
+
const version = "1.11.7".trim();
|
|
5578
5578
|
return version || void 0;
|
|
5579
5579
|
}
|
|
5580
5580
|
function readPluginVersionFromPackageJson() {
|
|
@@ -5594,6 +5594,78 @@ var PLUGIN_VERSION = readBuildInjectedVersion() ?? readPluginVersionFromPackageJ
|
|
|
5594
5594
|
// src/logger.ts
|
|
5595
5595
|
var DEFAULT_LOG_RETENTION_DAYS = 30;
|
|
5596
5596
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
5597
|
+
var REDACTED = "[redacted]";
|
|
5598
|
+
var REDACTED_SECRET = "[redacted-secret]";
|
|
5599
|
+
var REDACTED_URL = "[redacted-url]";
|
|
5600
|
+
var SECRET_KEYS = [
|
|
5601
|
+
"apiKey",
|
|
5602
|
+
"api_key",
|
|
5603
|
+
"appKey",
|
|
5604
|
+
"authorization",
|
|
5605
|
+
"password",
|
|
5606
|
+
"secret",
|
|
5607
|
+
"token",
|
|
5608
|
+
"accessToken",
|
|
5609
|
+
"refreshToken",
|
|
5610
|
+
"gatewayToken",
|
|
5611
|
+
"gatewayPassword",
|
|
5612
|
+
"apnsToken",
|
|
5613
|
+
"deviceToken",
|
|
5614
|
+
"X-Api-Key-Id",
|
|
5615
|
+
"x-api-key-id",
|
|
5616
|
+
"x-openclaw-password"
|
|
5617
|
+
];
|
|
5618
|
+
var USER_TEXT_KEYS = [
|
|
5619
|
+
"accountId",
|
|
5620
|
+
"body",
|
|
5621
|
+
"content",
|
|
5622
|
+
"conversationName",
|
|
5623
|
+
"deviceId",
|
|
5624
|
+
"loginAccount",
|
|
5625
|
+
"metadata",
|
|
5626
|
+
"name",
|
|
5627
|
+
"raw",
|
|
5628
|
+
"rawResponse",
|
|
5629
|
+
"reason",
|
|
5630
|
+
"recordResult",
|
|
5631
|
+
"recordingName",
|
|
5632
|
+
"resBody",
|
|
5633
|
+
"response",
|
|
5634
|
+
"senderName",
|
|
5635
|
+
"sourceText",
|
|
5636
|
+
"sourceTextList",
|
|
5637
|
+
"summary",
|
|
5638
|
+
"summaryResult",
|
|
5639
|
+
"summaryText",
|
|
5640
|
+
"text",
|
|
5641
|
+
"title",
|
|
5642
|
+
"transcript",
|
|
5643
|
+
"transcriptData",
|
|
5644
|
+
"userId"
|
|
5645
|
+
];
|
|
5646
|
+
var USER_URL_KEYS = [
|
|
5647
|
+
"audio",
|
|
5648
|
+
"audioOssUrl",
|
|
5649
|
+
"fileUrl",
|
|
5650
|
+
"oss_audio_url",
|
|
5651
|
+
"oss_srt_url",
|
|
5652
|
+
"srt",
|
|
5653
|
+
"url"
|
|
5654
|
+
];
|
|
5655
|
+
var SENSITIVE_QUERY_KEYS = [
|
|
5656
|
+
"access_token",
|
|
5657
|
+
"api_key",
|
|
5658
|
+
"apikey",
|
|
5659
|
+
"authorization",
|
|
5660
|
+
"fileUrl",
|
|
5661
|
+
"password",
|
|
5662
|
+
"refresh_token",
|
|
5663
|
+
"secret",
|
|
5664
|
+
"signature",
|
|
5665
|
+
"token",
|
|
5666
|
+
"x-api-key-id",
|
|
5667
|
+
"x-oss-security-token"
|
|
5668
|
+
];
|
|
5597
5669
|
function isBetaPluginVersion(version = PLUGIN_VERSION) {
|
|
5598
5670
|
return /\bbeta\b/i.test(version);
|
|
5599
5671
|
}
|
|
@@ -5602,13 +5674,14 @@ function createVersionAwareLogger(upstream, options = {}) {
|
|
|
5602
5674
|
return upstream;
|
|
5603
5675
|
}
|
|
5604
5676
|
return {
|
|
5605
|
-
info() {
|
|
5677
|
+
info(msg) {
|
|
5678
|
+
upstream.info(redactLogMessage(msg));
|
|
5606
5679
|
},
|
|
5607
5680
|
warn(msg) {
|
|
5608
|
-
upstream.warn(msg);
|
|
5681
|
+
upstream.warn(redactLogMessage(msg));
|
|
5609
5682
|
},
|
|
5610
5683
|
error(msg) {
|
|
5611
|
-
upstream.error(msg);
|
|
5684
|
+
upstream.error(redactLogMessage(msg));
|
|
5612
5685
|
}
|
|
5613
5686
|
};
|
|
5614
5687
|
}
|
|
@@ -5616,7 +5689,7 @@ var PluginFileLogger = class {
|
|
|
5616
5689
|
constructor(upstream, stateDir, options = {}) {
|
|
5617
5690
|
this.upstream = upstream;
|
|
5618
5691
|
this.logsDir = (0, import_node_path.join)(stateDir, "plugins", "phone-notifications", "logs");
|
|
5619
|
-
this.
|
|
5692
|
+
this.redactLogs = !isBetaPluginVersion(options.version ?? PLUGIN_VERSION);
|
|
5620
5693
|
this.retentionDays = Number.isFinite(options.retentionDays) && (options.retentionDays ?? 0) > 0 ? options.retentionDays : DEFAULT_LOG_RETENTION_DAYS;
|
|
5621
5694
|
(0, import_node_fs2.mkdirSync)(this.logsDir, { recursive: true });
|
|
5622
5695
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -5624,24 +5697,27 @@ var PluginFileLogger = class {
|
|
|
5624
5697
|
this.lastPruneDateKey = formatDate(now);
|
|
5625
5698
|
}
|
|
5626
5699
|
logsDir;
|
|
5627
|
-
|
|
5700
|
+
redactLogs;
|
|
5628
5701
|
retentionDays;
|
|
5629
5702
|
lastPruneDateKey = null;
|
|
5630
5703
|
info(msg) {
|
|
5631
5704
|
this.prepareLogDate(/* @__PURE__ */ new Date());
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
this.upstream.info(msg);
|
|
5636
|
-
this.append("INFO", msg);
|
|
5705
|
+
const safeMsg = this.formatLogMessage(msg);
|
|
5706
|
+
this.upstream.info(safeMsg);
|
|
5707
|
+
this.append("INFO", safeMsg);
|
|
5637
5708
|
}
|
|
5638
5709
|
warn(msg) {
|
|
5639
|
-
this.
|
|
5640
|
-
this.
|
|
5710
|
+
const safeMsg = this.formatLogMessage(msg);
|
|
5711
|
+
this.upstream.warn(safeMsg);
|
|
5712
|
+
this.append("WARN", safeMsg);
|
|
5641
5713
|
}
|
|
5642
5714
|
error(msg) {
|
|
5643
|
-
this.
|
|
5644
|
-
this.
|
|
5715
|
+
const safeMsg = this.formatLogMessage(msg);
|
|
5716
|
+
this.upstream.error(safeMsg);
|
|
5717
|
+
this.append("ERROR", safeMsg);
|
|
5718
|
+
}
|
|
5719
|
+
formatLogMessage(msg) {
|
|
5720
|
+
return this.redactLogs ? redactLogMessage(msg) : msg;
|
|
5645
5721
|
}
|
|
5646
5722
|
append(level, msg) {
|
|
5647
5723
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -5677,6 +5753,188 @@ var PluginFileLogger = class {
|
|
|
5677
5753
|
}
|
|
5678
5754
|
}
|
|
5679
5755
|
};
|
|
5756
|
+
function redactLogMessage(msg) {
|
|
5757
|
+
let redacted = String(msg);
|
|
5758
|
+
redacted = redactQuotedObjectFields(redacted, SECRET_KEYS, REDACTED_SECRET);
|
|
5759
|
+
redacted = redactQuotedObjectFields(redacted, USER_TEXT_KEYS, REDACTED);
|
|
5760
|
+
redacted = redactQuotedObjectFields(redacted, USER_URL_KEYS, REDACTED_URL);
|
|
5761
|
+
redacted = redactStructuredKeyValueFields(
|
|
5762
|
+
redacted,
|
|
5763
|
+
SECRET_KEYS,
|
|
5764
|
+
REDACTED_SECRET
|
|
5765
|
+
);
|
|
5766
|
+
redacted = redactStructuredKeyValueFields(redacted, USER_TEXT_KEYS, REDACTED);
|
|
5767
|
+
redacted = redactStructuredKeyValueFields(redacted, USER_URL_KEYS, REDACTED_URL);
|
|
5768
|
+
redacted = redactKeyValueFields(redacted, SECRET_KEYS, REDACTED_SECRET);
|
|
5769
|
+
redacted = redactKeyValueFields(redacted, USER_TEXT_KEYS, REDACTED);
|
|
5770
|
+
redacted = redactKeyValueFields(redacted, USER_URL_KEYS, REDACTED_URL);
|
|
5771
|
+
redacted = redactColonTextFields(redacted, SECRET_KEYS, REDACTED_SECRET);
|
|
5772
|
+
redacted = redactColonTextFields(redacted, USER_TEXT_KEYS, REDACTED);
|
|
5773
|
+
redacted = redactQueryParams(redacted, SENSITIVE_QUERY_KEYS);
|
|
5774
|
+
redacted = redactBearerTokens(redacted);
|
|
5775
|
+
redacted = redactLikelyUserUrls(redacted);
|
|
5776
|
+
redacted = redactEmails(redacted);
|
|
5777
|
+
redacted = redactPhoneNumbers(redacted);
|
|
5778
|
+
redacted = redactJwtTokens(redacted);
|
|
5779
|
+
redacted = redactLongHexTokens(redacted);
|
|
5780
|
+
return redacted;
|
|
5781
|
+
}
|
|
5782
|
+
function redactQuotedObjectFields(input, keys, placeholder) {
|
|
5783
|
+
const keyPattern = buildKeyPattern(keys);
|
|
5784
|
+
return input.replace(
|
|
5785
|
+
new RegExp(
|
|
5786
|
+
`(["'])(${keyPattern})\\1\\s*:\\s*(?:"(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|[^,}\\]]+)`,
|
|
5787
|
+
"gi"
|
|
5788
|
+
),
|
|
5789
|
+
(_match, quote, key) => `${quote}${key}${quote}: "${placeholder}"`
|
|
5790
|
+
);
|
|
5791
|
+
}
|
|
5792
|
+
function redactKeyValueFields(input, keys, placeholder) {
|
|
5793
|
+
const keyPattern = buildKeyPattern(keys);
|
|
5794
|
+
return input.replace(
|
|
5795
|
+
new RegExp(
|
|
5796
|
+
`(?<![?&])\\b(${keyPattern})\\s*=\\s*(?:Bearer\\s+[^,\\s)]+|"(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|[^,\\s)]+)`,
|
|
5797
|
+
"gi"
|
|
5798
|
+
),
|
|
5799
|
+
(_match, key) => `${key}=${placeholder}`
|
|
5800
|
+
);
|
|
5801
|
+
}
|
|
5802
|
+
function redactStructuredKeyValueFields(input, keys, placeholder) {
|
|
5803
|
+
const keyPattern = buildKeyPattern(keys);
|
|
5804
|
+
const regex = new RegExp(`\\b(${keyPattern})\\s*=\\s*([\\[{])`, "gi");
|
|
5805
|
+
let result = "";
|
|
5806
|
+
let lastIndex = 0;
|
|
5807
|
+
let match;
|
|
5808
|
+
while (match = regex.exec(input)) {
|
|
5809
|
+
const valueStart = regex.lastIndex - 1;
|
|
5810
|
+
const valueEnd = findStructuredValueEnd(input, valueStart);
|
|
5811
|
+
if (valueEnd === null) {
|
|
5812
|
+
continue;
|
|
5813
|
+
}
|
|
5814
|
+
result += input.slice(lastIndex, match.index);
|
|
5815
|
+
result += `${match[1]}=${placeholder}`;
|
|
5816
|
+
lastIndex = valueEnd;
|
|
5817
|
+
regex.lastIndex = valueEnd;
|
|
5818
|
+
}
|
|
5819
|
+
if (lastIndex === 0) {
|
|
5820
|
+
return input;
|
|
5821
|
+
}
|
|
5822
|
+
return result + input.slice(lastIndex);
|
|
5823
|
+
}
|
|
5824
|
+
function findStructuredValueEnd(input, start) {
|
|
5825
|
+
const open = input[start];
|
|
5826
|
+
const close = open === "{" ? "}" : "]";
|
|
5827
|
+
const stack = [close];
|
|
5828
|
+
let quote = null;
|
|
5829
|
+
let escaped = false;
|
|
5830
|
+
for (let i = start + 1; i < input.length; i++) {
|
|
5831
|
+
const ch = input[i];
|
|
5832
|
+
if (quote) {
|
|
5833
|
+
if (escaped) {
|
|
5834
|
+
escaped = false;
|
|
5835
|
+
} else if (ch === "\\") {
|
|
5836
|
+
escaped = true;
|
|
5837
|
+
} else if (ch === quote) {
|
|
5838
|
+
quote = null;
|
|
5839
|
+
}
|
|
5840
|
+
continue;
|
|
5841
|
+
}
|
|
5842
|
+
if (ch === '"' || ch === "'") {
|
|
5843
|
+
quote = ch;
|
|
5844
|
+
continue;
|
|
5845
|
+
}
|
|
5846
|
+
if (ch === "{" || ch === "[") {
|
|
5847
|
+
stack.push(ch === "{" ? "}" : "]");
|
|
5848
|
+
continue;
|
|
5849
|
+
}
|
|
5850
|
+
if (ch === stack[stack.length - 1]) {
|
|
5851
|
+
stack.pop();
|
|
5852
|
+
if (stack.length === 0) {
|
|
5853
|
+
return i + 1;
|
|
5854
|
+
}
|
|
5855
|
+
}
|
|
5856
|
+
}
|
|
5857
|
+
return null;
|
|
5858
|
+
}
|
|
5859
|
+
function redactColonTextFields(input, keys, placeholder) {
|
|
5860
|
+
const keyPattern = buildKeyPattern(keys);
|
|
5861
|
+
return input.replace(
|
|
5862
|
+
new RegExp(`\\b(${keyPattern})\\s*:\\s*([^,\\n]+)`, "gi"),
|
|
5863
|
+
(_match, key) => `${key}: ${placeholder}`
|
|
5864
|
+
);
|
|
5865
|
+
}
|
|
5866
|
+
function redactQueryParams(input, keys) {
|
|
5867
|
+
const keyPattern = buildKeyPattern(keys);
|
|
5868
|
+
return input.replace(
|
|
5869
|
+
new RegExp(`([?&](${keyPattern})=)([^&#\\s]+)`, "gi"),
|
|
5870
|
+
(_match, prefix) => `${prefix}${encodeURIComponent(REDACTED)}`
|
|
5871
|
+
);
|
|
5872
|
+
}
|
|
5873
|
+
function redactBearerTokens(input) {
|
|
5874
|
+
return input.replace(
|
|
5875
|
+
/\b(Bearer\s+)[A-Za-z0-9._~+/=-]+/gi,
|
|
5876
|
+
`$1${REDACTED_SECRET}`
|
|
5877
|
+
);
|
|
5878
|
+
}
|
|
5879
|
+
function redactJwtTokens(input) {
|
|
5880
|
+
return input.replace(
|
|
5881
|
+
/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g,
|
|
5882
|
+
REDACTED_SECRET
|
|
5883
|
+
);
|
|
5884
|
+
}
|
|
5885
|
+
function redactLongHexTokens(input) {
|
|
5886
|
+
return input.replace(/\b[a-f0-9]{32,}\b/gi, REDACTED_SECRET);
|
|
5887
|
+
}
|
|
5888
|
+
function redactEmails(input) {
|
|
5889
|
+
return input.replace(
|
|
5890
|
+
/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi,
|
|
5891
|
+
"[redacted-email]"
|
|
5892
|
+
);
|
|
5893
|
+
}
|
|
5894
|
+
function redactPhoneNumbers(input) {
|
|
5895
|
+
return input.replace(
|
|
5896
|
+
/\b1[3-9]\d{9}\b/g,
|
|
5897
|
+
(phone) => `${phone.slice(0, 3)}****${phone.slice(-4)}`
|
|
5898
|
+
);
|
|
5899
|
+
}
|
|
5900
|
+
function redactLikelyUserUrls(input) {
|
|
5901
|
+
return input.replace(
|
|
5902
|
+
/https?:\/\/[^\s"',)]+/gi,
|
|
5903
|
+
(rawUrl) => redactUrl(rawUrl)
|
|
5904
|
+
);
|
|
5905
|
+
}
|
|
5906
|
+
function redactUrl(rawUrl) {
|
|
5907
|
+
try {
|
|
5908
|
+
const url = new URL(rawUrl);
|
|
5909
|
+
for (const key of Array.from(url.searchParams.keys())) {
|
|
5910
|
+
if (SENSITIVE_QUERY_KEYS.some(
|
|
5911
|
+
(sensitiveKey) => sensitiveKey.toLowerCase() === key.toLowerCase()
|
|
5912
|
+
)) {
|
|
5913
|
+
url.searchParams.set(key, REDACTED);
|
|
5914
|
+
}
|
|
5915
|
+
}
|
|
5916
|
+
if (shouldRedactUrlPath(url)) {
|
|
5917
|
+
return `${url.origin}/${REDACTED_URL}`;
|
|
5918
|
+
}
|
|
5919
|
+
return url.toString();
|
|
5920
|
+
} catch {
|
|
5921
|
+
return rawUrl;
|
|
5922
|
+
}
|
|
5923
|
+
}
|
|
5924
|
+
function shouldRedactUrlPath(url) {
|
|
5925
|
+
const host = url.hostname.toLowerCase();
|
|
5926
|
+
const path2 = decodeURIComponent(url.pathname).toLowerCase();
|
|
5927
|
+
if (/(^|\.)((oss|cos|s3|storage|cdn)[.-])/.test(host) || /(aliyuncs|myqcloud|amazonaws|oss|storage|cdn)/.test(host)) {
|
|
5928
|
+
return true;
|
|
5929
|
+
}
|
|
5930
|
+
return /\/(audio|avatar|feedback|log|logs|recording|recordings)\//.test(path2) || /\.(aac|flac|json|m4a|md|mp3|ogg|opus|srt|wav|zip)$/i.test(path2);
|
|
5931
|
+
}
|
|
5932
|
+
function buildKeyPattern(keys) {
|
|
5933
|
+
return keys.map(escapeRegExp).join("|");
|
|
5934
|
+
}
|
|
5935
|
+
function escapeRegExp(value) {
|
|
5936
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5937
|
+
}
|
|
5680
5938
|
function formatDate(d) {
|
|
5681
5939
|
const y = d.getFullYear();
|
|
5682
5940
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|