@adobe/helix-onedrive-support 12.3.10 → 12.4.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 CHANGED
@@ -1,3 +1,17 @@
1
+ # [12.4.0](https://github.com/adobe/helix-onedrive-support/compare/v12.3.11...v12.4.0) (2026-06-11)
2
+
3
+
4
+ ### Features
5
+
6
+ * add sanitizeCache to repair MSAL refresh-token cache key mismatches ([#757](https://github.com/adobe/helix-onedrive-support/issues/757)) ([077d05a](https://github.com/adobe/helix-onedrive-support/commit/077d05a28d3d7e87f18281bd933bea049d6978ee))
7
+
8
+ ## [12.3.11](https://github.com/adobe/helix-onedrive-support/compare/v12.3.10...v12.3.11) (2026-06-08)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **deps:** update external fixes ([#756](https://github.com/adobe/helix-onedrive-support/issues/756)) ([81e490c](https://github.com/adobe/helix-onedrive-support/commit/81e490c0275fdb3764dd4c18b52f64d11e3c3c5a))
14
+
1
15
  ## [12.3.10](https://github.com/adobe/helix-onedrive-support/compare/v12.3.9...v12.3.10) (2026-05-25)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/helix-onedrive-support",
3
- "version": "12.3.10",
3
+ "version": "12.4.0",
4
4
  "description": "Helix OneDrive Support",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -30,13 +30,13 @@
30
30
  "@adobe/fetch": "^4.2.3",
31
31
  "@adobe/helix-shared-string": "^2.1.0",
32
32
  "@adobe/helix-shared-tokencache": "^1.4.19",
33
- "@azure/msal-common": "16.6.0",
34
- "@azure/msal-node": "5.2.0",
33
+ "@azure/msal-common": "16.6.2",
34
+ "@azure/msal-node": "5.2.2",
35
35
  "jose": "6.2.3"
36
36
  },
37
37
  "devDependencies": {
38
- "@adobe/eslint-config-helix": "3.0.27",
39
- "@aws-sdk/client-s3": "3.1045.0",
38
+ "@adobe/eslint-config-helix": "3.0.28",
39
+ "@aws-sdk/client-s3": "3.1053.0",
40
40
  "@eslint/config-helpers": "0.6.0",
41
41
  "@semantic-release/changelog": "6.0.3",
42
42
  "@semantic-release/git": "10.0.1",
@@ -50,12 +50,12 @@
50
50
  "jsdoc-to-markdown": "9.1.3",
51
51
  "jsdoc-tsimport-plugin": "1.0.5",
52
52
  "junit-report-builder": "5.1.2",
53
- "lint-staged": "16.4.0",
54
- "mocha": "11.7.5",
53
+ "lint-staged": "17.0.5",
54
+ "mocha": "11.7.6",
55
55
  "mocha-multi-reporters": "1.5.1",
56
56
  "mocha-suppress-logs": "0.6.0",
57
57
  "nock": "14.0.15",
58
- "npm": "11.14.1",
58
+ "npm": "11.15.0",
59
59
  "semantic-release": "25.0.3"
60
60
  },
61
61
  "lint-staged": {
package/src/index.js CHANGED
@@ -19,3 +19,5 @@ export { Range } from './excel/Range.js';
19
19
  export { Table } from './excel/Table.js';
20
20
  export { Workbook } from './excel/Workbook.js';
21
21
  export { Worksheet } from './excel/Worksheet.js';
22
+
23
+ export { sanitizeCache } from './sanitizeCache.js';
@@ -0,0 +1,87 @@
1
+ /*
2
+ * Copyright 2026 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ // internals is not part of MSAL's public API — pin @azure/msal-node tightly
14
+ // and revisit if Deserializer is ever exposed publicly.
15
+ import { internals } from '@azure/msal-node';
16
+
17
+ /**
18
+ * Derives the canonical MSAL cache key for a refresh token, matching the
19
+ * format used by MSAL's internal serializer: segments are joined with `-` and
20
+ * lowercased. Empty realm, target, and tokenType segments are included to keep
21
+ * the key structure consistent with all other credential types.
22
+ *
23
+ * @param {object} refreshToken deserialized MSAL refresh-token entry
24
+ * @param {string} refreshToken.homeAccountId account identifier
25
+ * @param {string} refreshToken.environment authority host (e.g. `login.microsoftonline.com`)
26
+ * @param {string} refreshToken.credentialType always `"RefreshToken"` for this entry type
27
+ * @param {string} [refreshToken.familyId] family ID for first-party apps; takes precedence over
28
+ * clientId
29
+ * @param {string} refreshToken.clientId application client ID
30
+ * @returns {string} lowercase hyphen-joined cache key
31
+ */
32
+ function generateKey(refreshToken) {
33
+ const {
34
+ homeAccountId, environment, credentialType, familyId, clientId,
35
+ } = refreshToken;
36
+ const credentialKey = [
37
+ homeAccountId,
38
+ environment,
39
+ credentialType,
40
+ familyId || clientId, // first-party apps share a family token; fall back to clientId
41
+ '', // realm
42
+ '', // target
43
+ '', // tokenType
44
+ ];
45
+ return credentialKey.join('-').toLowerCase();
46
+ }
47
+
48
+ /**
49
+ * Removes refresh-token entries whose cache key no longer matches the key that
50
+ * MSAL would generate for them today. This repairs caches that were written by
51
+ * an older MSAL version using a different key scheme.
52
+ *
53
+ * Mutates {@link data}.RefreshToken in place.
54
+ *
55
+ * If all tokens are outdated the cache is left untouched and a warning is
56
+ * logged, because wiping every token would sign out all active sessions.
57
+ *
58
+ * @param {object} data raw MSAL serialized cache (JSON-parsed)
59
+ * @param {{ info: Function, warn: Function }} log logger instance
60
+ */
61
+ export function sanitizeCache(data, log) {
62
+ const deserialized = internals.Deserializer.deserializeAllCache(data);
63
+ const { refreshTokens } = deserialized;
64
+
65
+ const outdatedKeys = [];
66
+ for (const [actualKey, refreshToken] of Object.entries(refreshTokens)) {
67
+ const expectedKey = generateKey(refreshToken);
68
+ if (actualKey !== expectedKey) {
69
+ outdatedKeys.push(actualKey);
70
+ }
71
+ }
72
+ if (outdatedKeys.length === 0) {
73
+ return;
74
+ }
75
+
76
+ // If every token is outdated the key scheme itself probably changed; removing
77
+ // them all would revoke all sessions, so bail out and let the caller decide.
78
+ if (Object.keys(refreshTokens).length === outdatedKeys.length) {
79
+ log.warn('All refresh tokens have an unexpected key, generation might have changed.');
80
+ return;
81
+ }
82
+
83
+ for (const key of outdatedKeys) {
84
+ delete data.RefreshToken[key];
85
+ log.info(`Removed RefreshToken with key: ${key}`);
86
+ }
87
+ }