EdgeAIG's picture
download
raw
4.57 kB
/**
* Cryptographic service for encrypted event-log replication.
*
* `EventLogEncryption` turns local journal entries into encrypted remote
* payloads and decrypts encrypted changes received from a server. It also
* hashes byte data and creates event-log identities, so remote replication can
* use storage or transport that should not see plaintext event data.
*
* @since 4.0.0
*/
import * as Context from "../../Context.js";
import * as Effect from "../../Effect.js";
import * as Layer from "../../Layer.js";
import * as Redacted from "../../Redacted.js";
import * as Schema from "../../Schema.js";
import * as Transferable from "../workers/Transferable.js";
import { Entry, EntryId, RemoteEntry } from "./EventJournal.js";
import { makeGetIdentityRootSecretMaterial } from "./internal/identityRootSecretDerivation.js";
/**
* Schema for an encrypted journal entry paired with the id of the original
* entry.
*
* @category models
* @since 4.0.0
*/
export const EncryptedEntry = /*#__PURE__*/Schema.Struct({
entryId: EntryId,
encryptedEntry: Transferable.Uint8Array
});
/**
* Schema for encrypted entries exchanged with a remote event-log server.
*
* @category models
* @since 4.0.0
*/
export const EncryptedRemoteEntry = /*#__PURE__*/Schema.Struct({
sequence: Schema.Number,
iv: Transferable.Uint8Array,
entryId: EntryId,
encryptedEntry: Transferable.Uint8Array
});
const toArrayBuffer = data => {
const buffer = new ArrayBuffer(data.byteLength);
new Uint8Array(buffer).set(data);
return buffer;
};
const toBufferSource = data => new Uint8Array(toArrayBuffer(data));
/**
* Service that provides identity generation, entry
* encryption and decryption, and SHA-256 hashing for event-log replication.
*
* **When to use**
*
* Use to provide cryptographic operations required by encrypted event-log
* replication.
*
* @category services
* @since 4.0.0
*/
export class EventLogEncryption extends /*#__PURE__*/Context.Service()("effect/eventlog/EventLogEncryption") {}
/**
* Creates an `EventLogEncryption` service backed by the Web Crypto `SubtleCrypto`
* APIs from the supplied `Crypto` implementation.
*
* @category encryption
* @since 4.0.0
*/
export const makeEncryptionSubtle = crypto => Effect.sync(() => {
const getIdentityRootSecretMaterial = makeGetIdentityRootSecretMaterial(crypto);
return EventLogEncryption.of({
encrypt: Effect.fnUntraced(function* (identity, entries) {
const data = yield* Effect.orDie(Entry.encodeArray(entries));
const key = (yield* getIdentityRootSecretMaterial(identity)).encryptionKey;
const iv = crypto.getRandomValues(new Uint8Array(12));
const encryptedEntries = yield* Effect.promise(() => Promise.all(data.map(entry => crypto.subtle.encrypt({
name: "AES-GCM",
iv: toBufferSource(iv),
tagLength: 128
}, key, toBufferSource(entry)))));
return {
iv,
encryptedEntries: encryptedEntries.map(entry => new Uint8Array(entry))
};
}),
decrypt: Effect.fnUntraced(function* (identity, entries) {
const key = (yield* getIdentityRootSecretMaterial(identity)).encryptionKey;
const decryptedData = (yield* Effect.promise(() => Promise.all(entries.map(data => crypto.subtle.decrypt({
name: "AES-GCM",
iv: toBufferSource(data.iv),
tagLength: 128
}, key, toBufferSource(data.encryptedEntry)))))).map(buffer => new Uint8Array(buffer));
const decoded = yield* Effect.orDie(Entry.decodeArray(decryptedData));
return decoded.map((entry, index) => new RemoteEntry({
remoteSequence: entries[index].sequence,
entry
}));
}),
sha256: data => Effect.promise(() => crypto.subtle.digest("SHA-256", toArrayBuffer(data))).pipe(Effect.map(hash => new Uint8Array(hash))),
sha256String: data => Effect.map(Effect.promise(() => crypto.subtle.digest("SHA-256", toArrayBuffer(data))), hash => {
const hashArray = Array.from(new Uint8Array(hash));
const hashHex = hashArray.map(bytes => bytes.toString(16).padStart(2, "0")).join("");
return hashHex;
}),
generateIdentity: Effect.sync(() => ({
publicKey: crypto.randomUUID(),
privateKey: Redacted.make(crypto.getRandomValues(new Uint8Array(32)))
}))
});
});
/**
* Provides `EventLogEncryption` using `globalThis.crypto`.
*
* @category encryption
* @since 4.0.0
*/
export const layerSubtle = /*#__PURE__*/Layer.effect(EventLogEncryption, /*#__PURE__*/makeEncryptionSubtle(globalThis.crypto));
//# sourceMappingURL=EventLogEncryption.js.map

Xet Storage Details

Size:
4.57 kB
·
Xet hash:
fa42c2708d1fe5087a94f28fb8bfcd697751f8909207316c775d35ce57a4b899

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.