Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: provide support for plugin metadata #823

Merged
merged 2 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions packages/helix-shared-tokencache/src/CachePlugin.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2022 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import { ICachePlugin, TokenCacheContext } from '@azure/msal-node';

export declare interface CachePlugin extends ICachePlugin {

afterCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;

beforeCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;

deleteCache(): Promise<void>;

location: string;

/**
* gets plugin metadata.
* @returns the plugin metadata
*/
getPluginMetadata(): Promise<object>;

/**
* sets the plugin metadata.
* @param meta
*/
setPluginMetadata(meta): Promise<void>;
}
13 changes: 2 additions & 11 deletions packages/helix-shared-tokencache/src/FSCachePlugin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,14 @@
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import { ICachePlugin, TokenCacheContext } from '@azure/msal-node';

import { Logger } from "../OneDrive";
import { CachePlugin } from './CachePlugin';

export declare interface FSCachePluginOptions {
log: Console;
filePath: string;
}

export declare class FSCachePlugin implements ICachePlugin {
export declare class FSCachePlugin implements CachePlugin {
constructor(opts: FSCachePluginOptions);

deleteCache(): Promise<void>;

afterCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;

beforeCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;

location: string;
}
69 changes: 58 additions & 11 deletions packages/helix-shared-tokencache/src/FSCachePlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ export class FSCachePlugin {
constructor(opts) {
this.filePath = opts.filePath;
this.log = opts.log || console;
this.meta = null;
this.data = null;
}

async deleteCache() {
this.data = null;
this.meta = null;
try {
await fs.rm(this.filePath);
} catch (e) {
Expand All @@ -38,34 +42,77 @@ export class FSCachePlugin {
}
}

/**
* @param {TokenCacheContext} cacheContext
* @returns {Promise<boolean>} if cache was updated
*/
async beforeCacheAccess(cacheContext) {
async #loadData() {
const { log, filePath } = this;
try {
cacheContext.tokenCache.deserialize(await fs.readFile(filePath, 'utf-8'));
return true;
let raw = await fs.readFile(filePath, 'utf-8');
const data = JSON.parse(raw);
if (data.cachePluginMetadata) {
this.meta = data.cachePluginMetadata;
delete data.cachePluginMetadata;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove cachePluginMetadata after load, so not to confuse the MSAL cache

raw = JSON.stringify(data);
} else {
this.meta = {};
}
this.data = data;
return raw;
} catch (e) {
if (e.code !== 'ENOENT') {
// only log warnings if file exists, otherwise ignore
log.warn('FSCachePlugin: unable to deserialize', e);
}
}
this.data = null;
return null;
}

async #saveData() {
const { filePath } = this;
const data = this.data || {};
if (Object.keys(this.meta || {}).length) {
data.cachePluginMetadata = this.meta;
tripodsan marked this conversation as resolved.
Show resolved Hide resolved
}
const raw = JSON.stringify(data, null, 2);
delete data.cachePluginMetadata;
await fs.writeFile(filePath, raw, 'utf-8');
}

/**
* @param {TokenCacheContext} cacheContext
* @returns {Promise<boolean>} if cache was updated
*/
async beforeCacheAccess(cacheContext) {
const raw = await this.#loadData();
if (raw) {
cacheContext.tokenCache.deserialize(raw);
return true;
}
return false;
}

async getPluginMetadata() {
if (!this.meta) {
await this.#loadData();
}
return this.meta;
}

async setPluginMetadata(meta) {
if (!this.data) {
await this.#loadData();
}
this.meta = meta || {};
await this.#saveData();
}

/**
* @param {TokenCacheContext} cacheContext
* @returns {Promise<boolean>} if cache was updated
*/
async afterCacheAccess(cacheContext) {
const { filePath } = this;
if (cacheContext.cacheHasChanged) {
// reparse and create a nice formatted JSON
const tokens = JSON.parse(cacheContext.tokenCache.serialize());
await fs.writeFile(filePath, JSON.stringify(tokens, null, 2), 'utf-8');
this.data = JSON.parse(cacheContext.tokenCache.serialize());
await this.#saveData();
return true;
}
return false;
Expand Down
15 changes: 3 additions & 12 deletions packages/helix-shared-tokencache/src/MemCachePlugin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,19 @@
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import { ICachePlugin, TokenCacheContext } from '@azure/msal-node';

import { Logger } from "../OneDrive";
import {CachePlugin} from "./CachePlugin";

export declare interface MemCachePluginOptions {
log: Console;
/**
* memory cache key
*/
key: string;
base: ICachePlugin;
base: CachePlugin;
caches?: Map<string, any>;
}

export declare class MemCachePlugin implements ICachePlugin {
export declare class MemCachePlugin implements CachePlugin {
constructor(opts: MemCachePluginOptions);

deleteCache(): Promise<void>;

afterCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;

beforeCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;

location: string;
}
34 changes: 29 additions & 5 deletions packages/helix-shared-tokencache/src/MemCachePlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,31 @@ export class MemCachePlugin {
}
}

#getOrCreateCache() {
let cache = this.caches.get(this.key);
if (!cache) {
cache = {};
this.caches.set(this.key, cache);
}
return cache;
}

/**
* @param {TokenCacheContext} cacheContext
*/
async beforeCacheAccess(cacheContext) {
try {
this.log.debug('mem: read token cache', this.key);
const cache = this.caches.get(this.key);
if (cache) {
cacheContext.tokenCache.deserialize(cache);
const cache = this.#getOrCreateCache();
if (cache.data) {
cacheContext.tokenCache.deserialize(cache.data);
return true;
} else if (this.base) {
this.log.debug('mem: read token cache failed. asking base');
const ret = await this.base.beforeCacheAccess(cacheContext);
if (ret) {
this.log.debug('mem: base updated. remember.');
this.caches.set(this.key, cacheContext.tokenCache.serialize());
cache.data = cacheContext.tokenCache.serialize();
}
return ret;
}
Expand All @@ -76,7 +85,8 @@ export class MemCachePlugin {
async afterCacheAccess(cacheContext) {
if (cacheContext.cacheHasChanged) {
this.log.debug('mem: write token cache', this.key);
this.caches.set(this.key, cacheContext.tokenCache.serialize());
const cache = this.#getOrCreateCache();
cache.data = cacheContext.tokenCache.serialize();
if (this.base) {
this.log.debug('mem: write token cache done. telling base', this.key);
return this.base.afterCacheAccess(cacheContext);
Expand All @@ -89,4 +99,18 @@ export class MemCachePlugin {
get location() {
return this.base ? this.base.location : this.key;
}

async getPluginMetadata() {
const cache = this.#getOrCreateCache();
if (!cache.metadata && this.base) {
cache.metadata = await this.base.getPluginMetadata();
}
return cache.metadata;
}

async setPluginMetadata(meta) {
const cache = this.#getOrCreateCache();
cache.metadata = meta;
await this.base?.setPluginMetadata(meta);
}
}
14 changes: 2 additions & 12 deletions packages/helix-shared-tokencache/src/S3CachePlugin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import { ICachePlugin, TokenCacheContext } from '@azure/msal-node';

import { Logger } from "../OneDrive";
import {CachePlugin} from "./CachePlugin";

export declare interface S3CachePluginOptions {
log: Console;
Expand All @@ -20,7 +18,7 @@ export declare interface S3CachePluginOptions {
secret: string;
}

export declare class S3CachePlugin implements ICachePlugin {
export declare class S3CachePlugin implements CachePlugin {
/**
* Decrypts a AES-GCM encrypted digest.
* @param {string} key encryption key / password
Expand All @@ -40,12 +38,4 @@ export declare class S3CachePlugin implements ICachePlugin {
static decrypt(key: string, data: Buffer):Buffer;

constructor(opts: S3CachePluginOptions);

deleteCache(): Promise<void>;

location: string;

afterCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;

beforeCacheAccess(tokenCacheContext: TokenCacheContext): Promise<boolean>;
}
Loading