174 lines
4.7 KiB
JavaScript
174 lines
4.7 KiB
JavaScript
/* global window */
|
|
const { ipcRenderer: ipc, remote } = require('electron');
|
|
const sharp = require('sharp');
|
|
const pify = require('pify');
|
|
const { readFile } = require('fs');
|
|
const config = require('url').parse(window.location.toString(), true).query;
|
|
const { noop, uniqBy } = require('lodash');
|
|
const pMap = require('p-map');
|
|
const { deriveStickerPackKey } = require('../js/modules/crypto');
|
|
const { makeGetter } = require('../preload_utils');
|
|
|
|
const { dialog } = remote;
|
|
const { systemPreferences } = remote.require('electron');
|
|
|
|
window.ROOT_PATH = window.location.href.startsWith('file') ? '../../' : '/';
|
|
window.PROTO_ROOT = '../../protos';
|
|
window.getEnvironment = () => config.environment;
|
|
window.getVersion = () => config.version;
|
|
window.getGuid = require('uuid/v4');
|
|
window.PQueue = require('p-queue');
|
|
|
|
window.localeMessages = ipc.sendSync('locale-data');
|
|
|
|
require('../js/logging');
|
|
|
|
window.log.info('sticker-creator starting up...');
|
|
|
|
const Signal = require('../js/modules/signal');
|
|
|
|
window.Signal = Signal.setup({});
|
|
|
|
const { initialize: initializeWebAPI } = require('../js/modules/web_api');
|
|
|
|
const WebAPI = initializeWebAPI({
|
|
url: config.serverUrl,
|
|
cdnUrl: config.cdnUrl,
|
|
certificateAuthority: config.certificateAuthority,
|
|
contentProxyUrl: config.contentProxyUrl,
|
|
proxyUrl: config.proxyUrl,
|
|
});
|
|
|
|
window.convertToWebp = async (path, width = 512, height = 512) => {
|
|
const imgBuffer = await pify(readFile)(path);
|
|
const sharpImg = sharp(imgBuffer);
|
|
const meta = await sharpImg.metadata();
|
|
|
|
const buffer = await sharpImg
|
|
.resize({
|
|
width,
|
|
height,
|
|
fit: 'contain',
|
|
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
})
|
|
.webp()
|
|
.toBuffer();
|
|
|
|
return {
|
|
path,
|
|
buffer,
|
|
src: `data:image/webp;base64,${buffer.toString('base64')}`,
|
|
meta,
|
|
};
|
|
};
|
|
|
|
window.encryptAndUpload = async (
|
|
manifest,
|
|
stickers,
|
|
cover,
|
|
onProgress = noop
|
|
) => {
|
|
const usernameItem = await window.Signal.Data.getItemById('number_id');
|
|
const passwordItem = await window.Signal.Data.getItemById('password');
|
|
|
|
if (!usernameItem || !passwordItem) {
|
|
const { message } = window.localeMessages[
|
|
'StickerCreator--Authentication--error'
|
|
];
|
|
|
|
dialog.showMessageBox({
|
|
type: 'warning',
|
|
message,
|
|
});
|
|
|
|
throw new Error(message);
|
|
}
|
|
|
|
const { value: username } = usernameItem;
|
|
const { value: password } = passwordItem;
|
|
|
|
const packKey = window.libsignal.crypto.getRandomBytes(32);
|
|
const encryptionKey = await deriveStickerPackKey(packKey);
|
|
const iv = window.libsignal.crypto.getRandomBytes(16);
|
|
|
|
const server = WebAPI.connect({ username, password });
|
|
|
|
const uniqueStickers = uniqBy([...stickers, { webp: cover }], 'webp');
|
|
|
|
const manifestProto = new window.textsecure.protobuf.StickerPack();
|
|
manifestProto.title = manifest.title;
|
|
manifestProto.author = manifest.author;
|
|
manifestProto.stickers = stickers.map(({ emoji }, id) => {
|
|
const s = new window.textsecure.protobuf.StickerPack.Sticker();
|
|
s.id = id;
|
|
s.emoji = emoji;
|
|
|
|
return s;
|
|
});
|
|
const coverSticker = new window.textsecure.protobuf.StickerPack.Sticker();
|
|
coverSticker.id =
|
|
uniqueStickers.length === stickers.length ? 0 : uniqueStickers.length - 1;
|
|
coverSticker.emoji = '';
|
|
manifestProto.cover = coverSticker;
|
|
|
|
const encryptedManifest = await encrypt(
|
|
manifestProto.toArrayBuffer(),
|
|
encryptionKey,
|
|
iv
|
|
);
|
|
const encryptedStickers = await pMap(
|
|
uniqueStickers,
|
|
({ webp }) => encrypt(webp.buffer, encryptionKey, iv),
|
|
{ concurrency: 3 }
|
|
);
|
|
|
|
const packId = await server.putStickers(
|
|
encryptedManifest,
|
|
encryptedStickers,
|
|
onProgress
|
|
);
|
|
|
|
const hexKey = window.Signal.Crypto.hexFromBytes(packKey);
|
|
|
|
ipc.send('install-sticker-pack', packId, hexKey);
|
|
|
|
return { packId, key: hexKey };
|
|
};
|
|
|
|
async function encrypt(data, key, iv) {
|
|
const { ciphertext } = await window.textsecure.crypto.encryptAttachment(
|
|
// Convert Node Buffer to ArrayBuffer
|
|
window.Signal.Crypto.concatenateBytes(data),
|
|
key,
|
|
iv
|
|
);
|
|
|
|
return ciphertext;
|
|
}
|
|
|
|
const getThemeSetting = makeGetter('theme-setting');
|
|
|
|
async function resolveTheme() {
|
|
const theme = (await getThemeSetting()) || 'light';
|
|
if (process.platform === 'darwin' && theme === 'system') {
|
|
return systemPreferences.isDarkMode() ? 'dark' : 'light';
|
|
}
|
|
return theme;
|
|
}
|
|
|
|
async function applyTheme() {
|
|
window.document.body.classList.remove('dark-theme');
|
|
window.document.body.classList.remove('light-theme');
|
|
window.document.body.classList.add(`${await resolveTheme()}-theme`);
|
|
}
|
|
|
|
window.addEventListener('DOMContentLoaded', applyTheme);
|
|
|
|
if (systemPreferences && systemPreferences.subscribeNotification) {
|
|
systemPreferences.subscribeNotification(
|
|
'AppleInterfaceThemeChangedNotification',
|
|
applyTheme
|
|
);
|
|
}
|
|
|
|
window.log.info('sticker-creator preload complete...');
|