@adobe/helix-onedrive-support 9.1.32 → 10.0.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,15 @@
1
+ # [10.0.0](https://github.com/adobe/helix-onedrive-support/compare/v9.1.32...v10.0.0) (2023-05-02)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * use helix-shared-tokencache ([#373](https://github.com/adobe/helix-onedrive-support/issues/373)) ([d6d2ab0](https://github.com/adobe/helix-onedrive-support/commit/d6d2ab0bce1987ad4f46d3a5e84d986dff1c54b2))
7
+
8
+
9
+ ### BREAKING CHANGES
10
+
11
+ * token cache moved to @adobe/helix-shared-tokencache
12
+
1
13
  ## [9.1.32](https://github.com/adobe/helix-onedrive-support/compare/v9.1.31...v9.1.32) (2023-04-29)
2
14
 
3
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/helix-onedrive-support",
3
- "version": "9.1.32",
3
+ "version": "10.0.0",
4
4
  "description": "Helix OneDrive Support",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -28,6 +28,7 @@
28
28
  "homepage": "https://github.com/adobe/helix-onedrive-support#readme",
29
29
  "dependencies": {
30
30
  "@adobe/fetch": "4.0.10",
31
+ "@adobe/helix-shared-tokencache": "1.0.0",
31
32
  "@aws-sdk/client-s3": "3.321.1",
32
33
  "@azure/msal-node": "1.17.1",
33
34
  "jose": "4.14.3"
@@ -13,8 +13,8 @@
13
13
  // eslint-disable-next-line max-classes-per-file
14
14
  import { keepAliveNoCache } from '@adobe/fetch';
15
15
  import { ConfidentialClientApplication, LogLevel, PublicClientApplication } from '@azure/msal-node';
16
+ import { MemCachePlugin } from '@adobe/helix-shared-tokencache';
16
17
  import { decodeJwt } from 'jose';
17
- import { MemCachePlugin } from './cache/MemCachePlugin.js';
18
18
 
19
19
  const AZ_AUTHORITY_HOST_URL = 'https://login.windows.net';
20
20
  const AZ_COMMON_TENANT = 'common';
package/src/index.d.ts CHANGED
@@ -18,9 +18,3 @@ export * from './excel/Worksheet';
18
18
  export * from './excel/NamedItem';
19
19
  export * from './excel/Table';
20
20
  export * from './excel/Range';
21
-
22
- export * from './cache/FSCacheManager';
23
- export * from './cache/FSCachePlugin';
24
- export * from './cache/MemCachePlugin';
25
- export * from './cache/S3CacheManager';
26
- export * from './cache/S3CachePlugin';
package/src/index.js CHANGED
@@ -12,11 +12,6 @@
12
12
  export { OneDrive } from './OneDrive.js';
13
13
  export { OneDriveAuth, AcquireMethod } from './OneDriveAuth.js';
14
14
 
15
- export { FSCachePlugin } from './cache/FSCachePlugin.js';
16
- export { FSCacheManager } from './cache/FSCacheManager.js';
17
- export { MemCachePlugin } from './cache/MemCachePlugin.js';
18
- export { S3CachePlugin } from './cache/S3CachePlugin.js';
19
- export { S3CacheManager } from './cache/S3CacheManager.js';
20
15
  export { OneDriveMock } from './OneDriveMock.js';
21
16
  export { StatusCodeError } from './StatusCodeError.js';
22
17
 
@@ -1,28 +0,0 @@
1
- /*
2
- * Copyright 2022 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
- import { FSCachePlugin } from "./FSCachePlugin";
13
-
14
- export declare interface FSCacheManagerOptions {
15
- log: Console;
16
- dirPath: string;
17
- type: string;
18
- }
19
-
20
- export declare class FSCacheManager {
21
- constructor(opts: FSCacheManagerOptions);
22
-
23
- listCacheKeys():Promise<string[]>;
24
-
25
- hasCache(key:string):Promise<boolean>;
26
-
27
- getCache(key:string):Promise<FSCachePlugin>;
28
- }
@@ -1,77 +0,0 @@
1
- /*
2
- * Copyright 2022 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
- import fs from 'fs/promises';
13
- import path from 'path';
14
- import { FSCachePlugin } from './FSCachePlugin.js';
15
-
16
- /**
17
- * aliases
18
- * @typedef {import("@azure/msal-node").ICachePlugin} ICachePlugin
19
- * @typedef {import("@azure/msal-node").TokenCacheContext} TokenCacheContext
20
- */
21
-
22
- export class FSCacheManager {
23
- constructor(opts) {
24
- this.dirPath = opts.dirPath;
25
- this.log = opts.log || console;
26
- this.type = opts.type;
27
- }
28
-
29
- getCacheFilePath(key) {
30
- return path.resolve(this.dirPath, `auth-${this.type}-${key}.json`);
31
- }
32
-
33
- async listCacheKeys() {
34
- try {
35
- const files = await fs.readdir(this.dirPath);
36
- return files
37
- .filter((name) => (name.startsWith('auth-') && name.endsWith('.json')))
38
- .map((name) => name.replace(/auth-([a-z0-9]+)-([a-z0-9]+).json/i, '$2'));
39
- } catch (e) {
40
- if (e.code === 'ENOENT') {
41
- return [];
42
- }
43
- throw e;
44
- }
45
- }
46
-
47
- async hasCache(key) {
48
- try {
49
- await fs.lstat(this.getCacheFilePath(key));
50
- return true;
51
- } catch (e) {
52
- if (e.code !== 'ENOENT') {
53
- throw e;
54
- }
55
- return false;
56
- }
57
- }
58
-
59
- /**
60
- * @param key
61
- * @returns {FSCachePlugin}
62
- */
63
- async getCache(key) {
64
- try {
65
- await fs.lstat(this.dirPath);
66
- } catch (e) {
67
- if (e.code !== 'ENOENT') {
68
- throw e;
69
- }
70
- await fs.mkdir(this.dirPath);
71
- }
72
- return new FSCachePlugin({
73
- log: this.log,
74
- filePath: this.getCacheFilePath(key),
75
- });
76
- }
77
- }
@@ -1,29 +0,0 @@
1
- /*
2
- * Copyright 2022 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
- import { ICachePlugin, TokenCacheContext } from '@azure/msal-node';
13
-
14
- import { Logger } from "../OneDrive";
15
-
16
- export declare interface FSCachePluginOptions {
17
- log: Console;
18
- filePath: string;
19
- }
20
-
21
- export declare class FSCachePlugin implements ICachePlugin {
22
- constructor(opts: FSCachePluginOptions);
23
-
24
- deleteCache(): Promise<void>;
25
-
26
- afterCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;
27
-
28
- beforeCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;
29
- }
@@ -1,73 +0,0 @@
1
- /*
2
- * Copyright 2022 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
- import fs from 'fs/promises';
13
-
14
- /**
15
- * aliases
16
- * @typedef {import("@azure/msal-node").ICachePlugin} ICachePlugin
17
- * @typedef {import("@azure/msal-node").TokenCacheContext} TokenCacheContext
18
- */
19
-
20
- /**
21
- * Cache plugin for MSAL
22
- * @param {FSCachePluginOptions} opts
23
- * @class FSCachePlugin
24
- * @implements ICachePlugin
25
- */
26
- export class FSCachePlugin {
27
- constructor(opts) {
28
- this.filePath = opts.filePath;
29
- this.log = opts.log || console;
30
- }
31
-
32
- async deleteCache() {
33
- try {
34
- await fs.rm(this.filePath);
35
- } catch (e) {
36
- this.log.warn(`error deleting cache: ${e.message}`);
37
- // ignore
38
- }
39
- }
40
-
41
- /**
42
- * @param {TokenCacheContext} cacheContext
43
- * @returns {Promise<boolean>} if cache was updated
44
- */
45
- async beforeCacheAccess(cacheContext) {
46
- const { log, filePath } = this;
47
- try {
48
- cacheContext.tokenCache.deserialize(await fs.readFile(filePath, 'utf-8'));
49
- return true;
50
- } catch (e) {
51
- if (e.code !== 'ENOENT') {
52
- // only log warnings if file exists, otherwise ignore
53
- log.warn('FSCachePlugin: unable to deserialize', e);
54
- }
55
- }
56
- return false;
57
- }
58
-
59
- /**
60
- * @param {TokenCacheContext} cacheContext
61
- * @returns {Promise<boolean>} if cache was updated
62
- */
63
- async afterCacheAccess(cacheContext) {
64
- const { filePath } = this;
65
- if (cacheContext.cacheHasChanged) {
66
- // reparse and create a nice formatted JSON
67
- const tokens = JSON.parse(cacheContext.tokenCache.serialize());
68
- await fs.writeFile(filePath, JSON.stringify(tokens, null, 2), 'utf-8');
69
- return true;
70
- }
71
- return false;
72
- }
73
- }
@@ -1,34 +0,0 @@
1
- /*
2
- * Copyright 2022 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
- import { ICachePlugin, TokenCacheContext } from '@azure/msal-node';
13
-
14
- import { Logger } from "../OneDrive";
15
-
16
- export declare interface MemCachePluginOptions {
17
- log: Console;
18
- /**
19
- * memory cache key
20
- */
21
- key: string;
22
- base: ICachePlugin;
23
- caches?: Map<string, any>;
24
- }
25
-
26
- export declare class MemCachePlugin implements ICachePlugin {
27
- constructor(opts: MemCachePluginOptions);
28
-
29
- deleteCache(): Promise<void>;
30
-
31
- afterCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;
32
-
33
- beforeCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;
34
- }
@@ -1,88 +0,0 @@
1
- /*
2
- * Copyright 2022 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
- const caches = new Map();
13
-
14
- /**
15
- * aliases
16
- * @typedef {import("@azure/msal-node").ICachePlugin} ICachePlugin
17
- * @typedef {import("@azure/msal-node").TokenCacheContext} TokenCacheContext
18
- */
19
-
20
- /**
21
- * Cache plugin for MSAL
22
- * @class MemCachePlugin
23
- * @implements ICachePlugin
24
- */
25
- export class MemCachePlugin {
26
- /**
27
- * @param {MemCachePluginOptions} opts
28
- */
29
- constructor(opts = {}) {
30
- this.log = opts.log || console;
31
- this.key = opts.key;
32
- this.base = opts.base;
33
- this.caches = opts.caches || caches;
34
- }
35
-
36
- clear() {
37
- this.caches.clear();
38
- }
39
-
40
- async deleteCache() {
41
- this.log.debug('mem: delete token cache', this.key);
42
- this.caches.delete(this.key);
43
- if (this.base) {
44
- await this.base.deleteCache();
45
- }
46
- }
47
-
48
- /**
49
- * @param {TokenCacheContext} cacheContext
50
- */
51
- async beforeCacheAccess(cacheContext) {
52
- try {
53
- this.log.debug('mem: read token cache', this.key);
54
- const cache = this.caches.get(this.key);
55
- if (cache) {
56
- cacheContext.tokenCache.deserialize(cache);
57
- return true;
58
- } else if (this.base) {
59
- this.log.debug('mem: read token cache failed. asking base');
60
- const ret = await this.base.beforeCacheAccess(cacheContext);
61
- if (ret) {
62
- this.log.debug('mem: base updated. remember.');
63
- this.caches.set(this.key, cacheContext.tokenCache.serialize());
64
- }
65
- return ret;
66
- }
67
- } catch (e) {
68
- this.log.warn('mem: unable to deserialize token cache.', e);
69
- }
70
- return false;
71
- }
72
-
73
- /**
74
- * @param {TokenCacheContext} cacheContext
75
- */
76
- async afterCacheAccess(cacheContext) {
77
- if (cacheContext.cacheHasChanged) {
78
- this.log.debug('mem: write token cache', this.key);
79
- this.caches.set(this.key, cacheContext.tokenCache.serialize());
80
- if (this.base) {
81
- this.log.debug('mem: write token cache done. telling base', this.key);
82
- return this.base.afterCacheAccess(cacheContext);
83
- }
84
- return true;
85
- }
86
- return false;
87
- }
88
- }
@@ -1,40 +0,0 @@
1
- /*
2
- * Copyright 2022 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
- import { S3CachePlugin } from "./FSCachePlugin";
13
-
14
- export declare interface S3CacheManagerOptions {
15
- log: Console;
16
- type: string;
17
- bucket: string;
18
- prefix: string;
19
- secret: string;
20
- }
21
-
22
- export declare class S3CacheManager {
23
- /**
24
- * Find the first cache with the given opts, that exists, otherwise the plugin using the
25
- * default options is returned.
26
- * @param {string} key
27
- * @param {object} defaultOpts
28
- * @param {object} opts
29
- * @returns {Promise<S3CachePlugin>}
30
- */
31
- static findCache(key:string, defaultOpts:S3CacheManagerOptions, ...opts:S3CacheManagerOptions[]):Promise<S3CachePlugin>;
32
-
33
- constructor(opts: S3CacheManagerOptions);
34
-
35
- listCacheKeys():Promise<string[]>;
36
-
37
- hasCache(key:string):Promise<boolean>;
38
-
39
- getCache(key:string):Promise<S3CachePlugin>;
40
- }
@@ -1,107 +0,0 @@
1
- /*
2
- * Copyright 2022 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
- import { basename } from 'path';
13
- import { HeadObjectCommand, ListObjectsV2Command, S3Client } from '@aws-sdk/client-s3';
14
- import { S3CachePlugin } from './S3CachePlugin.js';
15
-
16
- /**
17
- * aliases
18
- * @typedef {import("@azure/msal-node").ICachePlugin} ICachePlugin
19
- * @typedef {import("@azure/msal-node").TokenCacheContext} TokenCacheContext
20
- */
21
-
22
- export class S3CacheManager {
23
- /**
24
- * Find the first cache with the given opts, that exists, otherwise the plugin using the
25
- * default options is returned.
26
- * @param {string} key
27
- * @param {object} defaultOpts
28
- * @param {object} opts
29
- * @returns {Promise<S3CachePlugin>}
30
- */
31
- static async findCache(key, defaultOpts, ...opts) {
32
- for (const opt of opts) {
33
- const cacheManager = new S3CacheManager({
34
- ...defaultOpts,
35
- ...opt,
36
- });
37
- // eslint-disable-next-line no-await-in-loop
38
- if (await cacheManager.hasCache(key)) {
39
- return cacheManager.getCache(key);
40
- }
41
- }
42
- return new S3CacheManager(defaultOpts).getCache(key);
43
- }
44
-
45
- constructor(opts) {
46
- this.log = opts.log || console;
47
- this.bucket = opts.bucket;
48
- this.prefix = opts.prefix;
49
- this.secret = opts.secret;
50
- this.type = opts.type;
51
- this.s3 = new S3Client();
52
- }
53
-
54
- getAuthObjectKey(key) {
55
- return `${this.prefix}/auth-${this.type}-${key}.json`;
56
- }
57
-
58
- async listCacheKeys() {
59
- const {
60
- log, s3, bucket, prefix,
61
- } = this;
62
- log.debug('s3: list token cache', prefix);
63
- try {
64
- const res = await s3.send(new ListObjectsV2Command({
65
- Bucket: bucket,
66
- Prefix: `${prefix}/`,
67
- }));
68
- return (res.Contents || [])
69
- .map((entry) => basename(entry.Key))
70
- .filter((name) => (name.startsWith(`auth-${this.type}-`) && name.endsWith('.json')))
71
- .map((name) => name.replace(/auth-([a-z0-9]+)-([a-z0-9]+).json/i, '$2'));
72
- } catch (e) {
73
- log.info('s3: unable to list token caches', e);
74
- return [];
75
- }
76
- }
77
-
78
- async hasCache(key) {
79
- const { log, bucket } = this;
80
- try {
81
- await this.s3.send(new HeadObjectCommand({
82
- Bucket: bucket,
83
- Key: this.getAuthObjectKey(key),
84
- }));
85
- return true;
86
- } catch (e) {
87
- if (e.$metadata?.httpStatusCode !== 404) {
88
- log.warn('s3: unable to check token cache', e);
89
- throw e;
90
- }
91
- return false;
92
- }
93
- }
94
-
95
- /**
96
- * @param key
97
- * @returns {S3CachePlugin}
98
- */
99
- async getCache(key) {
100
- return new S3CachePlugin({
101
- log: this.log,
102
- key: this.getAuthObjectKey(key),
103
- secret: this.secret,
104
- bucket: this.bucket,
105
- });
106
- }
107
- }
@@ -1,49 +0,0 @@
1
- /*
2
- * Copyright 2022 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
- import { ICachePlugin, TokenCacheContext } from '@azure/msal-node';
13
-
14
- import { Logger } from "../OneDrive";
15
-
16
- export declare interface S3CachePluginOptions {
17
- log: Console;
18
- bucket: string;
19
- key: string;
20
- secret: string;
21
- }
22
-
23
- export declare class S3CachePlugin implements ICachePlugin {
24
- /**
25
- * Decrypts a AES-GCM encrypted digest.
26
- * @param {string} key encryption key / password
27
- * @param {Buffer} data the encrypted data
28
- * @returns {Buffer} the plain text
29
- * @throws an error if the given key cannot decrypt the digest.
30
- */
31
- static encrypt(key:string, data:Buffer):Buffer;
32
-
33
- /**
34
- * Decrypts a AES-GCM encrypted digest.
35
- * @param {string} key encryption key / password
36
- * @param {Buffer} data the encrypted data
37
- * @returns {Buffer} the plain text
38
- * @throws an error if the given key cannot decrypt the digest.
39
- */
40
- static decrypt(key: string, data: Buffer):Buffer;
41
-
42
- constructor(opts: S3CachePluginOptions);
43
-
44
- deleteCache(): Promise<void>;
45
-
46
- afterCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;
47
-
48
- beforeCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;
49
- }
@@ -1,116 +0,0 @@
1
- /*
2
- * Copyright 2021 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
- import {
13
- DeleteObjectCommand,
14
- GetObjectCommand,
15
- PutObjectCommand,
16
- S3Client,
17
- } from '@aws-sdk/client-s3';
18
- import { Response } from '@adobe/fetch';
19
- import { decrypt, encrypt } from './encrypt.js';
20
-
21
- /**
22
- * aliases
23
- * @typedef {import("@azure/msal-node").ICachePlugin} ICachePlugin
24
- * @typedef {import("@azure/msal-node").TokenCacheContext} TokenCacheContext
25
- */
26
-
27
- /**
28
- * Cache plugin for MSAL
29
- * @class MemCachePlugin
30
- * @implements ICachePlugin
31
- */
32
- export class S3CachePlugin {
33
- /**
34
- * @param {S3CachePluginOptions} opts
35
- */
36
- constructor(opts) {
37
- this.log = opts.log || console;
38
- this.bucket = opts.bucket;
39
- this.key = opts.key;
40
- this.secret = opts.secret;
41
- this.s3 = new S3Client();
42
- }
43
-
44
- async deleteCache() {
45
- const { log, key, bucket } = this;
46
- try {
47
- log.debug('s3: read token cache', key);
48
- await this.s3.send(new DeleteObjectCommand({
49
- Bucket: bucket,
50
- Key: key,
51
- }));
52
- } catch (e) {
53
- if (e.$metadata?.httpStatusCode === 404) {
54
- log.info('s3: unable to deserialize token cache: not found');
55
- } else {
56
- log.warn('s3: unable to deserialize token cache', e);
57
- }
58
- }
59
- }
60
-
61
- async beforeCacheAccess(cacheContext) {
62
- const {
63
- log, secret, key, bucket,
64
- } = this;
65
- try {
66
- log.debug('s3: read token cache', key);
67
- const res = await this.s3.send(new GetObjectCommand({
68
- Bucket: bucket,
69
- Key: key,
70
- }));
71
- let data = await new Response(res.Body, {}).buffer();
72
- if (secret) {
73
- data = decrypt(secret, data).toString('utf-8');
74
- } else {
75
- data = data.toString('utf-8');
76
- }
77
- cacheContext.tokenCache.deserialize(data);
78
- return true;
79
- } catch (e) {
80
- if (e.$metadata?.httpStatusCode === 404) {
81
- log.info('s3: unable to deserialize token cache: not found');
82
- } else {
83
- log.warn('s3: unable to deserialize token cache', e);
84
- }
85
- }
86
- return false;
87
- }
88
-
89
- async afterCacheAccess(cacheContext) {
90
- if (cacheContext.cacheHasChanged) {
91
- const {
92
- log, secret, key, bucket,
93
- } = this;
94
- try {
95
- log.debug('s3: write token cache', key);
96
- let data = cacheContext.tokenCache.serialize();
97
- if (secret) {
98
- data = encrypt(secret, Buffer.from(data, 'utf-8'));
99
- }
100
- await this.s3.send(new PutObjectCommand({
101
- Bucket: bucket,
102
- Key: key,
103
- Body: data,
104
- ContentType: secret ? 'application/octet-stream' : 'text/plain',
105
- }));
106
- return true;
107
- } catch (e) {
108
- log.warn('s3: unable to serialize token cache', e);
109
- }
110
- }
111
- return false;
112
- }
113
- }
114
-
115
- S3CachePlugin.encrypt = encrypt;
116
- S3CachePlugin.decrypt = decrypt;
@@ -1,70 +0,0 @@
1
- /*
2
- * Copyright 2021 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
- import crypto from 'crypto';
13
-
14
- const ALGO = 'aes-256-gcm';
15
- const SALT_SIZE = 8;
16
- const IV_SIZE = 12;
17
- const AUTH_TAG_SIZE = 16;
18
-
19
- function deriveKey(key, salt) {
20
- return crypto.pbkdf2Sync(key, salt, 10000, 32, 'sha512');
21
- }
22
-
23
- /**
24
- * Provides an AES-GCM symmetric encryption using a key derivation from a generic password.
25
- * The resulting string is a base64 encoded buffer of the salt, iv, auth and encrypted text.
26
- * Using GCM has the advantage over plain AES, that the validity of the key can be verified.
27
- * (similar to a AES + HMAC approach).
28
- *
29
- * result = base64( salt | iv | auth | enc )
30
- *
31
- * @param {string} key encryption key / password
32
- * @param {Buffer} plain Plain text to encrypt
33
- * @return {Buffer} digest.
34
- */
35
- export function encrypt(key, plain) {
36
- const salt = crypto.randomBytes(SALT_SIZE);
37
- const iv = crypto.randomBytes(IV_SIZE);
38
- const derivedKey = deriveKey(key, salt);
39
- const cipher = crypto.createCipheriv(ALGO, derivedKey, iv);
40
-
41
- const data = [salt, iv, null];
42
- data.push(cipher.update(plain));
43
- data.push(cipher.final());
44
- data[2] = cipher.getAuthTag();
45
- return Buffer.concat(data);
46
- }
47
-
48
- /**
49
- * Decrypts a AES-GCM encrypted digest.
50
- * @param {string} key encryption key / password
51
- * @param {Buffer} data the encrypted data
52
- * @returns {Buffer} the plain text
53
- * @throws an error if the given key cannot decrypt the digest.
54
- */
55
- export function decrypt(key, data) {
56
- const salt = data.slice(0, SALT_SIZE);
57
- const iv = data.slice(SALT_SIZE, SALT_SIZE + IV_SIZE);
58
- const authTag = data.slice(SALT_SIZE + IV_SIZE, SALT_SIZE + IV_SIZE + AUTH_TAG_SIZE);
59
- const enc = data.slice(SALT_SIZE + IV_SIZE + AUTH_TAG_SIZE);
60
-
61
- const derivedKey = deriveKey(key, salt);
62
- const decipher = crypto.createDecipheriv(ALGO, derivedKey, iv);
63
- decipher.setAuthTag(authTag);
64
-
65
- const ret = [
66
- decipher.update(enc),
67
- decipher.final(),
68
- ];
69
- return Buffer.concat(ret);
70
- }