Skip to content

Commit d1f5810

Browse files
committed
Add a connector as example, that saves passwords in local storage
1 parent 0531fbc commit d1f5810

File tree

4 files changed

+57
-6
lines changed

4 files changed

+57
-6
lines changed

src/connectors/local-storage.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { ISecret, ISecretsConnector } from '../token';
2+
3+
/**
4+
* Example connector that save the secrets to the local storage.
5+
*
6+
* WARNING: It should not be used in production, since the passwords are stored as plain
7+
* text in the local storage of the browser.
8+
*/
9+
export class LocalStorageConnector implements ISecretsConnector {
10+
storage = 'jupyter-secrets:secrets';
11+
12+
constructor() {
13+
console.warn(`
14+
The secret connector used currently should not be used in production, since the
15+
passwords are stored as plain text in the local storage of the browser'
16+
`);
17+
}
18+
async fetch(id: string): Promise<ISecret | undefined> {
19+
const secrets = JSON.parse(localStorage.getItem(this.storage) ?? '{}');
20+
if (!secrets || !secrets[id]) {
21+
return;
22+
}
23+
return secrets[id];
24+
}
25+
26+
async save(id: string, value: ISecret): Promise<any> {
27+
const secrets = JSON.parse(localStorage.getItem(this.storage) ?? '{}');
28+
secrets[id] = value;
29+
localStorage.setItem(this.storage, JSON.stringify(secrets));
30+
}
31+
32+
async remove(id: string): Promise<any> {
33+
const secrets = JSON.parse(localStorage.getItem(this.storage) ?? '{}');
34+
delete secrets[id];
35+
localStorage.setItem(this.storage, JSON.stringify(secrets));
36+
}
37+
38+
async list(
39+
query?: string | undefined
40+
): Promise<{ ids: string[]; values: ISecret[] }> {
41+
const secrets = JSON.parse(localStorage.getItem(this.storage) ?? '{}');
42+
return {
43+
ids: Object.keys(secrets).filter(key => secrets[key].namespace === query),
44+
values: []
45+
};
46+
}
47+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ const plugin: JupyterFrontEndPlugin<ISecretsManager> = {
2323
}
2424
};
2525

26+
export * from './connectors/local-storage';
2627
export * from './token';
2728
export default plugin;

src/manager.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,15 @@ export class SecretsManager implements ISecretsManager {
5858
}
5959
this._attachedInputs.set(attachedId, input);
6060

61-
// Fill the password if the input is empty and a value is fetched by the data
62-
// connector.
6361
input.dataset.secretsId = attachedId;
64-
const value = await this.get(attachedId);
65-
if (!input.value && value) {
66-
input.value = value.value;
62+
const secret = await this.get(attachedId);
63+
if (!input.value && secret) {
64+
// Fill the password if the input is empty and a value is fetched by the data
65+
// connector.
66+
input.value = secret.value;
67+
} else if (input.value && input.value !== secret?.value) {
68+
// Otherwise save the current input value using the data connector.
69+
this.set(attachedId, { namespace, id, value: input.value });
6770
}
6871
input.addEventListener('change', this._onchange);
6972
}

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@
2121
"target": "ES2018",
2222
"types": ["jest"]
2323
},
24-
"include": ["src/*"]
24+
"include": ["src/**/*"]
2525
}

0 commit comments

Comments
 (0)