A library for multi-key reversible encryption
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.
 

96 lines
3.1 KiB

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()),
}
}
}