@icure/cardinal-prescription-be-react
Version:
This is a Belgian-specific React application for healthcare professionals to manage electronic prescriptions with SAM. Created by iCure.
107 lines (93 loc) • 3.4 kB
text/typescript
import { IndexedDbServiceStore } from '../indexed-db'
import { CertificateRecordType } from '../../types'
import { CERTIFICATE_IDB_CONFIG } from '../constants'
const certificateStore = new IndexedDbServiceStore<CertificateRecordType>(CERTIFICATE_IDB_CONFIG)
export const loadCertificateInformation = async (
hcp_ssin: string,
): Promise<
| {
salt: ArrayBuffer
iv: ArrayBuffer
encryptedCertificate: ArrayBuffer
}
| undefined
> => {
try {
const record = await certificateStore.get(hcp_ssin)
return {
salt: new Uint8Array(record.salt).buffer,
iv: new Uint8Array(record.iv).buffer,
encryptedCertificate: new Uint8Array(record.encryptedCertificate).buffer,
}
} catch (error) {
console.error(`No certificate record found for HCP SSIN ${hcp_ssin}:`, error)
return undefined
}
}
export const loadAndDecryptCertificate = async (hcp_ssin: string, passphrase: string): Promise<ArrayBuffer | undefined> => {
try {
const info = await loadCertificateInformation(hcp_ssin)
if (!info) return undefined
const { salt, iv, encryptedCertificate } = info
const encoder = new TextEncoder()
const passwordKey = await crypto.subtle.importKey('raw', encoder.encode(passphrase), { name: 'PBKDF2' }, false, ['deriveKey'])
const decryptionKey = await crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt: new Uint8Array(salt), iterations: 100_000, hash: 'SHA-256' },
passwordKey,
{ name: 'AES-GCM', length: 256 },
false,
['decrypt'],
)
return await crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: new Uint8Array(iv),
},
decryptionKey,
new Uint8Array(encryptedCertificate),
)
} catch (error) {
console.error(`Decryption failed for HCP SSIN "${hcp_ssin}":`, error)
return undefined
}
}
export const uploadAndEncryptCertificate = async (hcp_ssin: string, passphrase: string, certificate: ArrayBuffer): Promise<CertificateRecordType | undefined> => {
try {
const salt = crypto.getRandomValues(new Uint8Array(16))
const iv = crypto.getRandomValues(new Uint8Array(12))
const passwordKey = await crypto.subtle.importKey('raw', new TextEncoder().encode(passphrase), { name: 'PBKDF2' }, false, ['deriveKey'])
const encryptionKey = await crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt,
iterations: 100_000,
hash: 'SHA-256',
},
passwordKey,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt'],
)
const encryptedCertificate = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, encryptionKey, certificate)
const record: CertificateRecordType = {
id: hcp_ssin,
salt: Array.from(salt),
iv: Array.from(iv),
encryptedCertificate: Array.from(new Uint8Array(encryptedCertificate)),
}
return await certificateStore.put(hcp_ssin, record)
} catch (error) {
console.error(`Encryption failed for certificate of the HCP SSIN ${hcp_ssin}:`, error)
return undefined
}
}
export const deleteCertificate = async (hcp_ssin: string): Promise<boolean> => {
try {
await certificateStore.delete(hcp_ssin)
console.log(`Certificate with ID ${hcp_ssin} successfully deleted.`)
return true
} catch (error) {
console.error(`Failed to delete certificate with ID ${hcp_ssin}:`, error)
return false
}
}