Move sticker creator API to chat service
This commit is contained in:
parent
a1e090d1f1
commit
31cbb89b0d
21 changed files with 124 additions and 587 deletions
|
@ -3148,15 +3148,15 @@
|
||||||
},
|
},
|
||||||
"icu:AuthArtCreator--dialog--message": {
|
"icu:AuthArtCreator--dialog--message": {
|
||||||
"messageformat": "Would you like to open Signal Sticker Pack Creator?",
|
"messageformat": "Would you like to open Signal Sticker Pack Creator?",
|
||||||
"description": "A body of the dialog that is presented when user tries to open Signal Sticker Pack Creator from a link"
|
"description": "(Deleted 2024/05/15) A body of the dialog that is presented when user tries to open Signal Sticker Pack Creator from a link"
|
||||||
},
|
},
|
||||||
"icu:AuthArtCreator--dialog--confirm": {
|
"icu:AuthArtCreator--dialog--confirm": {
|
||||||
"messageformat": "Confirm",
|
"messageformat": "Confirm",
|
||||||
"description": "A buttle title for confirming Signal Sticker Pack Creator dialog"
|
"description": "(Deleted 2024/05/15) A buttle title for confirming Signal Sticker Pack Creator dialog"
|
||||||
},
|
},
|
||||||
"icu:AuthArtCreator--dialog--dismiss": {
|
"icu:AuthArtCreator--dialog--dismiss": {
|
||||||
"messageformat": "Dismiss",
|
"messageformat": "Dismiss",
|
||||||
"description": "A buttle title for dismissing Signal Sticker Pack Creator dialog"
|
"description": "(Deleted 2024/05/15) A buttle title for dismissing Signal Sticker Pack Creator dialog"
|
||||||
},
|
},
|
||||||
"icu:ArtCreator--Authentication--error": {
|
"icu:ArtCreator--Authentication--error": {
|
||||||
"messageformat": "Please set up Signal on your phone and desktop to use the Sticker Pack Creator",
|
"messageformat": "Please set up Signal on your phone and desktop to use the Sticker Pack Creator",
|
||||||
|
|
41
app/main.ts
41
app/main.ts
|
@ -120,8 +120,6 @@ import { parseSignalRoute } from '../ts/util/signalRoutes';
|
||||||
import * as dns from '../ts/util/dns';
|
import * as dns from '../ts/util/dns';
|
||||||
import { ZoomFactorService } from '../ts/services/ZoomFactorService';
|
import { ZoomFactorService } from '../ts/services/ZoomFactorService';
|
||||||
|
|
||||||
const STICKER_CREATOR_PARTITION = 'sticker-creator';
|
|
||||||
|
|
||||||
const animationSettings = systemPreferences.getAnimationSettings();
|
const animationSettings = systemPreferences.getAnimationSettings();
|
||||||
|
|
||||||
if (OS.isMacOS()) {
|
if (OS.isMacOS()) {
|
||||||
|
@ -1000,21 +998,24 @@ ipc.handle('database-ready', async () => {
|
||||||
getLogger().info('sending `database-ready`');
|
getLogger().info('sending `database-ready`');
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.handle('get-art-creator-auth', () => {
|
ipc.handle(
|
||||||
|
'art-creator:uploadStickerPack',
|
||||||
|
(_event: Electron.Event, data: unknown) => {
|
||||||
const { promise, resolve } = explodePromise<unknown>();
|
const { promise, resolve } = explodePromise<unknown>();
|
||||||
strictAssert(mainWindow, 'Main window did not exist');
|
strictAssert(mainWindow, 'Main window did not exist');
|
||||||
|
|
||||||
mainWindow.webContents.send('open-art-creator');
|
mainWindow.webContents.send('art-creator:uploadStickerPack', data);
|
||||||
|
|
||||||
ipc.handleOnce('open-art-creator', (_event, { username, password }) => {
|
ipc.once('art-creator:uploadStickerPack:done', (_doneEvent, response) => {
|
||||||
resolve({
|
resolve(response);
|
||||||
baseUrl: config.get<string>('artCreatorUrl'),
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
ipc.on('art-creator:onUploadProgress', () => {
|
||||||
|
stickerCreatorWindow?.webContents.send('art-creator:onUploadProgress');
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.on('show-window', () => {
|
ipc.on('show-window', () => {
|
||||||
|
@ -1735,31 +1736,22 @@ app.on('ready', async () => {
|
||||||
realpath(app.getAppPath()),
|
realpath(app.getAppPath()),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const webSession = session.fromPartition(STICKER_CREATOR_PARTITION);
|
updateDefaultSession(session.defaultSession);
|
||||||
|
|
||||||
for (const s of [session.defaultSession, webSession]) {
|
|
||||||
updateDefaultSession(s);
|
|
||||||
|
|
||||||
if (getEnvironment() !== Environment.Test) {
|
if (getEnvironment() !== Environment.Test) {
|
||||||
installFileHandler({
|
installFileHandler({
|
||||||
session: s,
|
session: session.defaultSession,
|
||||||
userDataPath,
|
userDataPath,
|
||||||
installPath,
|
installPath,
|
||||||
isWindows: OS.isWindows(),
|
isWindows: OS.isWindows(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
installWebHandler({
|
installWebHandler({
|
||||||
enableHttp: Boolean(process.env.SIGNAL_ENABLE_HTTP),
|
enableHttp: Boolean(process.env.SIGNAL_ENABLE_HTTP),
|
||||||
session: session.defaultSession,
|
session: session.defaultSession,
|
||||||
});
|
});
|
||||||
|
|
||||||
installWebHandler({
|
|
||||||
enableHttp: true,
|
|
||||||
session: webSession,
|
|
||||||
});
|
|
||||||
|
|
||||||
logger = await logging.initialize(getMainWindow);
|
logger = await logging.initialize(getMainWindow);
|
||||||
|
|
||||||
// Write buffered information into newly created logger.
|
// Write buffered information into newly created logger.
|
||||||
|
@ -2454,7 +2446,6 @@ ipc.on('get-config', async event => {
|
||||||
storageUrl: config.get<string>('storageUrl'),
|
storageUrl: config.get<string>('storageUrl'),
|
||||||
updatesUrl: config.get<string>('updatesUrl'),
|
updatesUrl: config.get<string>('updatesUrl'),
|
||||||
resourcesUrl: config.get<string>('resourcesUrl'),
|
resourcesUrl: config.get<string>('resourcesUrl'),
|
||||||
artCreatorUrl: config.get<string>('artCreatorUrl'),
|
|
||||||
cdnUrl0: config.get<string>('cdn.0'),
|
cdnUrl0: config.get<string>('cdn.0'),
|
||||||
cdnUrl2: config.get<string>('cdn.2'),
|
cdnUrl2: config.get<string>('cdn.2'),
|
||||||
cdnUrl3: config.get<string>('cdn.3'),
|
cdnUrl3: config.get<string>('cdn.3'),
|
||||||
|
@ -2605,11 +2596,6 @@ function handleSignalRoute(route: ParsedSignalRoute) {
|
||||||
packId: route.args.packId,
|
packId: route.args.packId,
|
||||||
packKey: Buffer.from(route.args.packKey, 'hex').toString('base64'),
|
packKey: Buffer.from(route.args.packKey, 'hex').toString('base64'),
|
||||||
});
|
});
|
||||||
} else if (route.key === 'artAuth') {
|
|
||||||
mainWindow.webContents.send('authorize-art-creator', {
|
|
||||||
token: route.args.token,
|
|
||||||
pubKeyBase64: route.args.pubKey,
|
|
||||||
});
|
|
||||||
} else if (route.key === 'groupInvites') {
|
} else if (route.key === 'groupInvites') {
|
||||||
mainWindow.webContents.send('show-group-via-link', {
|
mainWindow.webContents.send('show-group-via-link', {
|
||||||
value: route.args.inviteCode,
|
value: route.args.inviteCode,
|
||||||
|
@ -2895,7 +2881,6 @@ async function showStickerCreatorWindow() {
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
...defaultWebPrefs,
|
...defaultWebPrefs,
|
||||||
partition: STICKER_CREATOR_PARTITION,
|
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
nodeIntegrationInWorker: false,
|
nodeIntegrationInWorker: false,
|
||||||
sandbox: true,
|
sandbox: true,
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
"contentProxyUrl": "http://contentproxy.signal.org:443",
|
"contentProxyUrl": "http://contentproxy.signal.org:443",
|
||||||
"updatesUrl": "https://updates2.signal.org/desktop",
|
"updatesUrl": "https://updates2.signal.org/desktop",
|
||||||
"resourcesUrl": "https://updates2.signal.org",
|
"resourcesUrl": "https://updates2.signal.org",
|
||||||
"artCreatorUrl": "https://create.staging.signal.art",
|
|
||||||
"updatesPublicKey": "05fd7dd3de7149dc0a127909fee7de0f7620ddd0de061b37a2c303e37de802a401",
|
"updatesPublicKey": "05fd7dd3de7149dc0a127909fee7de0f7620ddd0de061b37a2c303e37de802a401",
|
||||||
"sfuUrl": "https://sfu.staging.voip.signal.org/",
|
"sfuUrl": "https://sfu.staging.voip.signal.org/",
|
||||||
"challengeUrl": "https://signalcaptchas.org/staging/challenge/generate.html",
|
"challengeUrl": "https://signalcaptchas.org/staging/challenge/generate.html",
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
"2": "https://cdn2.signal.org",
|
"2": "https://cdn2.signal.org",
|
||||||
"3": "https://cdn3.signal.org"
|
"3": "https://cdn3.signal.org"
|
||||||
},
|
},
|
||||||
"artCreatorUrl": "https://create.signal.art",
|
|
||||||
"sfuUrl": "https://sfu.voip.signal.org/",
|
"sfuUrl": "https://sfu.voip.signal.org/",
|
||||||
"challengeUrl": "https://signalcaptchas.org/challenge/generate.html",
|
"challengeUrl": "https://signalcaptchas.org/challenge/generate.html",
|
||||||
"registrationChallengeUrl": "https://signalcaptchas.org/registration/generate.html",
|
"registrationChallengeUrl": "https://signalcaptchas.org/registration/generate.html",
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
"focus-trap-react": "10.1.1",
|
"focus-trap-react": "10.1.1",
|
||||||
"memoizee": "0.4.15",
|
"memoizee": "0.4.15",
|
||||||
"npm-run-all": "4.1.5",
|
"npm-run-all": "4.1.5",
|
||||||
"p-limit": "4.0.0",
|
|
||||||
"protobufjs": "7.2.5",
|
"protobufjs": "7.2.5",
|
||||||
"protobufjs-cli": "1.1.1",
|
"protobufjs-cli": "1.1.1",
|
||||||
"qrcode-generator": "1.4.4",
|
"qrcode-generator": "1.4.4",
|
||||||
|
|
1
sticker-creator/src/types.d.ts
vendored
1
sticker-creator/src/types.d.ts
vendored
|
@ -6,7 +6,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
export type Credentials = Readonly<{
|
export type Credentials = Readonly<{
|
||||||
baseUrl?: string;
|
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
// Copyright 2022 Signal Messenger, LLC
|
// Copyright 2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import b64 from 'base64-js';
|
|
||||||
import pLimit from 'p-limit';
|
|
||||||
import type { infer as zInfer } from 'zod';
|
|
||||||
import z from 'zod';
|
|
||||||
|
|
||||||
import { type ArtType } from '../constants';
|
import { type ArtType } from '../constants';
|
||||||
import { type Credentials } from '../types.d';
|
import { type EncryptResult } from './crypto';
|
||||||
import { type EncryptResult, getRandomString } from './crypto';
|
|
||||||
|
|
||||||
const MAX_PARALLEL_UPLOADS = 10;
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
interface Window {
|
interface Window {
|
||||||
getCredentials(): Promise<Credentials>;
|
uploadStickerPack(
|
||||||
|
manifest: Uint8Array,
|
||||||
|
stickers: ReadonlyArray<Uint8Array>,
|
||||||
|
onProgres?: () => void
|
||||||
|
): Promise<string>;
|
||||||
installStickerPack(packId: string, key: string): void;
|
installStickerPack(packId: string, key: string): void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,172 +21,33 @@ export type UploadOptions = Readonly<{
|
||||||
onProgress?: () => void;
|
onProgress?: () => void;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type UploadResult = Readonly<{
|
|
||||||
key: string;
|
|
||||||
packId: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
async function getSchemas() {
|
|
||||||
const UploadAttributes = z.object({
|
|
||||||
acl: z.string(),
|
|
||||||
algorithm: z.string(),
|
|
||||||
credential: z.string(),
|
|
||||||
date: z.string(),
|
|
||||||
id: z.number(),
|
|
||||||
key: z.string(),
|
|
||||||
policy: z.string(),
|
|
||||||
signature: z.string(),
|
|
||||||
securityToken: z.string(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const FormResponse = z.object({
|
|
||||||
packId: z.string(),
|
|
||||||
manifest: UploadAttributes,
|
|
||||||
art: z.array(UploadAttributes),
|
|
||||||
uploadURL: z.string(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return { UploadAttributes, FormResponse };
|
|
||||||
}
|
|
||||||
|
|
||||||
type Schemas = Awaited<ReturnType<typeof getSchemas>>;
|
|
||||||
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
|
|
||||||
export class APIError extends Error {
|
export class APIError extends Error {
|
||||||
constructor(message: string, public readonly errorMessageI18nKey: string) {
|
constructor(message: string, public readonly errorMessageI18nKey: string) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type UploadResult = Readonly<{
|
||||||
|
key: string;
|
||||||
|
packId: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
export async function upload(
|
export async function upload(
|
||||||
encryptResult: EncryptResult,
|
encryptResult: EncryptResult,
|
||||||
{ artType, onProgress }: UploadOptions
|
{ onProgress }: UploadOptions
|
||||||
): Promise<UploadResult> {
|
): Promise<UploadResult> {
|
||||||
const {
|
const { encryptedManifest, encryptedImages, key } = encryptResult;
|
||||||
encryptedManifest: manifest,
|
|
||||||
encryptedImages: images,
|
|
||||||
key,
|
|
||||||
} = encryptResult;
|
|
||||||
|
|
||||||
const credentials = await window.getCredentials();
|
const packId = await window.uploadStickerPack(
|
||||||
const { baseUrl = '' } = credentials;
|
encryptedManifest,
|
||||||
|
encryptedImages,
|
||||||
const auth = b64.fromByteArray(
|
onProgress
|
||||||
encoder.encode([credentials.username, credentials.password].join(':'))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const res = await fetch(
|
window.installStickerPack(packId, key);
|
||||||
`${baseUrl}/api/form?artType=${artType}&artCount=${images.length}`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
authorization: `Basic ${auth}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (res.status === 401 || res.status === 403) {
|
|
||||||
throw new APIError(
|
|
||||||
'Credentials expired',
|
|
||||||
'StickerCreator--Toasts--expired-credenitals'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`Request failed, status: ${res.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { FormResponse } = await getSchemas();
|
|
||||||
|
|
||||||
const form = FormResponse.parse(await res.json());
|
|
||||||
if (form.art.length !== images.length) {
|
|
||||||
throw new Error('Invalid form data, image count mismatch');
|
|
||||||
}
|
|
||||||
|
|
||||||
const limiter = pLimit(MAX_PARALLEL_UPLOADS);
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
limiter(async () => {
|
|
||||||
await uploadAttachment(form.uploadURL, form.manifest, manifest);
|
|
||||||
onProgress?.();
|
|
||||||
}),
|
|
||||||
...images.map((image, index) =>
|
|
||||||
limiter(async () => {
|
|
||||||
await uploadAttachment(form.uploadURL, form.art[index], image);
|
|
||||||
onProgress?.();
|
|
||||||
})
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
|
|
||||||
window.installStickerPack(form.packId, key);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
packId: form.packId,
|
packId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadAttachment(
|
|
||||||
uploadURL: string,
|
|
||||||
{
|
|
||||||
key,
|
|
||||||
credential,
|
|
||||||
acl,
|
|
||||||
algorithm,
|
|
||||||
date,
|
|
||||||
policy,
|
|
||||||
signature,
|
|
||||||
securityToken,
|
|
||||||
}: zInfer<Schemas['UploadAttributes']>,
|
|
||||||
encryptedData: Uint8Array
|
|
||||||
): Promise<void> {
|
|
||||||
// Note: when using the boundary string in the POST body, it needs to be
|
|
||||||
// prefixed by an extra --, and the final boundary string at the end gets a
|
|
||||||
// -- prefix and a -- suffix.
|
|
||||||
const boundaryString = getRandomString().replace(/=/g, '');
|
|
||||||
const CRLF = '\r\n';
|
|
||||||
const getSection = (name: string, value: string) =>
|
|
||||||
[
|
|
||||||
`--${boundaryString}`,
|
|
||||||
`Content-Disposition: form-data; name="${name}"${CRLF}`,
|
|
||||||
value,
|
|
||||||
].join(CRLF);
|
|
||||||
|
|
||||||
const start = [
|
|
||||||
getSection('key', key),
|
|
||||||
getSection('x-amz-credential', credential),
|
|
||||||
getSection('acl', acl),
|
|
||||||
getSection('x-amz-algorithm', algorithm),
|
|
||||||
getSection('x-amz-date', date),
|
|
||||||
getSection('policy', policy),
|
|
||||||
getSection('x-amz-signature', signature),
|
|
||||||
getSection('x-amz-security-token', securityToken),
|
|
||||||
getSection('Content-Type', 'application/octet-stream'),
|
|
||||||
`--${boundaryString}`,
|
|
||||||
'Content-Disposition: form-data; name="file"',
|
|
||||||
`Content-Type: application/octet-stream${CRLF}${CRLF}`,
|
|
||||||
].join(CRLF);
|
|
||||||
const end = `${CRLF}--${boundaryString}--${CRLF}`;
|
|
||||||
|
|
||||||
const startBuffer = encoder.encode(start);
|
|
||||||
const endBuffer = encoder.encode(end);
|
|
||||||
|
|
||||||
const contentLength =
|
|
||||||
startBuffer.length + encryptedData.length + endBuffer.length;
|
|
||||||
const body = new Uint8Array(contentLength);
|
|
||||||
body.set(startBuffer, 0);
|
|
||||||
body.set(encryptedData, startBuffer.length);
|
|
||||||
body.set(endBuffer, startBuffer.length + encryptedData.length);
|
|
||||||
|
|
||||||
const res = await fetch(uploadURL, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'content-length': contentLength.toString(),
|
|
||||||
'content-type': `multipart/form-data; boundary=${boundaryString}`,
|
|
||||||
},
|
|
||||||
body,
|
|
||||||
});
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error('Failed to upload attachment');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3108,13 +3108,6 @@ optionator@^0.9.1:
|
||||||
type-check "^0.4.0"
|
type-check "^0.4.0"
|
||||||
word-wrap "^1.2.3"
|
word-wrap "^1.2.3"
|
||||||
|
|
||||||
p-limit@4.0.0, p-limit@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644"
|
|
||||||
integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==
|
|
||||||
dependencies:
|
|
||||||
yocto-queue "^1.0.0"
|
|
||||||
|
|
||||||
p-limit@^3.0.2:
|
p-limit@^3.0.2:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
|
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
|
||||||
|
@ -3122,6 +3115,13 @@ p-limit@^3.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
yocto-queue "^0.1.0"
|
yocto-queue "^0.1.0"
|
||||||
|
|
||||||
|
p-limit@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644"
|
||||||
|
integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==
|
||||||
|
dependencies:
|
||||||
|
yocto-queue "^1.0.0"
|
||||||
|
|
||||||
p-locate@^5.0.0:
|
p-locate@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
|
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type {
|
import type {
|
||||||
AuthorizeArtCreatorDataType,
|
|
||||||
ContactModalStateType,
|
ContactModalStateType,
|
||||||
DeleteMessagesPropsType,
|
DeleteMessagesPropsType,
|
||||||
EditHistoryMessagesType,
|
EditHistoryMessagesType,
|
||||||
|
@ -96,11 +95,6 @@ export type PropsType = {
|
||||||
// UsernameOnboarding
|
// UsernameOnboarding
|
||||||
usernameOnboardingState: UsernameOnboardingState;
|
usernameOnboardingState: UsernameOnboardingState;
|
||||||
renderUsernameOnboarding: () => JSX.Element;
|
renderUsernameOnboarding: () => JSX.Element;
|
||||||
// AuthArtCreatorModal
|
|
||||||
authArtCreatorData?: AuthorizeArtCreatorDataType;
|
|
||||||
isAuthorizingArtCreator?: boolean;
|
|
||||||
cancelAuthorizeArtCreator: () => unknown;
|
|
||||||
confirmAuthorizeArtCreator: () => unknown;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function GlobalModalContainer({
|
export function GlobalModalContainer({
|
||||||
|
@ -166,11 +160,6 @@ export function GlobalModalContainer({
|
||||||
// UsernameOnboarding
|
// UsernameOnboarding
|
||||||
usernameOnboardingState,
|
usernameOnboardingState,
|
||||||
renderUsernameOnboarding,
|
renderUsernameOnboarding,
|
||||||
// AuthArtCreatorModal
|
|
||||||
authArtCreatorData,
|
|
||||||
isAuthorizingArtCreator,
|
|
||||||
cancelAuthorizeArtCreator,
|
|
||||||
confirmAuthorizeArtCreator,
|
|
||||||
}: PropsType): JSX.Element | null {
|
}: PropsType): JSX.Element | null {
|
||||||
// We want the following dialogs to show in this order:
|
// We want the following dialogs to show in this order:
|
||||||
// 1. Errors
|
// 1. Errors
|
||||||
|
@ -289,28 +278,5 @@ export function GlobalModalContainer({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authArtCreatorData) {
|
|
||||||
return (
|
|
||||||
<ConfirmationDialog
|
|
||||||
dialogName="GlobalModalContainer.authArtCreator"
|
|
||||||
cancelText={i18n('icu:AuthArtCreator--dialog--dismiss')}
|
|
||||||
cancelButtonVariant={ButtonVariant.Secondary}
|
|
||||||
i18n={i18n}
|
|
||||||
isSpinning={isAuthorizingArtCreator}
|
|
||||||
onClose={cancelAuthorizeArtCreator}
|
|
||||||
actions={[
|
|
||||||
{
|
|
||||||
text: i18n('icu:AuthArtCreator--dialog--confirm'),
|
|
||||||
style: 'affirmative',
|
|
||||||
action: confirmAuthorizeArtCreator,
|
|
||||||
autoClose: false,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{i18n('icu:AuthArtCreator--dialog--message')}
|
|
||||||
</ConfirmationDialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ import type { RecipientsByConversation } from './stories';
|
||||||
import type { SafetyNumberChangeSource } from '../../components/SafetyNumberChangeDialog';
|
import type { SafetyNumberChangeSource } from '../../components/SafetyNumberChangeDialog';
|
||||||
import type { EditState as ProfileEditorEditState } from '../../components/ProfileEditor';
|
import type { EditState as ProfileEditorEditState } from '../../components/ProfileEditor';
|
||||||
import type { StateType as RootStateType } from '../reducer';
|
import type { StateType as RootStateType } from '../reducer';
|
||||||
import * as Errors from '../../types/errors';
|
|
||||||
import * as SingleServePromise from '../../services/singleServePromise';
|
import * as SingleServePromise from '../../services/singleServePromise';
|
||||||
import * as Stickers from '../../types/Stickers';
|
import * as Stickers from '../../types/Stickers';
|
||||||
import { UsernameOnboardingState } from '../../types/globalModals';
|
import { UsernameOnboardingState } from '../../types/globalModals';
|
||||||
|
@ -28,18 +27,13 @@ import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||||
import { longRunningTaskWrapper } from '../../util/longRunningTaskWrapper';
|
import { longRunningTaskWrapper } from '../../util/longRunningTaskWrapper';
|
||||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||||
import { isGroupV1 } from '../../util/whatTypeOfConversation';
|
import { isGroupV1 } from '../../util/whatTypeOfConversation';
|
||||||
import { authorizeArtCreator } from '../../textsecure/authorizeArtCreator';
|
|
||||||
import type { AuthorizeArtCreatorOptionsType } from '../../textsecure/authorizeArtCreator';
|
|
||||||
import { getGroupMigrationMembers } from '../../groups';
|
import { getGroupMigrationMembers } from '../../groups';
|
||||||
import { ToastType } from '../../types/Toast';
|
|
||||||
import {
|
import {
|
||||||
MESSAGE_CHANGED,
|
MESSAGE_CHANGED,
|
||||||
MESSAGE_DELETED,
|
MESSAGE_DELETED,
|
||||||
MESSAGE_EXPIRED,
|
MESSAGE_EXPIRED,
|
||||||
actions as conversationsActions,
|
actions as conversationsActions,
|
||||||
} from './conversations';
|
} from './conversations';
|
||||||
import { SHOW_TOAST } from './toast';
|
|
||||||
import type { ShowToastActionType } from './toast';
|
|
||||||
import { isDownloaded } from '../../types/Attachment';
|
import { isDownloaded } from '../../types/Attachment';
|
||||||
import type { ButtonVariant } from '../../components/Button';
|
import type { ButtonVariant } from '../../components/Button';
|
||||||
import type { MessageRequestState } from '../../components/conversation/MessageRequestActionsConfirmation';
|
import type { MessageRequestState } from '../../components/conversation/MessageRequestActionsConfirmation';
|
||||||
|
@ -73,8 +67,6 @@ export type SafetyNumberChangedBlockingDataType = ReadonlyDeep<{
|
||||||
promiseUuid: SingleServePromise.SingleServePromiseIdString;
|
promiseUuid: SingleServePromise.SingleServePromiseIdString;
|
||||||
source?: SafetyNumberChangeSource;
|
source?: SafetyNumberChangeSource;
|
||||||
}>;
|
}>;
|
||||||
export type AuthorizeArtCreatorDataType =
|
|
||||||
ReadonlyDeep<AuthorizeArtCreatorOptionsType>;
|
|
||||||
|
|
||||||
type MigrateToGV2PropsType = ReadonlyDeep<{
|
type MigrateToGV2PropsType = ReadonlyDeep<{
|
||||||
areWeInvited: boolean;
|
areWeInvited: boolean;
|
||||||
|
@ -87,7 +79,6 @@ type MigrateToGV2PropsType = ReadonlyDeep<{
|
||||||
export type GlobalModalsStateType = ReadonlyDeep<{
|
export type GlobalModalsStateType = ReadonlyDeep<{
|
||||||
addUserToAnotherGroupModalContactId?: string;
|
addUserToAnotherGroupModalContactId?: string;
|
||||||
aboutContactModalContactId?: string;
|
aboutContactModalContactId?: string;
|
||||||
authArtCreatorData?: AuthorizeArtCreatorDataType;
|
|
||||||
contactModalState?: ContactModalStateType;
|
contactModalState?: ContactModalStateType;
|
||||||
deleteMessagesProps?: DeleteMessagesPropsType;
|
deleteMessagesProps?: DeleteMessagesPropsType;
|
||||||
editHistoryMessages?: EditHistoryMessagesType;
|
editHistoryMessages?: EditHistoryMessagesType;
|
||||||
|
@ -100,7 +91,6 @@ export type GlobalModalsStateType = ReadonlyDeep<{
|
||||||
forwardMessagesProps?: ForwardMessagesPropsType;
|
forwardMessagesProps?: ForwardMessagesPropsType;
|
||||||
gv2MigrationProps?: MigrateToGV2PropsType;
|
gv2MigrationProps?: MigrateToGV2PropsType;
|
||||||
hasConfirmationModal: boolean;
|
hasConfirmationModal: boolean;
|
||||||
isAuthorizingArtCreator?: boolean;
|
|
||||||
isProfileEditorVisible: boolean;
|
isProfileEditorVisible: boolean;
|
||||||
isShortcutGuideModalVisible: boolean;
|
isShortcutGuideModalVisible: boolean;
|
||||||
isSignalConnectionsVisible: boolean;
|
isSignalConnectionsVisible: boolean;
|
||||||
|
@ -157,13 +147,7 @@ const TOGGLE_MESSAGE_REQUEST_ACTIONS_CONFIRMATION =
|
||||||
'globalModals/TOGGLE_MESSAGE_REQUEST_ACTIONS_CONFIRMATION';
|
'globalModals/TOGGLE_MESSAGE_REQUEST_ACTIONS_CONFIRMATION';
|
||||||
const CLOSE_SHORTCUT_GUIDE_MODAL = 'globalModals/CLOSE_SHORTCUT_GUIDE_MODAL';
|
const CLOSE_SHORTCUT_GUIDE_MODAL = 'globalModals/CLOSE_SHORTCUT_GUIDE_MODAL';
|
||||||
const SHOW_SHORTCUT_GUIDE_MODAL = 'globalModals/SHOW_SHORTCUT_GUIDE_MODAL';
|
const SHOW_SHORTCUT_GUIDE_MODAL = 'globalModals/SHOW_SHORTCUT_GUIDE_MODAL';
|
||||||
const SHOW_AUTH_ART_CREATOR = 'globalModals/SHOW_AUTH_ART_CREATOR';
|
|
||||||
const TOGGLE_CONFIRMATION_MODAL = 'globalModals/TOGGLE_CONFIRMATION_MODAL';
|
const TOGGLE_CONFIRMATION_MODAL = 'globalModals/TOGGLE_CONFIRMATION_MODAL';
|
||||||
const CANCEL_AUTH_ART_CREATOR = 'globalModals/CANCEL_AUTH_ART_CREATOR';
|
|
||||||
const CONFIRM_AUTH_ART_CREATOR_PENDING =
|
|
||||||
'globalModals/CONFIRM_AUTH_ART_CREATOR_PENDING';
|
|
||||||
const CONFIRM_AUTH_ART_CREATOR_FULFILLED =
|
|
||||||
'globalModals/CONFIRM_AUTH_ART_CREATOR_FULFILLED';
|
|
||||||
const SHOW_EDIT_HISTORY_MODAL = 'globalModals/SHOW_EDIT_HISTORY_MODAL';
|
const SHOW_EDIT_HISTORY_MODAL = 'globalModals/SHOW_EDIT_HISTORY_MODAL';
|
||||||
const CLOSE_EDIT_HISTORY_MODAL = 'globalModals/CLOSE_EDIT_HISTORY_MODAL';
|
const CLOSE_EDIT_HISTORY_MODAL = 'globalModals/CLOSE_EDIT_HISTORY_MODAL';
|
||||||
const TOGGLE_USERNAME_ONBOARDING = 'globalModals/TOGGLE_USERNAME_ONBOARDING';
|
const TOGGLE_USERNAME_ONBOARDING = 'globalModals/TOGGLE_USERNAME_ONBOARDING';
|
||||||
|
@ -332,23 +316,6 @@ type ShowShortcutGuideModalActionType = ReadonlyDeep<{
|
||||||
type: typeof SHOW_SHORTCUT_GUIDE_MODAL;
|
type: typeof SHOW_SHORTCUT_GUIDE_MODAL;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type ShowAuthArtCreatorActionType = ReadonlyDeep<{
|
|
||||||
type: typeof SHOW_AUTH_ART_CREATOR;
|
|
||||||
payload: AuthorizeArtCreatorDataType;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
type CancelAuthArtCreatorActionType = ReadonlyDeep<{
|
|
||||||
type: typeof CANCEL_AUTH_ART_CREATOR;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
type ConfirmAuthArtCreatorPendingActionType = ReadonlyDeep<{
|
|
||||||
type: typeof CONFIRM_AUTH_ART_CREATOR_PENDING;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
type ConfirmAuthArtCreatorFulfilledActionType = ReadonlyDeep<{
|
|
||||||
type: typeof CONFIRM_AUTH_ART_CREATOR_FULFILLED;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
type ShowEditHistoryModalActionType = ReadonlyDeep<{
|
type ShowEditHistoryModalActionType = ReadonlyDeep<{
|
||||||
type: typeof SHOW_EDIT_HISTORY_MODAL;
|
type: typeof SHOW_EDIT_HISTORY_MODAL;
|
||||||
payload: {
|
payload: {
|
||||||
|
@ -361,14 +328,11 @@ type CloseEditHistoryModalActionType = ReadonlyDeep<{
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type GlobalModalsActionType = ReadonlyDeep<
|
export type GlobalModalsActionType = ReadonlyDeep<
|
||||||
| CancelAuthArtCreatorActionType
|
|
||||||
| CloseEditHistoryModalActionType
|
| CloseEditHistoryModalActionType
|
||||||
| CloseErrorModalActionType
|
| CloseErrorModalActionType
|
||||||
| CloseGV2MigrationDialogActionType
|
| CloseGV2MigrationDialogActionType
|
||||||
| CloseShortcutGuideModalActionType
|
| CloseShortcutGuideModalActionType
|
||||||
| CloseStickerPackPreviewActionType
|
| CloseStickerPackPreviewActionType
|
||||||
| ConfirmAuthArtCreatorFulfilledActionType
|
|
||||||
| ConfirmAuthArtCreatorPendingActionType
|
|
||||||
| HideContactModalActionType
|
| HideContactModalActionType
|
||||||
| HideSendAnywayDialogActiontype
|
| HideSendAnywayDialogActiontype
|
||||||
| HideStoriesSettingsActionType
|
| HideStoriesSettingsActionType
|
||||||
|
@ -377,7 +341,6 @@ export type GlobalModalsActionType = ReadonlyDeep<
|
||||||
| MessageChangedActionType
|
| MessageChangedActionType
|
||||||
| MessageDeletedActionType
|
| MessageDeletedActionType
|
||||||
| MessageExpiredActionType
|
| MessageExpiredActionType
|
||||||
| ShowAuthArtCreatorActionType
|
|
||||||
| ShowContactModalActionType
|
| ShowContactModalActionType
|
||||||
| ShowEditHistoryModalActionType
|
| ShowEditHistoryModalActionType
|
||||||
| ShowErrorModalActionType
|
| ShowErrorModalActionType
|
||||||
|
@ -406,19 +369,16 @@ export type GlobalModalsActionType = ReadonlyDeep<
|
||||||
// Action Creators
|
// Action Creators
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
cancelAuthorizeArtCreator,
|
|
||||||
closeEditHistoryModal,
|
closeEditHistoryModal,
|
||||||
closeErrorModal,
|
closeErrorModal,
|
||||||
closeGV2MigrationDialog,
|
closeGV2MigrationDialog,
|
||||||
closeShortcutGuideModal,
|
closeShortcutGuideModal,
|
||||||
closeStickerPackPreview,
|
closeStickerPackPreview,
|
||||||
confirmAuthorizeArtCreator,
|
|
||||||
hideBlockingSafetyNumberChangeDialog,
|
hideBlockingSafetyNumberChangeDialog,
|
||||||
hideContactModal,
|
hideContactModal,
|
||||||
hideStoriesSettings,
|
hideStoriesSettings,
|
||||||
hideUserNotFoundModal,
|
hideUserNotFoundModal,
|
||||||
hideWhatsNewModal,
|
hideWhatsNewModal,
|
||||||
showAuthorizeArtCreator,
|
|
||||||
showBlockingSafetyNumberChangeDialog,
|
showBlockingSafetyNumberChangeDialog,
|
||||||
showContactModal,
|
showContactModal,
|
||||||
showEditHistoryModal,
|
showEditHistoryModal,
|
||||||
|
@ -790,25 +750,6 @@ function showShortcutGuideModal(): ShowShortcutGuideModalActionType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelAuthorizeArtCreator(): ThunkAction<
|
|
||||||
void,
|
|
||||||
RootStateType,
|
|
||||||
unknown,
|
|
||||||
CancelAuthArtCreatorActionType
|
|
||||||
> {
|
|
||||||
return async (dispatch, getState) => {
|
|
||||||
const data = getState().globalModals.authArtCreatorData;
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: CANCEL_AUTH_ART_CREATOR,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyOverMessageAttributesIntoEditHistory(
|
function copyOverMessageAttributesIntoEditHistory(
|
||||||
messageAttributes: ReadonlyDeep<MessageAttributesType>
|
messageAttributes: ReadonlyDeep<MessageAttributesType>
|
||||||
): EditHistoryMessagesType | undefined {
|
): EditHistoryMessagesType | undefined {
|
||||||
|
@ -860,54 +801,6 @@ function closeEditHistoryModal(): CloseEditHistoryModalActionType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showAuthorizeArtCreator(
|
|
||||||
data: AuthorizeArtCreatorDataType
|
|
||||||
): ShowAuthArtCreatorActionType {
|
|
||||||
return {
|
|
||||||
type: SHOW_AUTH_ART_CREATOR,
|
|
||||||
payload: data,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function confirmAuthorizeArtCreator(): ThunkAction<
|
|
||||||
void,
|
|
||||||
RootStateType,
|
|
||||||
unknown,
|
|
||||||
| ConfirmAuthArtCreatorPendingActionType
|
|
||||||
| ConfirmAuthArtCreatorFulfilledActionType
|
|
||||||
| CancelAuthArtCreatorActionType
|
|
||||||
| ShowToastActionType
|
|
||||||
> {
|
|
||||||
return async (dispatch, getState) => {
|
|
||||||
const data = getState().globalModals.authArtCreatorData;
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
dispatch({ type: CANCEL_AUTH_ART_CREATOR });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: CONFIRM_AUTH_ART_CREATOR_PENDING,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
await authorizeArtCreator(data);
|
|
||||||
} catch (err) {
|
|
||||||
log.error('authorizeArtCreator failed', Errors.toLogFormat(err));
|
|
||||||
dispatch({
|
|
||||||
type: SHOW_TOAST,
|
|
||||||
payload: {
|
|
||||||
toastType: ToastType.Error,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: CONFIRM_AUTH_ART_CREATOR_FULFILLED,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyOverMessageAttributesIntoForwardMessages(
|
function copyOverMessageAttributesIntoForwardMessages(
|
||||||
messagesProps: ReadonlyArray<ForwardMessagePropsType>,
|
messagesProps: ReadonlyArray<ForwardMessagePropsType>,
|
||||||
attributes: ReadonlyDeep<MessageAttributesType>
|
attributes: ReadonlyDeep<MessageAttributesType>
|
||||||
|
@ -1168,36 +1061,6 @@ export function reducer(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === CANCEL_AUTH_ART_CREATOR) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
authArtCreatorData: undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.type === SHOW_AUTH_ART_CREATOR) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
isAuthorizingArtCreator: false,
|
|
||||||
authArtCreatorData: action.payload,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.type === CONFIRM_AUTH_ART_CREATOR_PENDING) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
isAuthorizingArtCreator: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.type === CONFIRM_AUTH_ART_CREATOR_FULFILLED) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
isAuthorizingArtCreator: false,
|
|
||||||
authArtCreatorData: undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.type === SHOW_EDIT_HISTORY_MODAL) {
|
if (action.type === SHOW_EDIT_HISTORY_MODAL) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|
|
@ -90,7 +90,6 @@ export const SmartGlobalModalContainer = memo(
|
||||||
const {
|
const {
|
||||||
aboutContactModalContactId,
|
aboutContactModalContactId,
|
||||||
addUserToAnotherGroupModalContactId,
|
addUserToAnotherGroupModalContactId,
|
||||||
authArtCreatorData,
|
|
||||||
contactModalState,
|
contactModalState,
|
||||||
deleteMessagesProps,
|
deleteMessagesProps,
|
||||||
editHistoryMessages,
|
editHistoryMessages,
|
||||||
|
@ -99,7 +98,6 @@ export const SmartGlobalModalContainer = memo(
|
||||||
forwardMessagesProps,
|
forwardMessagesProps,
|
||||||
messageRequestActionsConfirmationProps,
|
messageRequestActionsConfirmationProps,
|
||||||
notePreviewModalProps,
|
notePreviewModalProps,
|
||||||
isAuthorizingArtCreator,
|
|
||||||
isProfileEditorVisible,
|
isProfileEditorVisible,
|
||||||
isShortcutGuideModalVisible,
|
isShortcutGuideModalVisible,
|
||||||
isSignalConnectionsVisible,
|
isSignalConnectionsVisible,
|
||||||
|
@ -113,9 +111,7 @@ export const SmartGlobalModalContainer = memo(
|
||||||
} = useSelector(getGlobalModalsState);
|
} = useSelector(getGlobalModalsState);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
cancelAuthorizeArtCreator,
|
|
||||||
closeErrorModal,
|
closeErrorModal,
|
||||||
confirmAuthorizeArtCreator,
|
|
||||||
hideUserNotFoundModal,
|
hideUserNotFoundModal,
|
||||||
hideWhatsNewModal,
|
hideWhatsNewModal,
|
||||||
toggleSignalConnectionsModal,
|
toggleSignalConnectionsModal,
|
||||||
|
@ -218,10 +214,6 @@ export const SmartGlobalModalContainer = memo(
|
||||||
toggleSignalConnectionsModal={toggleSignalConnectionsModal}
|
toggleSignalConnectionsModal={toggleSignalConnectionsModal}
|
||||||
userNotFoundModalState={userNotFoundModalState}
|
userNotFoundModalState={userNotFoundModalState}
|
||||||
usernameOnboardingState={usernameOnboardingState}
|
usernameOnboardingState={usernameOnboardingState}
|
||||||
isAuthorizingArtCreator={isAuthorizingArtCreator}
|
|
||||||
authArtCreatorData={authArtCreatorData}
|
|
||||||
cancelAuthorizeArtCreator={cancelAuthorizeArtCreator}
|
|
||||||
confirmAuthorizeArtCreator={confirmAuthorizeArtCreator}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,16 +142,6 @@ describe('signalRoutes', () => {
|
||||||
check(`sgnl://signal.link/call#key=${foo}`, result);
|
check(`sgnl://signal.link/call#key=${foo}`, result);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('artAuth', () => {
|
|
||||||
const result: ParsedSignalRoute = {
|
|
||||||
key: 'artAuth',
|
|
||||||
args: { token: foo, pubKey: foo },
|
|
||||||
};
|
|
||||||
const check = createCheck({ hasWebUrl: false });
|
|
||||||
check(`sgnl://art-auth/?token=${foo}&pub_key=${foo}`, result);
|
|
||||||
check(`sgnl://art-auth?token=${foo}&pub_key=${foo}`, result);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('artAddStickers', () => {
|
it('artAddStickers', () => {
|
||||||
const result: ParsedSignalRoute = {
|
const result: ParsedSignalRoute = {
|
||||||
key: 'artAddStickers',
|
key: 'artAddStickers',
|
||||||
|
|
|
@ -52,7 +52,6 @@ export const AUTHENTICATED_CHANNEL_NAME = 'authenticated';
|
||||||
|
|
||||||
export type SocketManagerOptions = Readonly<{
|
export type SocketManagerOptions = Readonly<{
|
||||||
url: string;
|
url: string;
|
||||||
artCreatorUrl: string;
|
|
||||||
certificateAuthority: string;
|
certificateAuthority: string;
|
||||||
version: string;
|
version: string;
|
||||||
proxyUrl?: string;
|
proxyUrl?: string;
|
||||||
|
|
|
@ -14,7 +14,6 @@ import PQueue from 'p-queue';
|
||||||
import { v4 as getGuid } from 'uuid';
|
import { v4 as getGuid } from 'uuid';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import type { Readable } from 'stream';
|
import type { Readable } from 'stream';
|
||||||
import type { connection as WebSocket } from 'websocket';
|
|
||||||
|
|
||||||
import { Net } from '@signalapp/libsignal-client';
|
import { Net } from '@signalapp/libsignal-client';
|
||||||
import { assertDev, strictAssert } from '../util/assert';
|
import { assertDev, strictAssert } from '../util/assert';
|
||||||
|
@ -554,7 +553,6 @@ const URL_CALLS = {
|
||||||
getOnboardingStoryManifest:
|
getOnboardingStoryManifest:
|
||||||
'dynamic/desktop/stories/onboarding/manifest.json',
|
'dynamic/desktop/stories/onboarding/manifest.json',
|
||||||
getStickerPackUpload: 'v1/sticker/pack/form',
|
getStickerPackUpload: 'v1/sticker/pack/form',
|
||||||
getArtAuth: 'v1/art/auth',
|
|
||||||
getBackupCredentials: 'v1/archives/auth',
|
getBackupCredentials: 'v1/archives/auth',
|
||||||
getBackupCDNCredentials: 'v1/archives/auth/read',
|
getBackupCDNCredentials: 'v1/archives/auth/read',
|
||||||
getBackupUploadForm: 'v1/archives/upload/form',
|
getBackupUploadForm: 'v1/archives/upload/form',
|
||||||
|
@ -647,7 +645,6 @@ type InitializeOptionsType = {
|
||||||
storageUrl: string;
|
storageUrl: string;
|
||||||
updatesUrl: string;
|
updatesUrl: string;
|
||||||
resourcesUrl: string;
|
resourcesUrl: string;
|
||||||
artCreatorUrl: string;
|
|
||||||
cdnUrlObject: {
|
cdnUrlObject: {
|
||||||
readonly '0': string;
|
readonly '0': string;
|
||||||
readonly [propName: string]: string;
|
readonly [propName: string]: string;
|
||||||
|
@ -975,13 +972,6 @@ export type ReportMessageOptionsType = Readonly<{
|
||||||
token?: string;
|
token?: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
const artAuthZod = z.object({
|
|
||||||
username: z.string(),
|
|
||||||
password: z.string(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export type ArtAuthType = z.infer<typeof artAuthZod>;
|
|
||||||
|
|
||||||
const attachmentV3Response = z.object({
|
const attachmentV3Response = z.object({
|
||||||
cdn: z.literal(2).or(z.literal(3)),
|
cdn: z.literal(2).or(z.literal(3)),
|
||||||
key: z.string(),
|
key: z.string(),
|
||||||
|
@ -1149,6 +1139,23 @@ export type GetBackupInfoResponseType = z.infer<
|
||||||
typeof getBackupInfoResponseSchema
|
typeof getBackupInfoResponseSchema
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
const StickerPackUploadAttributesSchema = z.object({
|
||||||
|
acl: z.string(),
|
||||||
|
algorithm: z.string(),
|
||||||
|
credential: z.string(),
|
||||||
|
date: z.string(),
|
||||||
|
id: z.number(),
|
||||||
|
key: z.string(),
|
||||||
|
policy: z.string(),
|
||||||
|
signature: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const StickerPackUploadFormSchema = z.object({
|
||||||
|
packId: z.string(),
|
||||||
|
manifest: StickerPackUploadAttributesSchema,
|
||||||
|
stickers: z.array(StickerPackUploadAttributesSchema),
|
||||||
|
});
|
||||||
|
|
||||||
export type WebAPIType = {
|
export type WebAPIType = {
|
||||||
startRegistration(): unknown;
|
startRegistration(): unknown;
|
||||||
finishRegistration(baton: unknown): void;
|
finishRegistration(baton: unknown): void;
|
||||||
|
@ -1166,7 +1173,6 @@ export type WebAPIType = {
|
||||||
version: string,
|
version: string,
|
||||||
imageFiles: Array<string>
|
imageFiles: Array<string>
|
||||||
) => Promise<Array<Uint8Array>>;
|
) => Promise<Array<Uint8Array>>;
|
||||||
getArtAuth: () => Promise<ArtAuthType>;
|
|
||||||
getAttachmentFromBackupTier: (args: {
|
getAttachmentFromBackupTier: (args: {
|
||||||
mediaId: string;
|
mediaId: string;
|
||||||
backupDir: string;
|
backupDir: string;
|
||||||
|
@ -1237,7 +1243,6 @@ export type WebAPIType = {
|
||||||
getProvisioningResource: (
|
getProvisioningResource: (
|
||||||
handler: IRequestHandler
|
handler: IRequestHandler
|
||||||
) => Promise<IWebSocketResource>;
|
) => Promise<IWebSocketResource>;
|
||||||
getArtProvisioningSocket: (token: string) => Promise<WebSocket>;
|
|
||||||
getSenderCertificate: (
|
getSenderCertificate: (
|
||||||
withUuid?: boolean
|
withUuid?: boolean
|
||||||
) => Promise<GetSenderCertificateResultType>;
|
) => Promise<GetSenderCertificateResultType>;
|
||||||
|
@ -1280,7 +1285,7 @@ export type WebAPIType = {
|
||||||
) => Promise<UploadAvatarHeadersType | undefined>;
|
) => Promise<UploadAvatarHeadersType | undefined>;
|
||||||
putStickers: (
|
putStickers: (
|
||||||
encryptedManifest: Uint8Array,
|
encryptedManifest: Uint8Array,
|
||||||
encryptedStickers: Array<Uint8Array>,
|
encryptedStickers: ReadonlyArray<Uint8Array>,
|
||||||
onProgress?: () => void
|
onProgress?: () => void
|
||||||
) => Promise<string>;
|
) => Promise<string>;
|
||||||
reserveUsername: (
|
reserveUsername: (
|
||||||
|
@ -1471,7 +1476,6 @@ export function initialize({
|
||||||
storageUrl,
|
storageUrl,
|
||||||
updatesUrl,
|
updatesUrl,
|
||||||
resourcesUrl,
|
resourcesUrl,
|
||||||
artCreatorUrl,
|
|
||||||
directoryConfig,
|
directoryConfig,
|
||||||
cdnUrlObject,
|
cdnUrlObject,
|
||||||
certificateAuthority,
|
certificateAuthority,
|
||||||
|
@ -1493,9 +1497,6 @@ export function initialize({
|
||||||
if (!isString(resourcesUrl)) {
|
if (!isString(resourcesUrl)) {
|
||||||
throw new Error('WebAPI.initialize: Invalid updatesUrl (general)');
|
throw new Error('WebAPI.initialize: Invalid updatesUrl (general)');
|
||||||
}
|
}
|
||||||
if (!isString(artCreatorUrl)) {
|
|
||||||
throw new Error('WebAPI.initialize: Invalid artCreatorUrl');
|
|
||||||
}
|
|
||||||
if (!isObject(cdnUrlObject)) {
|
if (!isObject(cdnUrlObject)) {
|
||||||
throw new Error('WebAPI.initialize: Invalid cdnUrlObject');
|
throw new Error('WebAPI.initialize: Invalid cdnUrlObject');
|
||||||
}
|
}
|
||||||
|
@ -1558,7 +1559,6 @@ export function initialize({
|
||||||
|
|
||||||
const socketManager = new SocketManager(libsignalNet, {
|
const socketManager = new SocketManager(libsignalNet, {
|
||||||
url,
|
url,
|
||||||
artCreatorUrl,
|
|
||||||
certificateAuthority,
|
certificateAuthority,
|
||||||
version,
|
version,
|
||||||
proxyUrl,
|
proxyUrl,
|
||||||
|
@ -1667,8 +1667,6 @@ export function initialize({
|
||||||
fetchLinkPreviewMetadata,
|
fetchLinkPreviewMetadata,
|
||||||
finishRegistration,
|
finishRegistration,
|
||||||
getAccountForUsername,
|
getAccountForUsername,
|
||||||
getArtAuth,
|
|
||||||
getArtProvisioningSocket,
|
|
||||||
getAttachment,
|
getAttachment,
|
||||||
getAttachmentFromBackupTier,
|
getAttachmentFromBackupTier,
|
||||||
getAvatar,
|
getAvatar,
|
||||||
|
@ -3309,20 +3307,19 @@ export function initialize({
|
||||||
|
|
||||||
async function putStickers(
|
async function putStickers(
|
||||||
encryptedManifest: Uint8Array,
|
encryptedManifest: Uint8Array,
|
||||||
encryptedStickers: Array<Uint8Array>,
|
encryptedStickers: ReadonlyArray<Uint8Array>,
|
||||||
onProgress?: () => void
|
onProgress?: () => void
|
||||||
) {
|
) {
|
||||||
// Get manifest and sticker upload parameters
|
// Get manifest and sticker upload parameters
|
||||||
const { packId, manifest, stickers } = (await _ajax({
|
const formJson = await _ajax({
|
||||||
call: 'getStickerPackUpload',
|
call: 'getStickerPackUpload',
|
||||||
responseType: 'json',
|
responseType: 'json',
|
||||||
httpType: 'GET',
|
httpType: 'GET',
|
||||||
urlParameters: `/${encryptedStickers.length}`,
|
urlParameters: `/${encryptedStickers.length}`,
|
||||||
})) as {
|
});
|
||||||
packId: string;
|
|
||||||
manifest: ServerV2AttachmentType;
|
const { packId, manifest, stickers } =
|
||||||
stickers: ReadonlyArray<ServerV2AttachmentType>;
|
StickerPackUploadFormSchema.parse(formJson);
|
||||||
};
|
|
||||||
|
|
||||||
// Upload manifest
|
// Upload manifest
|
||||||
const manifestParams = makePutParams(manifest, encryptedManifest);
|
const manifestParams = makePutParams(manifest, encryptedManifest);
|
||||||
|
@ -4008,15 +4005,6 @@ export function initialize({
|
||||||
return socketManager.getProvisioningResource(handler);
|
return socketManager.getProvisioningResource(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getArtProvisioningSocket(token: string): Promise<WebSocket> {
|
|
||||||
return socketManager.connectExternalSocket({
|
|
||||||
url: `${artCreatorUrl}/api/socket?token=${token}`,
|
|
||||||
extraHeaders: {
|
|
||||||
origin: artCreatorUrl,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function cdsLookup({
|
async function cdsLookup({
|
||||||
e164s,
|
e164s,
|
||||||
acisAndAccessKeys = [],
|
acisAndAccessKeys = [],
|
||||||
|
@ -4030,19 +4018,5 @@ export function initialize({
|
||||||
useLibsignal,
|
useLibsignal,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Art
|
|
||||||
//
|
|
||||||
|
|
||||||
async function getArtAuth(): Promise<ArtAuthType> {
|
|
||||||
const response = await _ajax({
|
|
||||||
call: 'getArtAuth',
|
|
||||||
httpType: 'GET',
|
|
||||||
responseType: 'json',
|
|
||||||
});
|
|
||||||
|
|
||||||
return artAuthZod.parse(response);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
// Copyright 2022 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import { promisify } from 'util';
|
|
||||||
|
|
||||||
import { SignalService as Proto } from '../protobuf';
|
|
||||||
import { calculateAgreement, generateKeyPair } from '../Curve';
|
|
||||||
import { encryptAttachment, deriveSecrets } from '../Crypto';
|
|
||||||
import * as Bytes from '../Bytes';
|
|
||||||
|
|
||||||
const PROVISIONING_INFO = 'Art Service Provisioning Message';
|
|
||||||
|
|
||||||
export type AuthorizeArtCreatorOptionsType = Readonly<{
|
|
||||||
token: string;
|
|
||||||
pubKeyBase64: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export async function authorizeArtCreator({
|
|
||||||
token,
|
|
||||||
pubKeyBase64: theirPubKeyBase64,
|
|
||||||
}: AuthorizeArtCreatorOptionsType): Promise<void> {
|
|
||||||
const { server } = window.textsecure;
|
|
||||||
if (!server) {
|
|
||||||
throw new Error('Server not ready');
|
|
||||||
}
|
|
||||||
|
|
||||||
const auth = await server.getArtAuth();
|
|
||||||
|
|
||||||
const ourKeys = generateKeyPair();
|
|
||||||
const theirPubKey = Bytes.fromBase64(theirPubKeyBase64);
|
|
||||||
|
|
||||||
const secret = calculateAgreement(theirPubKey, ourKeys.privKey);
|
|
||||||
const [aesKey, macKey] = deriveSecrets(
|
|
||||||
secret,
|
|
||||||
new Uint8Array(64),
|
|
||||||
Bytes.fromString(PROVISIONING_INFO)
|
|
||||||
);
|
|
||||||
const keys = Bytes.concatenate([aesKey, macKey]);
|
|
||||||
|
|
||||||
const { ciphertext } = encryptAttachment({
|
|
||||||
plaintext: Proto.ArtProvisioningMessage.encode({
|
|
||||||
...auth,
|
|
||||||
}).finish(),
|
|
||||||
keys,
|
|
||||||
});
|
|
||||||
|
|
||||||
const envelope = Proto.ArtProvisioningEnvelope.encode({
|
|
||||||
publicKey: ourKeys.pubKey,
|
|
||||||
ciphertext,
|
|
||||||
}).finish();
|
|
||||||
|
|
||||||
const socket = await server.getArtProvisioningSocket(token);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await promisify(socket.sendBytes).call(socket, Buffer.from(envelope));
|
|
||||||
} finally {
|
|
||||||
socket.close(1000, 'goodbye');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -30,7 +30,6 @@ export type DirectoryConfigType = z.infer<typeof directoryConfigSchema>;
|
||||||
export const rendererConfigSchema = z.object({
|
export const rendererConfigSchema = z.object({
|
||||||
appInstance: configOptionalStringSchema,
|
appInstance: configOptionalStringSchema,
|
||||||
appStartInitialSpellcheckSetting: z.boolean(),
|
appStartInitialSpellcheckSetting: z.boolean(),
|
||||||
artCreatorUrl: configRequiredStringSchema,
|
|
||||||
buildCreation: z.number(),
|
buildCreation: z.number(),
|
||||||
buildExpiration: z.number(),
|
buildExpiration: z.number(),
|
||||||
cdnUrl0: configRequiredStringSchema,
|
cdnUrl0: configRequiredStringSchema,
|
||||||
|
|
|
@ -16,7 +16,6 @@ import * as Errors from '../types/errors';
|
||||||
import * as Stickers from '../types/Stickers';
|
import * as Stickers from '../types/Stickers';
|
||||||
|
|
||||||
import type { ConversationType } from '../state/ducks/conversations';
|
import type { ConversationType } from '../state/ducks/conversations';
|
||||||
import type { AuthorizeArtCreatorDataType } from '../state/ducks/globalModals';
|
|
||||||
import { calling } from '../services/calling';
|
import { calling } from '../services/calling';
|
||||||
import { resolveUsernameByLinkBase64 } from '../services/username';
|
import { resolveUsernameByLinkBase64 } from '../services/username';
|
||||||
import { writeProfile } from '../services/writeProfile';
|
import { writeProfile } from '../services/writeProfile';
|
||||||
|
@ -96,7 +95,6 @@ export type IPCEventsValuesType = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type IPCEventsCallbacksType = {
|
export type IPCEventsCallbacksType = {
|
||||||
openArtCreator(): Promise<void>;
|
|
||||||
getAvailableIODevices(): Promise<{
|
getAvailableIODevices(): Promise<{
|
||||||
availableCameras: Array<
|
availableCameras: Array<
|
||||||
Pick<MediaDeviceInfo, 'deviceId' | 'groupId' | 'kind' | 'label'>
|
Pick<MediaDeviceInfo, 'deviceId' | 'groupId' | 'kind' | 'label'>
|
||||||
|
@ -106,7 +104,6 @@ export type IPCEventsCallbacksType = {
|
||||||
}>;
|
}>;
|
||||||
addCustomColor: (customColor: CustomColorType) => void;
|
addCustomColor: (customColor: CustomColorType) => void;
|
||||||
addDarkOverlay: () => void;
|
addDarkOverlay: () => void;
|
||||||
authorizeArtCreator: (data: AuthorizeArtCreatorDataType) => void;
|
|
||||||
deleteAllData: () => Promise<void>;
|
deleteAllData: () => Promise<void>;
|
||||||
deleteAllMyStories: () => Promise<void>;
|
deleteAllMyStories: () => Promise<void>;
|
||||||
editCustomColor: (colorId: string, customColor: CustomColorType) => void;
|
editCustomColor: (colorId: string, customColor: CustomColorType) => void;
|
||||||
|
@ -141,6 +138,10 @@ export type IPCEventsCallbacksType = {
|
||||||
customColor?: { id: string; value: CustomColorType }
|
customColor?: { id: string; value: CustomColorType }
|
||||||
) => void;
|
) => void;
|
||||||
getDefaultConversationColor: () => DefaultConversationColorType;
|
getDefaultConversationColor: () => DefaultConversationColorType;
|
||||||
|
uploadStickerPack: (
|
||||||
|
manifest: Uint8Array,
|
||||||
|
stickers: ReadonlyArray<Uint8Array>
|
||||||
|
) => Promise<string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ValuesWithGetters = Omit<
|
type ValuesWithGetters = Omit<
|
||||||
|
@ -239,15 +240,6 @@ export function createIPCEvents(
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
openArtCreator: async () => {
|
|
||||||
const auth = await window.textsecure.server?.getArtAuth();
|
|
||||||
if (!auth) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.openArtCreator(auth);
|
|
||||||
},
|
|
||||||
|
|
||||||
getDeviceName: () => window.textsecure.storage.user.getDeviceName(),
|
getDeviceName: () => window.textsecure.storage.user.getDeviceName(),
|
||||||
getPhoneNumber: () => {
|
getPhoneNumber: () => {
|
||||||
try {
|
try {
|
||||||
|
@ -530,14 +522,6 @@ export function createIPCEvents(
|
||||||
});
|
});
|
||||||
document.body.prepend(newOverlay);
|
document.body.prepend(newOverlay);
|
||||||
},
|
},
|
||||||
authorizeArtCreator: (data: AuthorizeArtCreatorDataType) => {
|
|
||||||
// We can get these events even if the user has never linked this instance.
|
|
||||||
if (!Registration.everDone()) {
|
|
||||||
log.warn('authorizeArtCreator: Not registered, returning early');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.reduxActions.globalModals.showAuthorizeArtCreator(data);
|
|
||||||
},
|
|
||||||
removeDarkOverlay: () => {
|
removeDarkOverlay: () => {
|
||||||
const elems = document.querySelectorAll('.dark-overlay');
|
const elems = document.querySelectorAll('.dark-overlay');
|
||||||
|
|
||||||
|
@ -717,6 +701,16 @@ export function createIPCEvents(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uploadStickerPack: (
|
||||||
|
manifest: Uint8Array,
|
||||||
|
stickers: ReadonlyArray<Uint8Array>
|
||||||
|
): Promise<string> => {
|
||||||
|
strictAssert(window.textsecure.server, 'WebAPI must be available');
|
||||||
|
return window.textsecure.server.putStickers(manifest, stickers, () =>
|
||||||
|
ipcRenderer.send('art-creator:onUploadProgress')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
...overrideEvents,
|
...overrideEvents,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -439,38 +439,6 @@ export const artAddStickersRoute = _route('artAddStickers', {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Art Service Authentication
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* artAuthRoute.toAppUrl({
|
|
||||||
* token: "123",
|
|
||||||
* pubKey: "abc",
|
|
||||||
* })
|
|
||||||
* // URL { "sgnl://art-auth?token=123&pub_key=abc" }
|
|
||||||
*/
|
|
||||||
export const artAuthRoute = _route('artAuth', {
|
|
||||||
patterns: [_pattern('sgnl:', 'art-auth', '{/}?', { search: ':params' })],
|
|
||||||
schema: z.object({
|
|
||||||
token: paramSchema, // opaque
|
|
||||||
pubKey: paramSchema, // base64url
|
|
||||||
}),
|
|
||||||
parse(result) {
|
|
||||||
const params = new URLSearchParams(result.search.groups.params);
|
|
||||||
return {
|
|
||||||
token: params.get('token'),
|
|
||||||
pubKey: params.get('pub_key'),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
toAppUrl(args) {
|
|
||||||
const params = new URLSearchParams({
|
|
||||||
token: args.token,
|
|
||||||
pub_key: args.pubKey,
|
|
||||||
});
|
|
||||||
return new URL(`sgnl://art-auth?${params.toString()}`);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a conversation
|
* Show a conversation
|
||||||
* @example
|
* @example
|
||||||
|
@ -594,7 +562,6 @@ const _allSignalRoutes = [
|
||||||
captchaRoute,
|
captchaRoute,
|
||||||
linkCallRoute,
|
linkCallRoute,
|
||||||
artAddStickersRoute,
|
artAddStickersRoute,
|
||||||
artAuthRoute,
|
|
||||||
showConversationRoute,
|
showConversationRoute,
|
||||||
startCallLobbyRoute,
|
startCallLobbyRoute,
|
||||||
showWindowRoute,
|
showWindowRoute,
|
||||||
|
|
|
@ -341,24 +341,6 @@ ipc.on('show-group-via-link', (_event, info) => {
|
||||||
drop(window.Events.showGroupViaLink?.(info.value));
|
drop(window.Events.showGroupViaLink?.(info.value));
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.on('open-art-creator', () => {
|
|
||||||
drop(window.Events.openArtCreator());
|
|
||||||
});
|
|
||||||
|
|
||||||
window.openArtCreator = ({
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
}: {
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
}) => {
|
|
||||||
return ipc.invoke('open-art-creator', { username, password });
|
|
||||||
};
|
|
||||||
|
|
||||||
ipc.on('authorize-art-creator', (_event, info) => {
|
|
||||||
window.Events.authorizeArtCreator?.(info);
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.on('start-call-lobby', (_event, { conversationId }) => {
|
ipc.on('start-call-lobby', (_event, { conversationId }) => {
|
||||||
window.IPC.showWindow();
|
window.IPC.showWindow();
|
||||||
window.reduxActions?.calling?.startCallingLobby({
|
window.reduxActions?.calling?.startCallingLobby({
|
||||||
|
@ -458,3 +440,18 @@ ipc.on('show-release-notes', () => {
|
||||||
showReleaseNotes();
|
showReleaseNotes();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipc.on(
|
||||||
|
'art-creator:uploadStickerPack',
|
||||||
|
async (
|
||||||
|
event,
|
||||||
|
{
|
||||||
|
manifest,
|
||||||
|
stickers,
|
||||||
|
}: { manifest: Uint8Array; stickers: ReadonlyArray<Uint8Array> }
|
||||||
|
) => {
|
||||||
|
const packId = await window.Events?.uploadStickerPack(manifest, stickers);
|
||||||
|
|
||||||
|
event.sender.send('art-creator:uploadStickerPack:done', packId);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -27,7 +27,6 @@ window.WebAPI = window.textsecure.WebAPI.initialize({
|
||||||
storageUrl: config.storageUrl,
|
storageUrl: config.storageUrl,
|
||||||
updatesUrl: config.updatesUrl,
|
updatesUrl: config.updatesUrl,
|
||||||
resourcesUrl: config.resourcesUrl,
|
resourcesUrl: config.resourcesUrl,
|
||||||
artCreatorUrl: config.artCreatorUrl,
|
|
||||||
directoryConfig: config.directoryConfig,
|
directoryConfig: config.directoryConfig,
|
||||||
cdnUrlObject: {
|
cdnUrlObject: {
|
||||||
0: config.cdnUrl0,
|
0: config.cdnUrl0,
|
||||||
|
|
|
@ -3,8 +3,26 @@
|
||||||
|
|
||||||
import { contextBridge, ipcRenderer } from 'electron';
|
import { contextBridge, ipcRenderer } from 'electron';
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('getCredentials', async () =>
|
let onProgress: (() => void) | undefined;
|
||||||
ipcRenderer.invoke('get-art-creator-auth')
|
|
||||||
|
ipcRenderer.on('art-creator:onUploadProgress', () => {
|
||||||
|
onProgress?.();
|
||||||
|
});
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld(
|
||||||
|
'uploadStickerPack',
|
||||||
|
async (
|
||||||
|
manifest: Uint8Array,
|
||||||
|
stickers: Readonly<Uint8Array>,
|
||||||
|
newOnProgress: (() => void) | undefined
|
||||||
|
): Promise<string> => {
|
||||||
|
onProgress = newOnProgress;
|
||||||
|
|
||||||
|
return ipcRenderer.invoke('art-creator:uploadStickerPack', {
|
||||||
|
manifest,
|
||||||
|
stickers,
|
||||||
|
});
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld(
|
contextBridge.exposeInMainWorld(
|
||||||
|
|
Loading…
Reference in a new issue