import { Disposable } from '@typed/disposable' ; import { Effect , orFail } from '@typed/effects' ; import { Future } from '@typed/future' ; import { ArgsOf } from '@typed/lambda' ; import { debug , time } from '@typed/logger' ; import { CryptoEffects , CryptoFailure } from '../common' ; import { getSubtleCrypto } from './getSubtleCrypto' ; export const decrypt = createCryptoEffect ( 'decrypt' ) ; export const deriveBits = createCryptoEffect ( 'deriveBits' ) ; export const deriveKey = createCryptoEffect ( 'deriveKey' ) ; export const digest = createCryptoEffect ( 'digest' ) ; export const encrypt = createCryptoEffect ( 'encrypt' ) ; export const exportKey = createCryptoEffect ( 'exportKey' ) as { ( format , key ) : CryptoEffects < unknown , JsonWebKey > ; ( format , key ) : CryptoEffects < unknown , ArrayBuffer > ; ( format , key ) : CryptoEffects < unknown , ArrayBuffer | JsonWebKey > ; } ; export const generateKey = createCryptoEffect ( 'generateKey' ) as { ( algorithm , extractable , keyUsages ) : CryptoEffects < unknown , CryptoKey | CryptoKeyPair > ; ( algorithm , extractable , keyUsages ) : CryptoEffects < unknown , CryptoKeyPair > ; ( algorithm , extractable , keyUsages ) : CryptoEffects < unknown , CryptoKey > ; } ; export const importKey = createCryptoEffect ( 'importKey' ) as { ( format , keyData , algorithm , extractable , keyUsages ) : CryptoEffects < unknown , CryptoKey > ; ( format , keyData , algorithm , extractable , keyUsages ) : CryptoEffects < unknown , CryptoKey > ; ( format , keyData , algorithm , extractable , keyUsages ) : CryptoEffects < unknown , CryptoKey > ; } ; export const sign = createCryptoEffect ( 'sign' ) ; export const unwrapKey = createCryptoEffect ( 'unwrapKey' ) ; export const verify = createCryptoEffect ( 'verify' ) ; export const wrapKey = createCryptoEffect ( 'wrapKey' ) ; function createCryptoEffect < A extends keyof SubtleCrypto > ( key ) { let id = 0 ; return function * ( ... args ) : CryptoEffectFrom < A > { const label = `Crypto.subtle.${ key }${ id ++ }` ; const subtle = yield * getSubtleCrypto ( ) ; const fn = ( subtle [ key ] as any ) . bind ( subtle ) ; yield * debug ( `Running ${ label }...` ) ; const end = yield * time ( label ) ; const value = yield * orFail ( CryptoFailure , Effect . fromEnv ( fromPromise ( fn ( ... args ) ) ) ) ; yield * end ; return value ; } ; } export const fromPromise = < A > ( promise ) => Future . create < unknown , Error , A > ( ( reject , resolve ) => { const disposable = Disposable . lazy ( ) ; promise . then ( ( a ) => disposable . addDisposable ( resolve ( a ) ) , ( e ) => disposable . addDisposable ( reject ( e ) ) ) ; return disposable ; } ) ; type CryptoEffectFrom < A extends keyof SubtleCrypto > = CryptoEffects < unknown , PromiseValue < ReturnType < SubtleCrypto [ A ] > > > ; type PromiseValue < A > = A extends PromiseLike < infer R > ? R : never ;