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.
108 lines
3.5 KiB
108 lines
3.5 KiB
import {EncodedKeyPackage, 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: EncodedKeyPackage,
|
|
}
|
|
|
|
/**
|
|
* 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 name - the name of the initial sharer's key
|
|
* @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>(name: string, initialSharerKey: KeyValue, value: T): Promise<SharedValue<T>> {
|
|
const keyPackage = await KeyPackage.fromInitialSharer(name, 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 shareeName - the name of the new key
|
|
* @param shareeKey - the new key to add
|
|
*/
|
|
async addKey(sharerKey: KeyValue, shareeName: string, shareeKey?: KeyValue): Promise<KeyValue> {
|
|
return this.package.addCryptor(sharerKey, shareeName, shareeKey)
|
|
}
|
|
|
|
/**
|
|
* Remove a given key from the key package.
|
|
* @param sharerKey
|
|
* @param shareeKey
|
|
*/
|
|
async removeKey(sharerKey: KeyValue, shareeName: string): Promise<void> {
|
|
await this.package.removeCryptor(sharerKey, shareeName)
|
|
}
|
|
|
|
/** Serialize the shared value securely. */
|
|
toJSON(): SerializedSharedValue<T> {
|
|
return {
|
|
value: this.serialized.value,
|
|
...(this.package.toJSON()),
|
|
}
|
|
}
|
|
}
|