chore: load secrets at runtime

pull/270/head
dessant 4 years ago
parent 11a196c48b
commit e927330f43

@ -22,6 +22,8 @@ jobs:
run: yarn
- name: Build artifacts
run: yarn build:prod:zip:all
env:
BUSTER_SECRETS: ${{ secrets.BUSTER_SECRETS }}
- name: Hash artifacts
run: sha256sum artifacts/*/*
if: startsWith(github.ref, 'refs/tags/v')

1
.gitignore vendored

@ -1,4 +1,5 @@
.assets/
secrets.json
node_modules/
artifacts/

@ -11,8 +11,9 @@ const jsonmin = require('gulp-jsonmin');
const htmlmin = require('gulp-htmlmin');
const imagemin = require('gulp-imagemin');
const del = require('del');
const {ensureDirSync} = require('fs-extra');
const {ensureDirSync, readJsonSync} = require('fs-extra');
const sharp = require('sharp');
const CryptoJS = require('crypto-js');
const targetEnv = process.env.TARGET_ENV || 'firefox';
const isProduction = process.env.NODE_ENV === 'production';
@ -193,6 +194,33 @@ See the LICENSE file for further information.
return src(['LICENSE']).pipe(dest(distDir));
}
function secrets(done) {
try {
let data = process.env.BUSTER_SECRETS;
if (data) {
data = JSON.parse(data);
} else {
data = readJsonSync('secrets.json');
}
data = JSON.stringify(data);
const key = CryptoJS.SHA256(
readFileSync(path.join(distDir, 'src/background/script.js')).toString() +
readFileSync(path.join(distDir, 'src/solve/script.js')).toString()
).toString();
const ciphertext = CryptoJS.AES.encrypt(data, key).toString();
writeFileSync(path.join(distDir, 'secrets.json.enc'), ciphertext);
} catch (err) {
console.log(
'Secrets have not been set, secrets.json.enc will not be included in the extension package.'
);
}
done();
}
function zip(done) {
exec(
`web-ext build -s dist/${targetEnv} -a artifacts/${targetEnv} -n '{name}-{version}-${targetEnv}.zip' --overwrite-dest`,
@ -217,7 +245,9 @@ function inspect(done) {
exports.build = series(
clean,
parallel(js, html, css, images, fonts, locale, manifest, license)
parallel(js, html, css, images, fonts, locale, manifest, license),
secrets
);
exports.zip = zip;
exports.inspect = inspect;
exports.secrets = secrets;

@ -43,6 +43,7 @@
"audiobuffer-to-wav": "^1.0.0",
"bowser": "^2.11.0",
"core-js": "^3.6.5",
"crypto-js": "^4.0.0",
"ext-components": "dessant/ext-components#^0.4.0",
"ext-contribute": "dessant/ext-contribute#^0.3.3",
"fontsource-roboto": "^3.0.3",

@ -0,0 +1,34 @@
{
"witApiKeys": {
"arabic": "",
"bengali": "",
"catalan": "",
"chinese": "",
"dutch": "",
"english": "",
"finnish": "",
"french": "",
"german": "",
"hindi": "",
"indonesian": "",
"italian": "",
"japanese": "",
"kannada": "",
"korean": "",
"malay": "",
"malayalam": "",
"marathi": "",
"polish": "",
"portuguese": "",
"russian": "",
"sinhala": "",
"spanish": "",
"swedish": "",
"tamil": "",
"telugu": "",
"thai": "",
"turkish": "",
"urdu": "",
"vietnamese": ""
}
}

@ -304,6 +304,11 @@
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_marathi": {
"message": "Marathi",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_polish": {
"message": "Polish",
"description": "Value of the option."

@ -1,5 +1,8 @@
import browser from 'webextension-polyfill';
import audioBufferToWav from 'audiobuffer-to-wav';
import aes from 'crypto-js/aes';
import sha256 from 'crypto-js/sha256';
import utf8 from 'crypto-js/enc-utf8';
import {initStorage} from 'storage/init';
import storage from 'storage/storage';
@ -29,9 +32,10 @@ import {
ibmSpeechApiUrls,
microsoftSpeechApiUrls
} from 'utils/data';
import {targetEnv, clientAppVersion, witApiKeys} from 'utils/config';
import {targetEnv, clientAppVersion} from 'utils/config';
let nativePort;
let secrets;
function getFrameClientPos(index) {
let currentIndex = -1;
@ -221,12 +225,37 @@ async function prepareAudio(audio) {
return audioBufferToWav(audioSlice);
}
async function loadSecrets() {
try {
const ciphertext = await (await fetch('/secrets.json.enc')).text();
const key = sha256(
(await (await fetch('/src/background/script.js')).text()) +
(await (await fetch('/src/solve/script.js')).text())
).toString();
secrets = JSON.parse(aes.decrypt(ciphertext, key).toString(utf8));
} catch (err) {
secrets = {};
const {speechService} = await storage.get('speechService', 'sync');
if (speechService === 'witSpeechApiDemo') {
await storage.set({speechService: 'witSpeechApi'}, 'sync');
}
}
}
async function getWitSpeechApiKey(speechService, language) {
if (speechService === 'witSpeechApiDemo') {
if (language === 'english') {
return witApiKeys[language][getRandomInt(1, 4) - 1];
} else {
return witApiKeys[language];
if (!secrets) {
await loadSecrets();
}
const apiKeys = secrets.witApiKeys;
if (apiKeys) {
const apiKey = apiKeys[language];
if (Array.isArray(apiKey)) {
return apiKey[getRandomInt(1, apiKey.length) - 1];
}
return apiKey;
}
} else {
const {witSpeechApiKeys: apiKeys} = await storage.get(
@ -453,7 +482,11 @@ async function transcribeAudio(audioUrl, lang) {
}
}
return solution;
if (!solution) {
showNotification({messageId: 'error_captchaNotSolved'});
} else {
return solution;
}
}
async function onMessage(request, sender) {
@ -540,7 +573,7 @@ async function onInstall(details) {
await browser.tabs.insertCSS(tabId, {
frameId,
runAt: 'document_idle',
file: 'src/solve/reset-button.css'
file: '/src/solve/reset-button.css'
});
await browser.tabs.executeScript(tabId, {

@ -341,10 +341,6 @@ async function solve(simulateUserInput, clickEvent) {
});
if (!solution) {
browser.runtime.sendMessage({
id: 'notification',
messageId: 'error_captchaNotSolved'
});
return;
}

@ -2,41 +2,4 @@ const targetEnv = process.env.TARGET_ENV;
const clientAppVersion = '0.3.0';
const witApiKeys = {
arabic: 'AD6RLFYBWRGGJD76SWKALZMUFVGMVCTB',
bengali: 'ACETQ4IVS5ITSUTSWBETY2QZKBJVIQAI',
catalan: 'YBAZZV6ITGFD3C2QX7CANYQPMGUOI7RK',
chinese: 'KBBALJMRKYDJJDMC4NJ32VWCBKFJFIIU',
dutch: 'T43TEUNW4HDQFNUTIA3EYTTD4A22AS4H',
english: [
'BQE4QJJNYC6JVTDULHYIZHQOQFWUVDCQ',
'EQAXGAJVZIMI3YMILN2XQZY7IWGUPKGL',
'AA3LFNYPDNXX4MUDQQJNLT74YFRQ3M6F',
'DRTXENV66YE44PRYOJGWPX2BPGZNPYTQ'
],
finnish: '3GOWLMYD7DUY72XTPJW6QTVZSK2QEAPT',
french: 'JLNITTO2D4KMEOGQ6MTSN634ADK62VZ7',
german: 'LPVVXWRBFTVBOOHZAEJC3QRM6E3UMD7I',
hindi: 'GZY4V5WN75QHO4Q5PMCU5AIDKQZLKP4L',
indonesian: 'NBKNPYO6ZTVSSTH2AT3H5DM7OUOIAN3F',
italian: 'JNSYW453QWIXNR3TOCE2K7NO5GGU3KYL',
japanese: 'S3IDY5JTJVJ6XBISPGZBZQHQXO23BXEB',
kannada: 'MZ7NKAQGQI3T4JH6YRIEL6K4AWDCDE3A',
korean: '5UWNE4YDBZTSNWWBYC4XZEWJGBUI24YL',
malay: 'YW73R7QWXQT23GE5CTM4R2IVNCH2KMS3',
malayalam: 'KIZY64QLOGZ7JWJWX2DKE247KV6VHAYT',
polish: 'G73FWND7N5O3ZCSBCHF6NDOV2QIXW2MF',
portuguese: 'N7D57ZCGWLRSMQNHQYKWC3OHVNTZI5UT',
russian: 'V2IMQUEC5M7TSYAY3VCKSGQ7HOCWFPFY',
sinhala: 'N4RYKKDHSXB6IID6JILOX5A27UJLBJJ7',
spanish: 'JU6JOEJBHRH7IILGSSUVEYO552JUNMG4',
swedish: '33RMFTS5OKLEWV2KGX2HMTP7M3VCKXC4',
tamil: 'MNIEHY7BQVMEU6BBJBL57E4QYNHOUIDB',
telugu: 'MXE6BFOLRMR72GLUFEK3Y7NOUBPV5W4G',
thai: 'MA3JUGAZNCCTBBTO2K7HR3RWJ3LILU6E',
turkish: 'HZJRJNL3C3KLBXZQ4BPIODYRKXXRKYCL',
urdu: 'T5FSZMLJ55LNPBIILM2A2SVEA3YIIYL3',
vietnamese: 'ULJN5SUWA3HJKLPKHOSTOH5AJSSWN5H3'
};
export {targetEnv, clientAppVersion, witApiKeys};
export {targetEnv, clientAppVersion};

@ -290,7 +290,7 @@ const captchaWitSpeechApiLangCodes = {
lt: '', // Lithuanian
ms: 'malay', // Malay
ml: 'malayalam', // Malayalam
mr: '', // Marathi
mr: 'marathi', // Marathi
mn: '', // Mongolian
no: '', // Norwegian
fa: '', // Persian

@ -3730,6 +3730,11 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
crypto-js@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.0.0.tgz#2904ab2677a9d042856a2ea2ef80de92e4a36dcc"
integrity sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==
crypto-random-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"

Loading…
Cancel
Save