generated from garrettmills/template-npm-typescript
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
3.1 KiB
97 lines
3.1 KiB
2 years ago
|
import {EncodedValue, KeyValue} from './types'
|
||
|
import {KeyPackage} from './KeyPackage'
|
||
|
import {Payload} from './Payload'
|
||
|
|
||
|
/** Interface for a JSON-serializable shared value. */
|
||
|
export interface SerializedSharedValue<T> {
|
||
|
value: EncodedValue,
|
||
|
envelopes: EncodedValue[],
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* A value that is shared and accessible by multiple encryption keys.
|
||
|
*/
|
||
|
export class SharedValue<T> {
|
||
|
/** The package of keys allowed to access the encoded value. */
|
||
|
public readonly package: KeyPackage
|
||
|
|
||
|
/**
|
||
|
* Create a new shared value.
|
||
|
* @param initialSharerKey - an initial key, used to give access to the encoded value
|
||
|
* @param value - the value to be encoded and shared
|
||
|
*/
|
||
|
public static async create<T>(initialSharerKey: KeyValue, value: T): Promise<SharedValue<T>> {
|
||
|
const keyPackage = await KeyPackage.fromInitialSharer(initialSharerKey)
|
||
|
const cryptor = await keyPackage.getCryptor(initialSharerKey)
|
||
|
const payload = new Payload<T>(value)
|
||
|
|
||
|
const serialized = {
|
||
|
value: await cryptor.encode(payload.encode()),
|
||
|
...(keyPackage.toJSON()),
|
||
|
}
|
||
|
|
||
|
return new SharedValue<T>(serialized)
|
||
|
}
|
||
|
|
||
|
constructor(
|
||
|
/** The serialized data for this shared value. */
|
||
|
private serialized: SerializedSharedValue<T>,
|
||
|
public readonly validator: (w: unknown) => w is T = (w: unknown): w is T => true,
|
||
|
) {
|
||
|
this.package = KeyPackage.fromJSON(serialized)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get a Payload instance of the decoded value.
|
||
|
* @param key - valid key to decode the payload
|
||
|
*/
|
||
|
async payload(key: KeyValue): Promise<Payload<T>> {
|
||
|
const cryptor = await this.package.getCryptor(key)
|
||
|
const decodedValue = await cryptor.decode(this.serialized.value)
|
||
|
return Payload.from<T>(decodedValue)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the value of this secret.
|
||
|
* @param key - valid key to decode the value
|
||
|
*/
|
||
|
async get(key: KeyValue): Promise<T> {
|
||
|
const payload = await this.payload(key)
|
||
|
const value = payload.value
|
||
|
if ( !this.validator(value) ) {
|
||
|
throw new TypeError('Invalid encoded value!')
|
||
|
}
|
||
|
|
||
|
return value
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set a new value for this secret.
|
||
|
* @param key - valid key to encode the value
|
||
|
* @param value - new value to encode
|
||
|
*/
|
||
|
async set(key: KeyValue, value: T): Promise<void> {
|
||
|
const cryptor = await this.package.getCryptor(key)
|
||
|
const payload = new Payload<T>(value)
|
||
|
this.serialized.value = await cryptor.encode(payload.encode())
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a new key to the key package for this shared value. This allows
|
||
|
* the `shareeKey` to access this shared value.
|
||
|
* @param sharerKey - a currently valid key
|
||
|
* @param shareeKey - the new key to add
|
||
|
*/
|
||
|
async addKey(sharerKey: KeyValue, shareeKey?: KeyValue): Promise<KeyValue> {
|
||
|
return this.package.addCryptor(sharerKey, shareeKey)
|
||
|
}
|
||
|
|
||
|
/** Serialize the shared value securely. */
|
||
|
toJSON(): SerializedSharedValue<T> {
|
||
|
return {
|
||
|
value: this.serialized.value,
|
||
|
...(this.package.toJSON()),
|
||
|
}
|
||
|
}
|
||
|
}
|