@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 CHANGED
@@ -5574,7 +5574,7 @@ function readBuildInjectedVersion() {
5574
5574
  if (false) {
5575
5575
  return void 0;
5576
5576
  }
5577
- const version = "1.11.6".trim();
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.infoEnabled = isBetaPluginVersion(options.version ?? PLUGIN_VERSION);
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
- infoEnabled;
5700
+ redactLogs;
5628
5701
  retentionDays;
5629
5702
  lastPruneDateKey = null;
5630
5703
  info(msg) {
5631
5704
  this.prepareLogDate(/* @__PURE__ */ new Date());
5632
- if (!this.infoEnabled) {
5633
- return;
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.upstream.warn(msg);
5640
- this.append("WARN", msg);
5710
+ const safeMsg = this.formatLogMessage(msg);
5711
+ this.upstream.warn(safeMsg);
5712
+ this.append("WARN", safeMsg);
5641
5713
  }
5642
5714
  error(msg) {
5643
- this.upstream.error(msg);
5644
- this.append("ERROR", msg);
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");