Skip to content

Commit

Permalink
feat: add preset 2023_Firefly (#11313)
Browse files Browse the repository at this point in the history
Co-authored-by: Jack Works <jackworks@protonmail.com>
  • Loading branch information
guanbinrui and Jack-Works committed Jan 25, 2024
1 parent 18ade9e commit 180c0ae
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 50 deletions.
5 changes: 5 additions & 0 deletions .changeset/strong-trains-attend.md
@@ -0,0 +1,5 @@
---
'@masknet/encryption': minor
---

add preset 2023_Firefly
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/base/package.json
Expand Up @@ -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",
Expand Down
Expand Up @@ -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
}
}

Expand Down
20 changes: 11 additions & 9 deletions 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<ArrayBuffer>
}
Expand All @@ -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
Expand Down Expand Up @@ -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),
Expand Down
21 changes: 20 additions & 1 deletion 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 {
Expand All @@ -27,6 +26,7 @@ const libV1AlgrDefaults: Omit<EncodeOptions, 'text'> = {
transformAlgorithm: TransformAlgorithm.FFT1D,
version: AlgorithmVersion.V1,
}

const libV2AlgrDefaults: Omit<EncodeOptions, 'text'> = {
size: 8,
narrow: 0,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
2 changes: 2 additions & 0 deletions packages/mask/background/services/crypto/steganography.ts
Expand Up @@ -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<EncodeImageOptions, 'downloadImage'>,
Expand Down
Expand Up @@ -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,
Expand Down
@@ -1,6 +1,7 @@
import { SteganographyPreset } from '@masknet/encryption'
export const SteganographyPresetImage: Record<SteganographyPreset, string> = {
export const SteganographyPresetImage: Record<SteganographyPreset, string | null> = {
[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,
}
42 changes: 13 additions & 29 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 180c0ae

Please sign in to comment.