uppy-encrypt 2.1.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/UppyEncrypt.ts","../src/constants.ts","../src/UppyDecrypt.ts"],"sourcesContent":["import UppyEncrypt from './UppyEncrypt';\nimport UppyDecrypt, { type DecryptedMetaData } from './UppyDecrypt';\nimport _sodium from 'libsodium-wrappers-sumo';\nimport { BasePlugin as _BasePlugin, type Uppy } from '@uppy/core';\n\ninterface UppyEncryptPluginOptions {\n id?: string;\n password?: string | null;\n}\n\n// Uppy 3 exposed `BasePlugin<TOptions>` (1 generic); Uppy 4 exposes\n// `BasePlugin<Opts, M, B, PluginState>` where Opts/M/B have no defaults.\n// Cast to a structural type covering the BasePlugin instance surface that\n// `uppy.use()` type-checks against on both majors — including setOptions,\n// getPluginState, setPluginState which Uppy 3's `.use()` requires.\n// Runtime behavior is identical: the real BasePlugin supplies these.\nconst BasePluginCompat = _BasePlugin as unknown as new (\n uppy: Uppy,\n opts?: unknown,\n) => {\n id: string;\n type: string;\n uppy: Uppy;\n install(): void;\n uninstall(): void;\n setOptions(newOpts: Partial<Record<string, unknown>>): void;\n getPluginState(): Record<string, unknown>;\n // Uppy 3's BasePlugin.setPluginState returns Record<string, unknown>.\n // Declaring void here makes TS reject the class as a BasePlugin subtype\n // (return types are covariant), forcing `.use()` to fall through to\n // UIPlugin and fail. A real return type is also valid against Uppy 4\n // (where it's void), since returning-a-value is assignable to void.\n setPluginState(update?: Partial<Record<string, unknown>>): Record<string, unknown>;\n update(state?: unknown): void;\n afterUpdate(): void;\n};\n\n// Sodium is initialized automatically within UppyEncrypt / UppyDecrypt\n// Optionally call this to ensure initialization\nlet sodiumIsReady = false;\nexport const uppyEncryptReady = async () => {\n if (!sodiumIsReady) {\n await _sodium.ready;\n sodiumIsReady = true;\n }\n};\n\nexport class UppyEncryptPlugin extends BasePluginCompat {\n opts: UppyEncryptPluginOptions;\n\n constructor(uppy: Uppy, opts?: UppyEncryptPluginOptions) {\n super(uppy, opts);\n this.id = opts?.id ?? 'UppyEncryptPlugin';\n this.type = 'modifier';\n\n const defaultOptions = {\n password: null,\n };\n this.opts = { ...defaultOptions, ...opts };\n\n this.encryptFiles = this.encryptFiles.bind(this);\n }\n\n async encryptFiles(fileIds: string[]) {\n // Generate a password here if none is already set\n this.opts.password = this.opts.password || UppyEncrypt.generatePassword();\n\n // Add password to meta data so it can be referenced externally\n this.uppy.setMeta({ password: this.opts.password });\n\n for (const fileId of fileIds) {\n const file = this.uppy.getFile(fileId);\n const enc = new UppyEncrypt(this.uppy, file, this.opts.password);\n if (await enc.encryptFile()) {\n this.uppy.emit('preprocess-complete', file);\n let blob = await enc.getEncryptedFile();\n this.uppy.setFileState(fileId, {\n type: 'application/octet-stream',\n data: blob,\n size: blob.size,\n });\n\n this.uppy.setFileMeta(fileId, {\n name: `${file.name}.enc`,\n type: 'application/octet-stream',\n encryption: {\n salt: enc.getSalt(),\n header: enc.getHeader(),\n hash: enc.getPasswordHash(),\n meta: enc.getEncryptMetaData(),\n },\n });\n }\n }\n }\n\n install() {\n this.uppy.addPreProcessor(this.encryptFiles);\n }\n\n uninstall() {\n this.uppy.removePreProcessor(this.encryptFiles);\n }\n}\n\nexport { UppyEncrypt, UppyDecrypt, DecryptedMetaData };\n","import type { Uppy, UppyFile } from '@uppy/core';\nimport _sodium from 'libsodium-wrappers-sumo';\nimport { CHUNK_SIZE, SIGNATURE } from './constants';\n\n// `any` generics keep this compatible with Uppy 3.x (`UppyFile<TMeta, TBody>`),\n// 4.x and 5.x (`UppyFile<M extends Meta, B extends Body>`) without forcing\n// consumers to pin a specific Body shape. Uppy 5 splits `UppyFile` into a\n// discriminated union (`LocalUppyFile | RemoteUppyFile`); we narrow `data` to\n// `Blob` at the access sites since encryption only runs for local files.\ntype AnyUppyFile = UppyFile<any, any>;\n\n// Init Sodium\nlet sodium: typeof _sodium;\n(async () => {\n await _sodium.ready;\n sodium = _sodium;\n})();\n\nexport default class UppyEncrypt {\n private uppy: Uppy;\n private password: string;\n private salt: Uint8Array;\n private key: Uint8Array;\n private state: _sodium.StateAddress;\n private header: Uint8Array;\n private file: AnyUppyFile;\n private fileSize: number;\n private stream: ReadableStream;\n private streamController: ReadableStreamDefaultController | undefined;\n private streamCanceled = false;\n\n private index = 0;\n\n constructor(uppy: Uppy, file: AnyUppyFile, password: string) {\n this.uppy = uppy;\n this.file = file;\n this.password = password;\n // Uppy 4+ types `UppyFile.size` as `number | null`; fall back to the\n // underlying Blob/File size when Uppy hasn't populated it yet.\n this.fileSize = file.size ?? (file.data as Blob).size;\n\n // Set Uppy event handlers that effect the encryption process\n uppy.on('cancel-all', () => {\n this.streamCanceled = true;\n });\n\n this.streamController;\n this.stream = new ReadableStream({\n start: (controller) => {\n this.streamController = controller;\n },\n });\n\n this.salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES);\n this.key = sodium.crypto_pwhash(\n sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES,\n password,\n this.salt,\n sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_ALG_ARGON2ID13\n );\n\n const res = sodium.crypto_secretstream_xchacha20poly1305_init_push(this.key);\n this.state = res.state;\n this.header = res.header;\n }\n\n /**\n * Helper function that generate a random password\n */\n static generatePassword() {\n return sodium.to_base64(sodium.randombytes_buf(16), sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n\n /**\n * Encrypts the file\n */\n async encryptFile() {\n if (!this.streamController) {\n throw new Error('Encryption stream does not exist');\n }\n\n while (this.index < this.fileSize) {\n if (this.streamCanceled) {\n await this.stream.cancel();\n return false;\n }\n\n // If first chunk\n if (this.index === 0) {\n this.streamController.enqueue(new Uint8Array(new TextEncoder().encode(SIGNATURE)));\n this.streamController.enqueue(this.salt);\n this.streamController.enqueue(this.header);\n }\n\n const tag =\n this.index + CHUNK_SIZE < this.fileSize\n ? sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE\n : sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL;\n\n const chunk = await (this.file.data as Blob).slice(this.index, this.index + CHUNK_SIZE).arrayBuffer();\n const encryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_push(this.state, new Uint8Array(chunk), null, tag);\n\n this.streamController.enqueue(new Uint8Array(encryptedChunk));\n\n this.uppy.emit('preprocess-progress', this.file as any, {\n mode: 'determinate',\n message: `Encrypting ${this.file.name}...`,\n value: this.index / this.fileSize,\n });\n\n this.index += CHUNK_SIZE;\n }\n\n this.uppy.emit('preprocess-progress', this.file as any, {\n mode: 'determinate',\n message: `Encrypting ${this.file.name}...`,\n value: 1,\n });\n\n this.streamController.close();\n\n return true;\n }\n\n /**\n * Creates and returns a Blob of the encrypted file\n */\n async getEncryptedFile() {\n const response = new Response(this.stream);\n return response.blob();\n }\n\n /**\n * Returns an encrypted representation of the file's metadata (name, content-type)\n * header: base64-encoded header data\n * meta: Encrypted JSON string of the file's metadata, base64-encoded\n */\n getEncryptMetaData() {\n // Init fresh state\n const res = sodium.crypto_secretstream_xchacha20poly1305_init_push(this.key);\n\n const metaJson = JSON.stringify({ name: this.file.meta.name, type: this.file.meta.type || null });\n const encryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_push(\n res.state,\n new Uint8Array(new TextEncoder().encode(metaJson)),\n null,\n sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL\n );\n\n return {\n header: sodium.to_base64(res.header, sodium.base64_variants.URLSAFE_NO_PADDING),\n data: sodium.to_base64(encryptedChunk, sodium.base64_variants.URLSAFE_NO_PADDING),\n };\n }\n\n /**\n * Returns a hash of the password base64-encoded\n * This data is safe to store in a database, etc\n */\n getPasswordHash() {\n return sodium.crypto_pwhash_str(this.password, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE);\n }\n\n /**\n * Returns the header base64-encoded\n * This data is safe to store in a database, etc\n */\n getHeader() {\n return sodium.to_base64(this.header, sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n\n /**\n * Returns the salt base64-encoded\n * This data is safe to store in a database, etc\n */\n getSalt() {\n return sodium.to_base64(this.salt, sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n}\n","export const CHUNK_SIZE = 64 * 1024 * 1024;\nexport const SIGNATURE = 'uppyencrypt';\n","import _sodium from 'libsodium-wrappers-sumo';\nimport { CHUNK_SIZE, SIGNATURE } from './constants';\n\nexport interface DecryptedMetaData {\n name: string;\n type?: string;\n}\n\n// Init Sodium\nlet sodium: typeof _sodium;\n(async () => {\n await _sodium.ready;\n sodium = _sodium;\n})();\n\nexport default class UppyDecrypt {\n private key: Uint8Array;\n private state: _sodium.StateAddress;\n private stream: ReadableStream;\n private streamController: ReadableStreamDefaultController | undefined;\n private contentType: string;\n\n private index = 0;\n\n constructor(password: string, salt: string, header: string) {\n const saltUint = sodium.from_base64(salt, sodium.base64_variants.URLSAFE_NO_PADDING);\n const headerUint = sodium.from_base64(header, sodium.base64_variants.URLSAFE_NO_PADDING);\n\n this.streamController;\n this.stream = new ReadableStream({\n start: (controller) => {\n this.streamController = controller;\n },\n });\n this.contentType = ''; // Defined if/when meta-data is decrypted\n\n this.key = sodium.crypto_pwhash(\n sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES,\n password,\n saltUint,\n sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_ALG_ARGON2ID13\n );\n\n this.state = sodium.crypto_secretstream_xchacha20poly1305_init_pull(headerUint, this.key);\n\n this.index = SIGNATURE.length + saltUint.length + headerUint.length;\n }\n\n /**\n * Validates that the provided password is correct\n * @param hash The hash value of the password created during UppyEncrypt\n * @param password The user-provided password\n * @returns {bool} true if correct password\n */\n static verifyPassword(hash: string, password: string) {\n return sodium.crypto_pwhash_str_verify(hash, password);\n }\n\n /**\n * Decrypts the provided file\n * @param file Blob of encryptyed file\n * @returns Decrypted file as a blob\n */\n async decryptFile(file: Blob) {\n if (!this.streamController) {\n throw new Error('Encryption stream does not exist');\n }\n\n while (this.index < file.size) {\n const chunk = await file.slice(this.index, this.index + CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES).arrayBuffer();\n const decryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_pull(this.state, new Uint8Array(chunk));\n\n this.streamController.enqueue(decryptedChunk.message);\n\n this.index += CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES;\n }\n\n this.streamController.close();\n\n const response = new Response(this.stream, { headers: { 'Content-Type': this.contentType } });\n return response.blob();\n }\n\n /**\n *\n * @param header Header created during encryption of the meta data\n * @param meta Encrypted meta data string\n * @returns object of the decrypted meta data\n */\n getDecryptedMetaData(header: string, meta: string) {\n // Init fresh state\n const state = sodium.crypto_secretstream_xchacha20poly1305_init_pull(sodium.from_base64(header, sodium.base64_variants.URLSAFE_NO_PADDING), this.key);\n const decryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_pull(state, sodium.from_base64(meta, sodium.base64_variants.URLSAFE_NO_PADDING));\n\n if (!decryptedChunk) throw new Error('Unable to decrypt meta data');\n const decryptedMeta = JSON.parse(new TextDecoder().decode(decryptedChunk.message)) as DecryptedMetaData;\n if (decryptedMeta.type) this.contentType = decryptedMeta.type;\n return decryptedMeta;\n }\n}\n"],"mappings":"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","names":["_sodium","import_libsodium_wrappers_sumo","sodium","_sodium","import_libsodium_wrappers_sumo","_BasePlugin","_sodium"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/UppyEncrypt.ts","../src/constants.ts","../src/UppyDecrypt.ts"],"sourcesContent":["import UppyEncrypt from './UppyEncrypt';\nimport UppyDecrypt, { type DecryptedMetaData } from './UppyDecrypt';\nimport _sodium from 'libsodium-wrappers-sumo';\nimport { BasePlugin as _BasePlugin, type Uppy } from '@uppy/core';\n\ninterface UppyEncryptPluginOptions {\n id?: string;\n password?: string | null;\n}\n\n// Uppy 3 exposed `BasePlugin<TOptions>` (1 generic); Uppy 4 exposes\n// `BasePlugin<Opts, M, B, PluginState>` where Opts/M/B have no defaults.\n// Cast to a structural type covering the BasePlugin instance surface that\n// `uppy.use()` type-checks against on both majors — including setOptions,\n// getPluginState, setPluginState which Uppy 3's `.use()` requires.\n// Runtime behavior is identical: the real BasePlugin supplies these.\nconst BasePluginCompat = _BasePlugin as unknown as new (\n uppy: Uppy,\n opts?: unknown,\n) => {\n id: string;\n type: string;\n uppy: Uppy;\n install(): void;\n uninstall(): void;\n setOptions(newOpts: Partial<Record<string, unknown>>): void;\n getPluginState(): Record<string, unknown>;\n // Uppy 3's BasePlugin.setPluginState returns Record<string, unknown>.\n // Declaring void here makes TS reject the class as a BasePlugin subtype\n // (return types are covariant), forcing `.use()` to fall through to\n // UIPlugin and fail. A real return type is also valid against Uppy 4\n // (where it's void), since returning-a-value is assignable to void.\n setPluginState(update?: Partial<Record<string, unknown>>): Record<string, unknown>;\n update(state?: unknown): void;\n afterUpdate(): void;\n // The remaining members exist on Uppy 3/4/5's `BasePlugin` but were absent\n // from earlier versions of this shim. Without them, `uppy.use<T extends\n // typeof BasePlugin<any, M, B>>(UppyEncryptPlugin)` fails structural\n // assignability and consumers need a cast. `any` (not `unknown`) is required\n // for the data members because TS checks property types invariantly — the\n // shim's type must be assignable to the real `OptionalPluralizeLocale`/`I18n`\n // shapes, and only `any` is bidirectionally compatible. Real values come\n // from runtime BasePlugin inheritance and are never accessed by consumers.\n defaultLocale: any;\n i18n: any;\n i18nArray: any;\n VERSION: string;\n i18nInit(): void;\n addTarget(plugin: any): HTMLElement | null;\n};\n\n// Sodium is initialized automatically within UppyEncrypt / UppyDecrypt\n// Optionally call this to ensure initialization\nlet sodiumIsReady = false;\nexport const uppyEncryptReady = async () => {\n if (!sodiumIsReady) {\n await _sodium.ready;\n sodiumIsReady = true;\n }\n};\n\nexport class UppyEncryptPlugin extends BasePluginCompat {\n opts: UppyEncryptPluginOptions;\n\n constructor(uppy: Uppy, opts?: UppyEncryptPluginOptions) {\n super(uppy, opts);\n this.id = opts?.id ?? 'UppyEncryptPlugin';\n this.type = 'modifier';\n\n const defaultOptions = {\n password: null,\n };\n this.opts = { ...defaultOptions, ...opts };\n\n this.encryptFiles = this.encryptFiles.bind(this);\n }\n\n async encryptFiles(fileIds: string[]) {\n // Generate a password here if none is already set\n this.opts.password = this.opts.password || UppyEncrypt.generatePassword();\n\n // Add password to meta data so it can be referenced externally\n this.uppy.setMeta({ password: this.opts.password });\n\n for (const fileId of fileIds) {\n const file = this.uppy.getFile(fileId);\n const enc = new UppyEncrypt(this.uppy, file, this.opts.password);\n if (await enc.encryptFile()) {\n this.uppy.emit('preprocess-complete', file);\n let blob = await enc.getEncryptedFile();\n this.uppy.setFileState(fileId, {\n type: 'application/octet-stream',\n data: blob,\n size: blob.size,\n });\n\n this.uppy.setFileMeta(fileId, {\n name: `${file.name}.enc`,\n type: 'application/octet-stream',\n encryption: {\n salt: enc.getSalt(),\n header: enc.getHeader(),\n hash: enc.getPasswordHash(),\n meta: enc.getEncryptMetaData(),\n },\n });\n }\n }\n }\n\n install() {\n this.uppy.addPreProcessor(this.encryptFiles);\n }\n\n uninstall() {\n this.uppy.removePreProcessor(this.encryptFiles);\n }\n}\n\nexport { UppyEncrypt, UppyDecrypt, DecryptedMetaData };\n","import type { Uppy, UppyFile } from '@uppy/core';\nimport _sodium from 'libsodium-wrappers-sumo';\nimport { CHUNK_SIZE, SIGNATURE } from './constants';\n\n// `any` generics keep this compatible with Uppy 3.x (`UppyFile<TMeta, TBody>`),\n// 4.x and 5.x (`UppyFile<M extends Meta, B extends Body>`) without forcing\n// consumers to pin a specific Body shape. Uppy 5 splits `UppyFile` into a\n// discriminated union (`LocalUppyFile | RemoteUppyFile`); we narrow `data` to\n// `Blob` at the access sites since encryption only runs for local files.\ntype AnyUppyFile = UppyFile<any, any>;\n\n// Init Sodium\nlet sodium: typeof _sodium;\n(async () => {\n await _sodium.ready;\n sodium = _sodium;\n})();\n\nexport default class UppyEncrypt {\n private uppy: Uppy;\n private password: string;\n private salt: Uint8Array;\n private key: Uint8Array;\n private state: _sodium.StateAddress;\n private header: Uint8Array;\n private file: AnyUppyFile;\n private fileSize: number;\n private stream: ReadableStream;\n private streamController: ReadableStreamDefaultController | undefined;\n private streamCanceled = false;\n\n private index = 0;\n\n constructor(uppy: Uppy, file: AnyUppyFile, password: string) {\n this.uppy = uppy;\n this.file = file;\n this.password = password;\n // Uppy 4+ types `UppyFile.size` as `number | null`; fall back to the\n // underlying Blob/File size when Uppy hasn't populated it yet.\n this.fileSize = file.size ?? (file.data as Blob).size;\n\n // Set Uppy event handlers that effect the encryption process\n uppy.on('cancel-all', () => {\n this.streamCanceled = true;\n });\n\n this.streamController;\n this.stream = new ReadableStream({\n start: (controller) => {\n this.streamController = controller;\n },\n });\n\n this.salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES);\n this.key = sodium.crypto_pwhash(\n sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES,\n password,\n this.salt,\n sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_ALG_ARGON2ID13\n );\n\n const res = sodium.crypto_secretstream_xchacha20poly1305_init_push(this.key);\n this.state = res.state;\n this.header = res.header;\n }\n\n /**\n * Helper function that generate a random password\n */\n static generatePassword() {\n return sodium.to_base64(sodium.randombytes_buf(16), sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n\n /**\n * Encrypts the file\n */\n async encryptFile() {\n if (!this.streamController) {\n throw new Error('Encryption stream does not exist');\n }\n\n while (this.index < this.fileSize) {\n if (this.streamCanceled) {\n await this.stream.cancel();\n return false;\n }\n\n // If first chunk\n if (this.index === 0) {\n this.streamController.enqueue(new Uint8Array(new TextEncoder().encode(SIGNATURE)));\n this.streamController.enqueue(this.salt);\n this.streamController.enqueue(this.header);\n }\n\n const tag =\n this.index + CHUNK_SIZE < this.fileSize\n ? sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE\n : sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL;\n\n const chunk = await (this.file.data as Blob).slice(this.index, this.index + CHUNK_SIZE).arrayBuffer();\n const encryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_push(this.state, new Uint8Array(chunk), null, tag);\n\n this.streamController.enqueue(new Uint8Array(encryptedChunk));\n\n this.uppy.emit('preprocess-progress', this.file as any, {\n mode: 'determinate',\n message: `Encrypting ${this.file.name}...`,\n value: this.index / this.fileSize,\n });\n\n this.index += CHUNK_SIZE;\n }\n\n this.uppy.emit('preprocess-progress', this.file as any, {\n mode: 'determinate',\n message: `Encrypting ${this.file.name}...`,\n value: 1,\n });\n\n this.streamController.close();\n\n return true;\n }\n\n /**\n * Creates and returns a Blob of the encrypted file\n */\n async getEncryptedFile() {\n const response = new Response(this.stream);\n return response.blob();\n }\n\n /**\n * Returns an encrypted representation of the file's metadata (name, content-type)\n * header: base64-encoded header data\n * meta: Encrypted JSON string of the file's metadata, base64-encoded\n */\n getEncryptMetaData() {\n // Init fresh state\n const res = sodium.crypto_secretstream_xchacha20poly1305_init_push(this.key);\n\n const metaJson = JSON.stringify({ name: this.file.meta.name, type: this.file.meta.type || null });\n const encryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_push(\n res.state,\n new Uint8Array(new TextEncoder().encode(metaJson)),\n null,\n sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL\n );\n\n return {\n header: sodium.to_base64(res.header, sodium.base64_variants.URLSAFE_NO_PADDING),\n data: sodium.to_base64(encryptedChunk, sodium.base64_variants.URLSAFE_NO_PADDING),\n };\n }\n\n /**\n * Returns a hash of the password base64-encoded\n * This data is safe to store in a database, etc\n */\n getPasswordHash() {\n return sodium.crypto_pwhash_str(this.password, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE);\n }\n\n /**\n * Returns the header base64-encoded\n * This data is safe to store in a database, etc\n */\n getHeader() {\n return sodium.to_base64(this.header, sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n\n /**\n * Returns the salt base64-encoded\n * This data is safe to store in a database, etc\n */\n getSalt() {\n return sodium.to_base64(this.salt, sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n}\n","export const CHUNK_SIZE = 64 * 1024 * 1024;\nexport const SIGNATURE = 'uppyencrypt';\n","import _sodium from 'libsodium-wrappers-sumo';\nimport { CHUNK_SIZE, SIGNATURE } from './constants';\n\nexport interface DecryptedMetaData {\n name: string;\n type?: string;\n}\n\n// Init Sodium\nlet sodium: typeof _sodium;\n(async () => {\n await _sodium.ready;\n sodium = _sodium;\n})();\n\nexport default class UppyDecrypt {\n private key: Uint8Array;\n private state: _sodium.StateAddress;\n private stream: ReadableStream;\n private streamController: ReadableStreamDefaultController | undefined;\n private contentType: string;\n\n private index = 0;\n\n constructor(password: string, salt: string, header: string) {\n const saltUint = sodium.from_base64(salt, sodium.base64_variants.URLSAFE_NO_PADDING);\n const headerUint = sodium.from_base64(header, sodium.base64_variants.URLSAFE_NO_PADDING);\n\n this.streamController;\n this.stream = new ReadableStream({\n start: (controller) => {\n this.streamController = controller;\n },\n });\n this.contentType = ''; // Defined if/when meta-data is decrypted\n\n this.key = sodium.crypto_pwhash(\n sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES,\n password,\n saltUint,\n sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_ALG_ARGON2ID13\n );\n\n this.state = sodium.crypto_secretstream_xchacha20poly1305_init_pull(headerUint, this.key);\n\n this.index = SIGNATURE.length + saltUint.length + headerUint.length;\n }\n\n /**\n * Validates that the provided password is correct\n * @param hash The hash value of the password created during UppyEncrypt\n * @param password The user-provided password\n * @returns {bool} true if correct password\n */\n static verifyPassword(hash: string, password: string) {\n return sodium.crypto_pwhash_str_verify(hash, password);\n }\n\n /**\n * Decrypts the provided file\n * @param file Blob of encryptyed file\n * @returns Decrypted file as a blob\n */\n async decryptFile(file: Blob) {\n if (!this.streamController) {\n throw new Error('Encryption stream does not exist');\n }\n\n while (this.index < file.size) {\n const chunk = await file.slice(this.index, this.index + CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES).arrayBuffer();\n const decryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_pull(this.state, new Uint8Array(chunk));\n\n this.streamController.enqueue(decryptedChunk.message);\n\n this.index += CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES;\n }\n\n this.streamController.close();\n\n const response = new Response(this.stream, { headers: { 'Content-Type': this.contentType } });\n return response.blob();\n }\n\n /**\n *\n * @param header Header created during encryption of the meta data\n * @param meta Encrypted meta data string\n * @returns object of the decrypted meta data\n */\n getDecryptedMetaData(header: string, meta: string) {\n // Init fresh state\n const state = sodium.crypto_secretstream_xchacha20poly1305_init_pull(sodium.from_base64(header, sodium.base64_variants.URLSAFE_NO_PADDING), this.key);\n const decryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_pull(state, sodium.from_base64(meta, sodium.base64_variants.URLSAFE_NO_PADDING));\n\n if (!decryptedChunk) throw new Error('Unable to decrypt meta data');\n const decryptedMeta = JSON.parse(new TextDecoder().decode(decryptedChunk.message)) as DecryptedMetaData;\n if (decryptedMeta.type) this.contentType = decryptedMeta.type;\n return decryptedMeta;\n }\n}\n"],"mappings":"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","names":["_sodium","import_libsodium_wrappers_sumo","sodium","_sodium","import_libsodium_wrappers_sumo","_BasePlugin","_sodium"]}
package/dist/index.d.cts CHANGED
@@ -59,6 +59,12 @@ declare const BasePluginCompat: new (uppy: Uppy, opts?: unknown) => {
59
59
  setPluginState(update?: Partial<Record<string, unknown>>): Record<string, unknown>;
60
60
  update(state?: unknown): void;
61
61
  afterUpdate(): void;
62
+ defaultLocale: any;
63
+ i18n: any;
64
+ i18nArray: any;
65
+ VERSION: string;
66
+ i18nInit(): void;
67
+ addTarget(plugin: any): HTMLElement | null;
62
68
  };
63
69
  declare const uppyEncryptReady: () => Promise<void>;
64
70
  declare class UppyEncryptPlugin extends BasePluginCompat {
package/dist/index.d.ts CHANGED
@@ -59,6 +59,12 @@ declare const BasePluginCompat: new (uppy: Uppy, opts?: unknown) => {
59
59
  setPluginState(update?: Partial<Record<string, unknown>>): Record<string, unknown>;
60
60
  update(state?: unknown): void;
61
61
  afterUpdate(): void;
62
+ defaultLocale: any;
63
+ i18n: any;
64
+ i18nArray: any;
65
+ VERSION: string;
66
+ i18nInit(): void;
67
+ addTarget(plugin: any): HTMLElement | null;
62
68
  };
63
69
  declare const uppyEncryptReady: () => Promise<void>;
64
70
  declare class UppyEncryptPlugin extends BasePluginCompat {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/UppyEncrypt.ts","../src/constants.ts","../src/UppyDecrypt.ts","../src/index.ts"],"sourcesContent":["import type { Uppy, UppyFile } from '@uppy/core';\nimport _sodium from 'libsodium-wrappers-sumo';\nimport { CHUNK_SIZE, SIGNATURE } from './constants';\n\n// `any` generics keep this compatible with Uppy 3.x (`UppyFile<TMeta, TBody>`),\n// 4.x and 5.x (`UppyFile<M extends Meta, B extends Body>`) without forcing\n// consumers to pin a specific Body shape. Uppy 5 splits `UppyFile` into a\n// discriminated union (`LocalUppyFile | RemoteUppyFile`); we narrow `data` to\n// `Blob` at the access sites since encryption only runs for local files.\ntype AnyUppyFile = UppyFile<any, any>;\n\n// Init Sodium\nlet sodium: typeof _sodium;\n(async () => {\n await _sodium.ready;\n sodium = _sodium;\n})();\n\nexport default class UppyEncrypt {\n private uppy: Uppy;\n private password: string;\n private salt: Uint8Array;\n private key: Uint8Array;\n private state: _sodium.StateAddress;\n private header: Uint8Array;\n private file: AnyUppyFile;\n private fileSize: number;\n private stream: ReadableStream;\n private streamController: ReadableStreamDefaultController | undefined;\n private streamCanceled = false;\n\n private index = 0;\n\n constructor(uppy: Uppy, file: AnyUppyFile, password: string) {\n this.uppy = uppy;\n this.file = file;\n this.password = password;\n // Uppy 4+ types `UppyFile.size` as `number | null`; fall back to the\n // underlying Blob/File size when Uppy hasn't populated it yet.\n this.fileSize = file.size ?? (file.data as Blob).size;\n\n // Set Uppy event handlers that effect the encryption process\n uppy.on('cancel-all', () => {\n this.streamCanceled = true;\n });\n\n this.streamController;\n this.stream = new ReadableStream({\n start: (controller) => {\n this.streamController = controller;\n },\n });\n\n this.salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES);\n this.key = sodium.crypto_pwhash(\n sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES,\n password,\n this.salt,\n sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_ALG_ARGON2ID13\n );\n\n const res = sodium.crypto_secretstream_xchacha20poly1305_init_push(this.key);\n this.state = res.state;\n this.header = res.header;\n }\n\n /**\n * Helper function that generate a random password\n */\n static generatePassword() {\n return sodium.to_base64(sodium.randombytes_buf(16), sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n\n /**\n * Encrypts the file\n */\n async encryptFile() {\n if (!this.streamController) {\n throw new Error('Encryption stream does not exist');\n }\n\n while (this.index < this.fileSize) {\n if (this.streamCanceled) {\n await this.stream.cancel();\n return false;\n }\n\n // If first chunk\n if (this.index === 0) {\n this.streamController.enqueue(new Uint8Array(new TextEncoder().encode(SIGNATURE)));\n this.streamController.enqueue(this.salt);\n this.streamController.enqueue(this.header);\n }\n\n const tag =\n this.index + CHUNK_SIZE < this.fileSize\n ? sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE\n : sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL;\n\n const chunk = await (this.file.data as Blob).slice(this.index, this.index + CHUNK_SIZE).arrayBuffer();\n const encryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_push(this.state, new Uint8Array(chunk), null, tag);\n\n this.streamController.enqueue(new Uint8Array(encryptedChunk));\n\n this.uppy.emit('preprocess-progress', this.file as any, {\n mode: 'determinate',\n message: `Encrypting ${this.file.name}...`,\n value: this.index / this.fileSize,\n });\n\n this.index += CHUNK_SIZE;\n }\n\n this.uppy.emit('preprocess-progress', this.file as any, {\n mode: 'determinate',\n message: `Encrypting ${this.file.name}...`,\n value: 1,\n });\n\n this.streamController.close();\n\n return true;\n }\n\n /**\n * Creates and returns a Blob of the encrypted file\n */\n async getEncryptedFile() {\n const response = new Response(this.stream);\n return response.blob();\n }\n\n /**\n * Returns an encrypted representation of the file's metadata (name, content-type)\n * header: base64-encoded header data\n * meta: Encrypted JSON string of the file's metadata, base64-encoded\n */\n getEncryptMetaData() {\n // Init fresh state\n const res = sodium.crypto_secretstream_xchacha20poly1305_init_push(this.key);\n\n const metaJson = JSON.stringify({ name: this.file.meta.name, type: this.file.meta.type || null });\n const encryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_push(\n res.state,\n new Uint8Array(new TextEncoder().encode(metaJson)),\n null,\n sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL\n );\n\n return {\n header: sodium.to_base64(res.header, sodium.base64_variants.URLSAFE_NO_PADDING),\n data: sodium.to_base64(encryptedChunk, sodium.base64_variants.URLSAFE_NO_PADDING),\n };\n }\n\n /**\n * Returns a hash of the password base64-encoded\n * This data is safe to store in a database, etc\n */\n getPasswordHash() {\n return sodium.crypto_pwhash_str(this.password, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE);\n }\n\n /**\n * Returns the header base64-encoded\n * This data is safe to store in a database, etc\n */\n getHeader() {\n return sodium.to_base64(this.header, sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n\n /**\n * Returns the salt base64-encoded\n * This data is safe to store in a database, etc\n */\n getSalt() {\n return sodium.to_base64(this.salt, sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n}\n","export const CHUNK_SIZE = 64 * 1024 * 1024;\nexport const SIGNATURE = 'uppyencrypt';\n","import _sodium from 'libsodium-wrappers-sumo';\nimport { CHUNK_SIZE, SIGNATURE } from './constants';\n\nexport interface DecryptedMetaData {\n name: string;\n type?: string;\n}\n\n// Init Sodium\nlet sodium: typeof _sodium;\n(async () => {\n await _sodium.ready;\n sodium = _sodium;\n})();\n\nexport default class UppyDecrypt {\n private key: Uint8Array;\n private state: _sodium.StateAddress;\n private stream: ReadableStream;\n private streamController: ReadableStreamDefaultController | undefined;\n private contentType: string;\n\n private index = 0;\n\n constructor(password: string, salt: string, header: string) {\n const saltUint = sodium.from_base64(salt, sodium.base64_variants.URLSAFE_NO_PADDING);\n const headerUint = sodium.from_base64(header, sodium.base64_variants.URLSAFE_NO_PADDING);\n\n this.streamController;\n this.stream = new ReadableStream({\n start: (controller) => {\n this.streamController = controller;\n },\n });\n this.contentType = ''; // Defined if/when meta-data is decrypted\n\n this.key = sodium.crypto_pwhash(\n sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES,\n password,\n saltUint,\n sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_ALG_ARGON2ID13\n );\n\n this.state = sodium.crypto_secretstream_xchacha20poly1305_init_pull(headerUint, this.key);\n\n this.index = SIGNATURE.length + saltUint.length + headerUint.length;\n }\n\n /**\n * Validates that the provided password is correct\n * @param hash The hash value of the password created during UppyEncrypt\n * @param password The user-provided password\n * @returns {bool} true if correct password\n */\n static verifyPassword(hash: string, password: string) {\n return sodium.crypto_pwhash_str_verify(hash, password);\n }\n\n /**\n * Decrypts the provided file\n * @param file Blob of encryptyed file\n * @returns Decrypted file as a blob\n */\n async decryptFile(file: Blob) {\n if (!this.streamController) {\n throw new Error('Encryption stream does not exist');\n }\n\n while (this.index < file.size) {\n const chunk = await file.slice(this.index, this.index + CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES).arrayBuffer();\n const decryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_pull(this.state, new Uint8Array(chunk));\n\n this.streamController.enqueue(decryptedChunk.message);\n\n this.index += CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES;\n }\n\n this.streamController.close();\n\n const response = new Response(this.stream, { headers: { 'Content-Type': this.contentType } });\n return response.blob();\n }\n\n /**\n *\n * @param header Header created during encryption of the meta data\n * @param meta Encrypted meta data string\n * @returns object of the decrypted meta data\n */\n getDecryptedMetaData(header: string, meta: string) {\n // Init fresh state\n const state = sodium.crypto_secretstream_xchacha20poly1305_init_pull(sodium.from_base64(header, sodium.base64_variants.URLSAFE_NO_PADDING), this.key);\n const decryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_pull(state, sodium.from_base64(meta, sodium.base64_variants.URLSAFE_NO_PADDING));\n\n if (!decryptedChunk) throw new Error('Unable to decrypt meta data');\n const decryptedMeta = JSON.parse(new TextDecoder().decode(decryptedChunk.message)) as DecryptedMetaData;\n if (decryptedMeta.type) this.contentType = decryptedMeta.type;\n return decryptedMeta;\n }\n}\n","import UppyEncrypt from './UppyEncrypt';\nimport UppyDecrypt, { type DecryptedMetaData } from './UppyDecrypt';\nimport _sodium from 'libsodium-wrappers-sumo';\nimport { BasePlugin as _BasePlugin, type Uppy } from '@uppy/core';\n\ninterface UppyEncryptPluginOptions {\n id?: string;\n password?: string | null;\n}\n\n// Uppy 3 exposed `BasePlugin<TOptions>` (1 generic); Uppy 4 exposes\n// `BasePlugin<Opts, M, B, PluginState>` where Opts/M/B have no defaults.\n// Cast to a structural type covering the BasePlugin instance surface that\n// `uppy.use()` type-checks against on both majors — including setOptions,\n// getPluginState, setPluginState which Uppy 3's `.use()` requires.\n// Runtime behavior is identical: the real BasePlugin supplies these.\nconst BasePluginCompat = _BasePlugin as unknown as new (\n uppy: Uppy,\n opts?: unknown,\n) => {\n id: string;\n type: string;\n uppy: Uppy;\n install(): void;\n uninstall(): void;\n setOptions(newOpts: Partial<Record<string, unknown>>): void;\n getPluginState(): Record<string, unknown>;\n // Uppy 3's BasePlugin.setPluginState returns Record<string, unknown>.\n // Declaring void here makes TS reject the class as a BasePlugin subtype\n // (return types are covariant), forcing `.use()` to fall through to\n // UIPlugin and fail. A real return type is also valid against Uppy 4\n // (where it's void), since returning-a-value is assignable to void.\n setPluginState(update?: Partial<Record<string, unknown>>): Record<string, unknown>;\n update(state?: unknown): void;\n afterUpdate(): void;\n};\n\n// Sodium is initialized automatically within UppyEncrypt / UppyDecrypt\n// Optionally call this to ensure initialization\nlet sodiumIsReady = false;\nexport const uppyEncryptReady = async () => {\n if (!sodiumIsReady) {\n await _sodium.ready;\n sodiumIsReady = true;\n }\n};\n\nexport class UppyEncryptPlugin extends BasePluginCompat {\n opts: UppyEncryptPluginOptions;\n\n constructor(uppy: Uppy, opts?: UppyEncryptPluginOptions) {\n super(uppy, opts);\n this.id = opts?.id ?? 'UppyEncryptPlugin';\n this.type = 'modifier';\n\n const defaultOptions = {\n password: null,\n };\n this.opts = { ...defaultOptions, ...opts };\n\n this.encryptFiles = this.encryptFiles.bind(this);\n }\n\n async encryptFiles(fileIds: string[]) {\n // Generate a password here if none is already set\n this.opts.password = this.opts.password || UppyEncrypt.generatePassword();\n\n // Add password to meta data so it can be referenced externally\n this.uppy.setMeta({ password: this.opts.password });\n\n for (const fileId of fileIds) {\n const file = this.uppy.getFile(fileId);\n const enc = new UppyEncrypt(this.uppy, file, this.opts.password);\n if (await enc.encryptFile()) {\n this.uppy.emit('preprocess-complete', file);\n let blob = await enc.getEncryptedFile();\n this.uppy.setFileState(fileId, {\n type: 'application/octet-stream',\n data: blob,\n size: blob.size,\n });\n\n this.uppy.setFileMeta(fileId, {\n name: `${file.name}.enc`,\n type: 'application/octet-stream',\n encryption: {\n salt: enc.getSalt(),\n header: enc.getHeader(),\n hash: enc.getPasswordHash(),\n meta: enc.getEncryptMetaData(),\n },\n });\n }\n }\n }\n\n install() {\n this.uppy.addPreProcessor(this.encryptFiles);\n }\n\n uninstall() {\n this.uppy.removePreProcessor(this.encryptFiles);\n }\n}\n\nexport { UppyEncrypt, UppyDecrypt, DecryptedMetaData };\n"],"mappings":"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","names":["_sodium","sodium","_sodium","_sodium","_sodium"]}
1
+ {"version":3,"sources":["../src/UppyEncrypt.ts","../src/constants.ts","../src/UppyDecrypt.ts","../src/index.ts"],"sourcesContent":["import type { Uppy, UppyFile } from '@uppy/core';\nimport _sodium from 'libsodium-wrappers-sumo';\nimport { CHUNK_SIZE, SIGNATURE } from './constants';\n\n// `any` generics keep this compatible with Uppy 3.x (`UppyFile<TMeta, TBody>`),\n// 4.x and 5.x (`UppyFile<M extends Meta, B extends Body>`) without forcing\n// consumers to pin a specific Body shape. Uppy 5 splits `UppyFile` into a\n// discriminated union (`LocalUppyFile | RemoteUppyFile`); we narrow `data` to\n// `Blob` at the access sites since encryption only runs for local files.\ntype AnyUppyFile = UppyFile<any, any>;\n\n// Init Sodium\nlet sodium: typeof _sodium;\n(async () => {\n await _sodium.ready;\n sodium = _sodium;\n})();\n\nexport default class UppyEncrypt {\n private uppy: Uppy;\n private password: string;\n private salt: Uint8Array;\n private key: Uint8Array;\n private state: _sodium.StateAddress;\n private header: Uint8Array;\n private file: AnyUppyFile;\n private fileSize: number;\n private stream: ReadableStream;\n private streamController: ReadableStreamDefaultController | undefined;\n private streamCanceled = false;\n\n private index = 0;\n\n constructor(uppy: Uppy, file: AnyUppyFile, password: string) {\n this.uppy = uppy;\n this.file = file;\n this.password = password;\n // Uppy 4+ types `UppyFile.size` as `number | null`; fall back to the\n // underlying Blob/File size when Uppy hasn't populated it yet.\n this.fileSize = file.size ?? (file.data as Blob).size;\n\n // Set Uppy event handlers that effect the encryption process\n uppy.on('cancel-all', () => {\n this.streamCanceled = true;\n });\n\n this.streamController;\n this.stream = new ReadableStream({\n start: (controller) => {\n this.streamController = controller;\n },\n });\n\n this.salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES);\n this.key = sodium.crypto_pwhash(\n sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES,\n password,\n this.salt,\n sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_ALG_ARGON2ID13\n );\n\n const res = sodium.crypto_secretstream_xchacha20poly1305_init_push(this.key);\n this.state = res.state;\n this.header = res.header;\n }\n\n /**\n * Helper function that generate a random password\n */\n static generatePassword() {\n return sodium.to_base64(sodium.randombytes_buf(16), sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n\n /**\n * Encrypts the file\n */\n async encryptFile() {\n if (!this.streamController) {\n throw new Error('Encryption stream does not exist');\n }\n\n while (this.index < this.fileSize) {\n if (this.streamCanceled) {\n await this.stream.cancel();\n return false;\n }\n\n // If first chunk\n if (this.index === 0) {\n this.streamController.enqueue(new Uint8Array(new TextEncoder().encode(SIGNATURE)));\n this.streamController.enqueue(this.salt);\n this.streamController.enqueue(this.header);\n }\n\n const tag =\n this.index + CHUNK_SIZE < this.fileSize\n ? sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE\n : sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL;\n\n const chunk = await (this.file.data as Blob).slice(this.index, this.index + CHUNK_SIZE).arrayBuffer();\n const encryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_push(this.state, new Uint8Array(chunk), null, tag);\n\n this.streamController.enqueue(new Uint8Array(encryptedChunk));\n\n this.uppy.emit('preprocess-progress', this.file as any, {\n mode: 'determinate',\n message: `Encrypting ${this.file.name}...`,\n value: this.index / this.fileSize,\n });\n\n this.index += CHUNK_SIZE;\n }\n\n this.uppy.emit('preprocess-progress', this.file as any, {\n mode: 'determinate',\n message: `Encrypting ${this.file.name}...`,\n value: 1,\n });\n\n this.streamController.close();\n\n return true;\n }\n\n /**\n * Creates and returns a Blob of the encrypted file\n */\n async getEncryptedFile() {\n const response = new Response(this.stream);\n return response.blob();\n }\n\n /**\n * Returns an encrypted representation of the file's metadata (name, content-type)\n * header: base64-encoded header data\n * meta: Encrypted JSON string of the file's metadata, base64-encoded\n */\n getEncryptMetaData() {\n // Init fresh state\n const res = sodium.crypto_secretstream_xchacha20poly1305_init_push(this.key);\n\n const metaJson = JSON.stringify({ name: this.file.meta.name, type: this.file.meta.type || null });\n const encryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_push(\n res.state,\n new Uint8Array(new TextEncoder().encode(metaJson)),\n null,\n sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL\n );\n\n return {\n header: sodium.to_base64(res.header, sodium.base64_variants.URLSAFE_NO_PADDING),\n data: sodium.to_base64(encryptedChunk, sodium.base64_variants.URLSAFE_NO_PADDING),\n };\n }\n\n /**\n * Returns a hash of the password base64-encoded\n * This data is safe to store in a database, etc\n */\n getPasswordHash() {\n return sodium.crypto_pwhash_str(this.password, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE);\n }\n\n /**\n * Returns the header base64-encoded\n * This data is safe to store in a database, etc\n */\n getHeader() {\n return sodium.to_base64(this.header, sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n\n /**\n * Returns the salt base64-encoded\n * This data is safe to store in a database, etc\n */\n getSalt() {\n return sodium.to_base64(this.salt, sodium.base64_variants.URLSAFE_NO_PADDING);\n }\n}\n","export const CHUNK_SIZE = 64 * 1024 * 1024;\nexport const SIGNATURE = 'uppyencrypt';\n","import _sodium from 'libsodium-wrappers-sumo';\nimport { CHUNK_SIZE, SIGNATURE } from './constants';\n\nexport interface DecryptedMetaData {\n name: string;\n type?: string;\n}\n\n// Init Sodium\nlet sodium: typeof _sodium;\n(async () => {\n await _sodium.ready;\n sodium = _sodium;\n})();\n\nexport default class UppyDecrypt {\n private key: Uint8Array;\n private state: _sodium.StateAddress;\n private stream: ReadableStream;\n private streamController: ReadableStreamDefaultController | undefined;\n private contentType: string;\n\n private index = 0;\n\n constructor(password: string, salt: string, header: string) {\n const saltUint = sodium.from_base64(salt, sodium.base64_variants.URLSAFE_NO_PADDING);\n const headerUint = sodium.from_base64(header, sodium.base64_variants.URLSAFE_NO_PADDING);\n\n this.streamController;\n this.stream = new ReadableStream({\n start: (controller) => {\n this.streamController = controller;\n },\n });\n this.contentType = ''; // Defined if/when meta-data is decrypted\n\n this.key = sodium.crypto_pwhash(\n sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES,\n password,\n saltUint,\n sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_ALG_ARGON2ID13\n );\n\n this.state = sodium.crypto_secretstream_xchacha20poly1305_init_pull(headerUint, this.key);\n\n this.index = SIGNATURE.length + saltUint.length + headerUint.length;\n }\n\n /**\n * Validates that the provided password is correct\n * @param hash The hash value of the password created during UppyEncrypt\n * @param password The user-provided password\n * @returns {bool} true if correct password\n */\n static verifyPassword(hash: string, password: string) {\n return sodium.crypto_pwhash_str_verify(hash, password);\n }\n\n /**\n * Decrypts the provided file\n * @param file Blob of encryptyed file\n * @returns Decrypted file as a blob\n */\n async decryptFile(file: Blob) {\n if (!this.streamController) {\n throw new Error('Encryption stream does not exist');\n }\n\n while (this.index < file.size) {\n const chunk = await file.slice(this.index, this.index + CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES).arrayBuffer();\n const decryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_pull(this.state, new Uint8Array(chunk));\n\n this.streamController.enqueue(decryptedChunk.message);\n\n this.index += CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES;\n }\n\n this.streamController.close();\n\n const response = new Response(this.stream, { headers: { 'Content-Type': this.contentType } });\n return response.blob();\n }\n\n /**\n *\n * @param header Header created during encryption of the meta data\n * @param meta Encrypted meta data string\n * @returns object of the decrypted meta data\n */\n getDecryptedMetaData(header: string, meta: string) {\n // Init fresh state\n const state = sodium.crypto_secretstream_xchacha20poly1305_init_pull(sodium.from_base64(header, sodium.base64_variants.URLSAFE_NO_PADDING), this.key);\n const decryptedChunk = sodium.crypto_secretstream_xchacha20poly1305_pull(state, sodium.from_base64(meta, sodium.base64_variants.URLSAFE_NO_PADDING));\n\n if (!decryptedChunk) throw new Error('Unable to decrypt meta data');\n const decryptedMeta = JSON.parse(new TextDecoder().decode(decryptedChunk.message)) as DecryptedMetaData;\n if (decryptedMeta.type) this.contentType = decryptedMeta.type;\n return decryptedMeta;\n }\n}\n","import UppyEncrypt from './UppyEncrypt';\nimport UppyDecrypt, { type DecryptedMetaData } from './UppyDecrypt';\nimport _sodium from 'libsodium-wrappers-sumo';\nimport { BasePlugin as _BasePlugin, type Uppy } from '@uppy/core';\n\ninterface UppyEncryptPluginOptions {\n id?: string;\n password?: string | null;\n}\n\n// Uppy 3 exposed `BasePlugin<TOptions>` (1 generic); Uppy 4 exposes\n// `BasePlugin<Opts, M, B, PluginState>` where Opts/M/B have no defaults.\n// Cast to a structural type covering the BasePlugin instance surface that\n// `uppy.use()` type-checks against on both majors — including setOptions,\n// getPluginState, setPluginState which Uppy 3's `.use()` requires.\n// Runtime behavior is identical: the real BasePlugin supplies these.\nconst BasePluginCompat = _BasePlugin as unknown as new (\n uppy: Uppy,\n opts?: unknown,\n) => {\n id: string;\n type: string;\n uppy: Uppy;\n install(): void;\n uninstall(): void;\n setOptions(newOpts: Partial<Record<string, unknown>>): void;\n getPluginState(): Record<string, unknown>;\n // Uppy 3's BasePlugin.setPluginState returns Record<string, unknown>.\n // Declaring void here makes TS reject the class as a BasePlugin subtype\n // (return types are covariant), forcing `.use()` to fall through to\n // UIPlugin and fail. A real return type is also valid against Uppy 4\n // (where it's void), since returning-a-value is assignable to void.\n setPluginState(update?: Partial<Record<string, unknown>>): Record<string, unknown>;\n update(state?: unknown): void;\n afterUpdate(): void;\n // The remaining members exist on Uppy 3/4/5's `BasePlugin` but were absent\n // from earlier versions of this shim. Without them, `uppy.use<T extends\n // typeof BasePlugin<any, M, B>>(UppyEncryptPlugin)` fails structural\n // assignability and consumers need a cast. `any` (not `unknown`) is required\n // for the data members because TS checks property types invariantly — the\n // shim's type must be assignable to the real `OptionalPluralizeLocale`/`I18n`\n // shapes, and only `any` is bidirectionally compatible. Real values come\n // from runtime BasePlugin inheritance and are never accessed by consumers.\n defaultLocale: any;\n i18n: any;\n i18nArray: any;\n VERSION: string;\n i18nInit(): void;\n addTarget(plugin: any): HTMLElement | null;\n};\n\n// Sodium is initialized automatically within UppyEncrypt / UppyDecrypt\n// Optionally call this to ensure initialization\nlet sodiumIsReady = false;\nexport const uppyEncryptReady = async () => {\n if (!sodiumIsReady) {\n await _sodium.ready;\n sodiumIsReady = true;\n }\n};\n\nexport class UppyEncryptPlugin extends BasePluginCompat {\n opts: UppyEncryptPluginOptions;\n\n constructor(uppy: Uppy, opts?: UppyEncryptPluginOptions) {\n super(uppy, opts);\n this.id = opts?.id ?? 'UppyEncryptPlugin';\n this.type = 'modifier';\n\n const defaultOptions = {\n password: null,\n };\n this.opts = { ...defaultOptions, ...opts };\n\n this.encryptFiles = this.encryptFiles.bind(this);\n }\n\n async encryptFiles(fileIds: string[]) {\n // Generate a password here if none is already set\n this.opts.password = this.opts.password || UppyEncrypt.generatePassword();\n\n // Add password to meta data so it can be referenced externally\n this.uppy.setMeta({ password: this.opts.password });\n\n for (const fileId of fileIds) {\n const file = this.uppy.getFile(fileId);\n const enc = new UppyEncrypt(this.uppy, file, this.opts.password);\n if (await enc.encryptFile()) {\n this.uppy.emit('preprocess-complete', file);\n let blob = await enc.getEncryptedFile();\n this.uppy.setFileState(fileId, {\n type: 'application/octet-stream',\n data: blob,\n size: blob.size,\n });\n\n this.uppy.setFileMeta(fileId, {\n name: `${file.name}.enc`,\n type: 'application/octet-stream',\n encryption: {\n salt: enc.getSalt(),\n header: enc.getHeader(),\n hash: enc.getPasswordHash(),\n meta: enc.getEncryptMetaData(),\n },\n });\n }\n }\n }\n\n install() {\n this.uppy.addPreProcessor(this.encryptFiles);\n }\n\n uninstall() {\n this.uppy.removePreProcessor(this.encryptFiles);\n }\n}\n\nexport { UppyEncrypt, UppyDecrypt, DecryptedMetaData };\n"],"mappings":"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","names":["_sodium","sodium","_sodium","_sodium","_sodium"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uppy-encrypt",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Uppy plugin to encrypt and decrypt files in the browser before upload using libsodium-wrappers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",