From 180c0ae15d130d8d8dc92811ead7742440964e37 Mon Sep 17 00:00:00 2001 From: guanbinrui <52657989+guanbinrui@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:25:50 +0800 Subject: [PATCH] feat: add preset 2023_Firefly (#11313) Co-authored-by: Jack Works --- .changeset/strong-trains-attend.md | 5 +++ package.json | 2 +- packages/base/package.json | 2 +- .../{utils.ts => getDimensionAsBuffer.ts} | 10 ++--- .../src/image-steganography/index.ts | 20 +++++---- .../src/image-steganography/presets.ts | 21 +++++++++- .../services/crypto/steganography.ts | 2 + .../CompositionDialog/SteganographyPayload.ts | 4 +- .../resources/image-payload/index.ts | 3 +- pnpm-lock.yaml | 42 ++++++------------- 10 files changed, 61 insertions(+), 50 deletions(-) create mode 100644 .changeset/strong-trains-attend.md rename packages/encryption/src/image-steganography/{utils.ts => getDimensionAsBuffer.ts} (91%) diff --git a/.changeset/strong-trains-attend.md b/.changeset/strong-trains-attend.md new file mode 100644 index 00000000000..79d0a345c93 --- /dev/null +++ b/.changeset/strong-trains-attend.md @@ -0,0 +1,5 @@ +--- +'@masknet/encryption': minor +--- + +add preset 2023_Firefly diff --git a/package.json b/package.json index f492f39f642..ed9ca4c7abc 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@emotion/react": "11.11.1", "@emotion/serialize": "1.1.2", "@emotion/styled": "11.11.0", - "@masknet/kit": "0.2.0", + "@masknet/kit": "0.3.0", "@mui/base": "5.0.0-alpha.100", "@mui/icons-material": "5.10.6", "@mui/lab": "5.0.0-alpha.102", diff --git a/packages/base/package.json b/packages/base/package.json index 8b2b71c9bd7..cf387360d5b 100644 --- a/packages/base/package.json +++ b/packages/base/package.json @@ -12,7 +12,7 @@ }, "types": "./dist/index.d.ts", "dependencies": { - "@masknet/kit": "0.2.0", + "@masknet/kit": "0.3.0", "anchorme": "^2.1.2", "pvtsutils": "^1.3.5", "tiny-secp256k1": "^2.2.3", diff --git a/packages/encryption/src/image-steganography/utils.ts b/packages/encryption/src/image-steganography/getDimensionAsBuffer.ts similarity index 91% rename from packages/encryption/src/image-steganography/utils.ts rename to packages/encryption/src/image-steganography/getDimensionAsBuffer.ts index 4d3cd25e192..be8cd0ae3dd 100644 --- a/packages/encryption/src/image-steganography/utils.ts +++ b/packages/encryption/src/image-steganography/getDimensionAsBuffer.ts @@ -2,18 +2,14 @@ import { getImageType } from '@masknet/stego-js' import type { Dimension } from './presets.js' /** @internal */ -export function getDimension(buf: ArrayBuffer): Dimension { - const fallback = { - width: 0, - height: 0, - } +export function getDimensionAsBuffer(buf: ArrayBuffer): Dimension | undefined { switch (getImageType(new Uint8Array(buf))) { case 'image/jpeg': - return getDimensionAsJPEG(buf) ?? fallback + return getDimensionAsJPEG(buf) case 'image/png': return getDimensionAsPNG(buf) default: - return fallback + return } } diff --git a/packages/encryption/src/image-steganography/index.ts b/packages/encryption/src/image-steganography/index.ts index 8e1045663c9..5b3d284e6da 100644 --- a/packages/encryption/src/image-steganography/index.ts +++ b/packages/encryption/src/image-steganography/index.ts @@ -1,10 +1,12 @@ import { encode, decode, type GrayscaleAlgorithm, DEFAULT_MASK, type EncodeOptions } from '@masknet/stego-js' -import { getDimension } from './utils.js' -import { getPreset, findPreset } from './presets.js' -import { decodeArrayBuffer, encodeArrayBuffer } from '@masknet/kit' +import { decodeArrayBuffer, encodeArrayBuffer, getDimensionByDOM } from '@masknet/kit' +import { getDimensionAsBuffer } from './getDimensionAsBuffer.js' +import { getPreset, findPreset, type SteganographyPreset } from './presets.js' export { GrayscaleAlgorithm } from '@masknet/stego-js' +export { SteganographyPreset } from './presets.js' + export interface SteganographyIO { downloadImage: (url: string) => Promise } @@ -14,11 +16,6 @@ export interface EncodeImageOptions extends SteganographyIO { grayscaleAlgorithm?: GrayscaleAlgorithm preset: SteganographyPreset } -export enum SteganographyPreset { - Preset2021 = '2021', - Preset2022 = '2022', - Preset2023 = '2023', -} export async function steganographyEncodeImage(buf: ArrayBuffer, options: EncodeImageOptions) { const { downloadImage, data, password, grayscaleAlgorithm } = options @@ -48,11 +45,16 @@ export async function steganographyEncodeImage(buf: ArrayBuffer, options: Encode export interface DecodeImageOptions extends SteganographyIO { password: string } + export async function steganographyDecodeImage(image: Blob | string, options: DecodeImageOptions) { const buffer = typeof image === 'string' ? await options.downloadImage(image) : await image.arrayBuffer() - const dimension = getDimension(buffer) + + const dimension = (await getDimensionByDOM(image).catch(() => undefined)) ?? getDimensionAsBuffer(buffer) + if (!dimension) return null + const preset = findPreset(dimension) if (!preset) return null + const result = decode( buffer, preset.mask ? await options.downloadImage(preset.mask) : new Uint8Array(DEFAULT_MASK), diff --git a/packages/encryption/src/image-steganography/presets.ts b/packages/encryption/src/image-steganography/presets.ts index 9d60826966d..66b39147761 100644 --- a/packages/encryption/src/image-steganography/presets.ts +++ b/packages/encryption/src/image-steganography/presets.ts @@ -1,6 +1,5 @@ import { unreachable } from '@masknet/kit' import { AlgorithmVersion, GrayscaleAlgorithm, TransformAlgorithm, type EncodeOptions } from '@masknet/stego-js' -import { SteganographyPreset } from './index.js' /** @internal */ export interface Dimension { @@ -27,6 +26,7 @@ const libV1AlgrDefaults: Omit = { transformAlgorithm: TransformAlgorithm.FFT1D, version: AlgorithmVersion.V1, } + const libV2AlgrDefaults: Omit = { size: 8, narrow: 0, @@ -67,6 +67,15 @@ const Preset2023: Preset = { options: libV2AlgrDefaults, } +const Preset2023_Firefly: Preset = { + type: 'raw', + description: 'the preset we used for firefly PC', + width: 1200, + height: 840, + mask: null, + options: libV2AlgrDefaults, +} + const dimensionPreset: readonly Preset[] = [ Preset2023, Preset2022, @@ -108,16 +117,26 @@ const dimensionPreset: readonly Preset[] = [ }, ] +export enum SteganographyPreset { + Preset2021 = '2021', + Preset2022 = '2022', + Preset2023 = '2023', + Preset2023_Firefly = '2023_Firefly', +} + /** @internal */ export function findPreset(dimension: Dimension) { return dimensionPreset.find((d) => isSameDimension(d, dimension)) } + export function getPreset(preset: SteganographyPreset): Preset { if (preset === SteganographyPreset.Preset2021) return Preset2021 if (preset === SteganographyPreset.Preset2022) return Preset2022 if (preset === SteganographyPreset.Preset2023) return Preset2023 + if (preset === SteganographyPreset.Preset2023_Firefly) return Preset2023_Firefly unreachable(preset) } + function isSameDimension(dimension: Dimension, otherDimension: Dimension) { return dimension.width === otherDimension.width && dimension.height === otherDimension.height } diff --git a/packages/mask/background/services/crypto/steganography.ts b/packages/mask/background/services/crypto/steganography.ts index 9fd08306143..f5359ec0cd7 100644 --- a/packages/mask/background/services/crypto/steganography.ts +++ b/packages/mask/background/services/crypto/steganography.ts @@ -7,7 +7,9 @@ async function fetchImage(url: string) { if (!res.ok) throw new Error('Fetch failed.') return res.arrayBuffer() } + const steganographyDownloadImage = memoizePromise(memoize, fetchImage, (x) => x) + export function steganographyEncodeImage( buf: ArrayBuffer, options: Omit, diff --git a/packages/mask/content-script/components/CompositionDialog/SteganographyPayload.ts b/packages/mask/content-script/components/CompositionDialog/SteganographyPayload.ts index 46422fb4e27..4cf33b7550a 100644 --- a/packages/mask/content-script/components/CompositionDialog/SteganographyPayload.ts +++ b/packages/mask/content-script/components/CompositionDialog/SteganographyPayload.ts @@ -7,7 +7,9 @@ import { downloadUrl } from '../../utils/downloadUrl.js' export async function SteganographyPayload(data: string | Uint8Array) { const password = activatedSiteAdaptorUI!.configuration.steganography?.password?.() || 'mask' const preset = typeof data === 'string' ? SteganographyPreset.Preset2022 : SteganographyPreset.Preset2023 - const blankImage = await downloadUrl(SteganographyPresetImage[preset]).then((x) => x.arrayBuffer()) + const blankImageUrl = SteganographyPresetImage[preset] + if (!blankImageUrl) throw new Error('No preset image found.') + const blankImage = await downloadUrl(blankImageUrl).then((x) => x.arrayBuffer()) const secretImage = await Services.Crypto.steganographyEncodeImage(new Uint8Array(blankImage), { preset, data, diff --git a/packages/mask/content-script/resources/image-payload/index.ts b/packages/mask/content-script/resources/image-payload/index.ts index cef193231a5..58f4ed05b9b 100644 --- a/packages/mask/content-script/resources/image-payload/index.ts +++ b/packages/mask/content-script/resources/image-payload/index.ts @@ -1,6 +1,7 @@ import { SteganographyPreset } from '@masknet/encryption' -export const SteganographyPresetImage: Record = { +export const SteganographyPresetImage: Record = { [SteganographyPreset.Preset2021]: new URL('./normal/payload-2021.png', import.meta.url).toString(), [SteganographyPreset.Preset2022]: new URL('./normal/payload-2022.png', import.meta.url).toString(), [SteganographyPreset.Preset2023]: new URL('./normal/payload-2023.png', import.meta.url).toString(), + [SteganographyPreset.Preset2023_Firefly]: null, } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e9433e21a45..01bd46bc199 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,8 +108,8 @@ importers: specifier: 11.11.0 version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.21)(react@0.0.0-experimental-8039e6d0b-20231026) '@masknet/kit': - specifier: 0.2.0 - version: 0.2.0 + specifier: 0.3.0 + version: 0.3.0 '@mui/base': specifier: 5.0.0-alpha.100 version: 5.0.0-alpha.100(patch_hash=ved4raqjjkr2jjhghdp5ouuxk4)(@types/react@18.2.21)(react-dom@0.0.0-experimental-8039e6d0b-20231026)(react@0.0.0-experimental-8039e6d0b-20231026) @@ -525,8 +525,8 @@ importers: packages/base: dependencies: '@masknet/kit': - specifier: 0.2.0 - version: 0.2.0 + specifier: 0.3.0 + version: 0.3.0 anchorme: specifier: ^2.1.2 version: 2.1.2 @@ -3644,7 +3644,7 @@ packages: dependencies: '@babel/compat-data': 7.21.4 '@babel/helper-validator-option': 7.22.5 - browserslist: 4.22.1 + browserslist: 4.22.2 lru-cache: 5.1.1 semver: 6.3.1 dev: false @@ -3655,7 +3655,7 @@ packages: dependencies: '@babel/compat-data': 7.22.9 '@babel/helper-validator-option': 7.22.5 - browserslist: 4.22.1 + browserslist: 4.22.2 lru-cache: 5.1.1 semver: 6.3.1 dev: false @@ -6986,8 +6986,8 @@ packages: eslint: 8.48.0 dev: true - /@masknet/kit@0.2.0: - resolution: {integrity: sha512-XAN6dHD2eSnVoDKJdbqwf5sYus94yfE/CgTldzgWMJGXKM0WouwM8zmWFYtYUpnthznI57PxpIj8QIgABS44jQ==} + /@masknet/kit@0.3.0: + resolution: {integrity: sha512-/7kJ/i0R5QXU1VMjY//vCkH2tnBhw5ffDTECT8zh40WfSedema0K4XriYrVa5IAI1VwHJMMqqCcRPnqCJ7nZZA==} dev: false /@masknet/membrane@0.1.5: @@ -12641,16 +12641,6 @@ packages: update-browserslist-db: 1.0.13(browserslist@4.21.5) dev: false - /browserslist@4.22.1: - resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - caniuse-lite: 1.0.30001543 - electron-to-chromium: 1.4.539 - node-releases: 2.0.13 - update-browserslist-db: 1.0.13(browserslist@4.22.1) - /browserslist@4.22.2: resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -12922,6 +12912,7 @@ packages: /caniuse-lite@1.0.30001543: resolution: {integrity: sha512-qxdO8KPWPQ+Zk6bvNpPeQIOH47qZSYdFZd6dXQzb2KzhnSXju4Kd7H1PkSJx6NICSMgo/IhRZRhhfPTHYpJUCA==} + dev: false /caniuse-lite@1.0.30001565: resolution: {integrity: sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==} @@ -15148,6 +15139,7 @@ packages: /electron-to-chromium@1.4.539: resolution: {integrity: sha512-wRmWJ8F7rgmINuI32S6r2SLrw/h/bJQsDSvBiq9GBfvc2Lh73qTOwn73r3Cf67mjVgFGJYcYtmERzySa5jIWlg==} + dev: false /electron-to-chromium@1.4.616: resolution: {integrity: sha512-1n7zWYh8eS0L9Uy+GskE0lkBUNK83cXTVJI0pU3mGprFsbfSdAc15VTFbo+A+Bq4pwstmL30AVcEU3Fo463lNg==} @@ -21980,6 +21972,7 @@ packages: /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: false /node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} @@ -27039,16 +27032,6 @@ packages: picocolors: 1.0.0 dev: false - /update-browserslist-db@1.0.13(browserslist@4.22.1): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.22.1 - escalade: 3.1.1 - picocolors: 1.0.0 - /update-browserslist-db@1.0.13(browserslist@4.22.2): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true @@ -28711,7 +28694,7 @@ packages: '@webassemblyjs/wasm-parser': 1.11.6 acorn: 8.10.0 acorn-import-assertions: 1.9.0(acorn@8.10.0) - browserslist: 4.22.1 + browserslist: 4.22.2 chrome-trace-event: 1.0.3 enhanced-resolve: 5.15.0 es-module-lexer: 1.3.0 @@ -28745,6 +28728,7 @@ packages: time: /@dimensiondev/holoflows-kit@0.9.0-20240104084316-88642f9: '2024-01-04T08:43:44Z' + /@masknet/kit@0.3.0: '2024-01-25T08:08:18.361Z' /@tanstack/eslint-plugin-query@5.8.4: '2023-11-15T11:29:55.027Z' /@tanstack/query-async-storage-persister@5.8.7: '2023-11-24T19:49:27.017Z' /@tanstack/query-broadcast-client-experimental@5.8.7: '2023-11-24T19:48:56.520Z'