mirror of
https://github.com/paritytech/banana_split.git
synced 2026-09-12 19:51:03 +05:00
fix #35 migrate to Typescript
This commit is contained in:
parent
77ba6c7939
commit
c79f43b613
@ -13,7 +13,8 @@ module.exports = {
|
||||
globalReturn: false,
|
||||
impliedStrict: false,
|
||||
jsx: false
|
||||
}
|
||||
},
|
||||
parser: "@typescript-eslint/parser"
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
module.exports = {
|
||||
moduleFileExtensions: ["js", "jsx", "json", "vue"],
|
||||
moduleFileExtensions: ["js", "jsx", "ts", "tsx", "json", "vue"],
|
||||
transform: {
|
||||
"^.+\\.vue$": "vue-jest",
|
||||
".+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$":
|
||||
"jest-transform-stub",
|
||||
"^.+\\.jsx?$": "babel-jest"
|
||||
"^.+\\.(js|jsx|ts|tsx)$": "ts-jest"
|
||||
},
|
||||
moduleNameMapper: {
|
||||
"^@/(.*)$": "<rootDir>/src/$1"
|
||||
|
||||
15
package.json
15
package.json
@ -19,17 +19,20 @@
|
||||
"scryptsy": "^2.0.0",
|
||||
"secrets.js-grempe": "^1.1.0",
|
||||
"tweetnacl": "^1.0.0",
|
||||
"typescript": "^4.4.3",
|
||||
"vue": "^2.5.17",
|
||||
"vue-qrcode-reader": "^1.3.1",
|
||||
"vue-qriously": "^1.1.1",
|
||||
"vue-router": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-eslint": "^3.1.5",
|
||||
"@vue/cli-plugin-unit-jest": "^3.1.1",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@typescript-eslint/parser": "^4.31.2",
|
||||
"@vue/cli-plugin-eslint": "^4.5.13",
|
||||
"@vue/cli-plugin-typescript": "^4.5.13",
|
||||
"@vue/cli-plugin-unit-jest": "^4.5.13",
|
||||
"@vue/cli-service": "^3.1.4",
|
||||
"@vue/test-utils": "^1.0.0-beta.20",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"eslint": "^5.8.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
@ -40,7 +43,9 @@
|
||||
"html-webpack-inline-source-plugin": "1.0.0-beta.2",
|
||||
"html-webpack-plugin": "4.0.0-beta.4",
|
||||
"jest-junit": "^6.0.1",
|
||||
"vue-template-compiler": "^2.5.17"
|
||||
"ts-jest": "^26.4.4",
|
||||
"vue-template-compiler": "^2.5.17",
|
||||
"vuetype": "^0.3.2"
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
@ -50,7 +55,7 @@
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
"not ie <= 11"
|
||||
],
|
||||
"jest-junit": {
|
||||
"outputDirectory": ".test-results/jest",
|
||||
|
||||
19
src/App.vue
19
src/App.vue
@ -35,22 +35,23 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GeneralInfo from "./components/GeneralInfo";
|
||||
import GoOfflineInfo from "./components/GoOfflineInfo";
|
||||
import SavePageInfo from "./components/SavePageInfo";
|
||||
import ForkMe from "./components/ForkMe";
|
||||
<script lang="ts">
|
||||
import GeneralInfo from "./components/GeneralInfo.vue";
|
||||
import GoOfflineInfo from "./components/GoOfflineInfo.vue";
|
||||
import SavePageInfo from "./components/SavePageInfo.vue";
|
||||
import ForkMe from "./components/ForkMe.vue";
|
||||
|
||||
import { version } from "../package.json";
|
||||
import Vue from "vue";
|
||||
|
||||
export default {
|
||||
export default Vue.extend({
|
||||
name: "App",
|
||||
components: { GeneralInfo, GoOfflineInfo, SavePageInfo, ForkMe },
|
||||
computed: {
|
||||
localFile: function() {
|
||||
localFile(): boolean {
|
||||
return window.location.protocol === "file:";
|
||||
},
|
||||
secure: function() {
|
||||
secure(): boolean {
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
return this.localFile && !this.isOnline;
|
||||
} else {
|
||||
@ -64,7 +65,7 @@ export default {
|
||||
return process.env.GIT_REVISION;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@ -2,16 +2,24 @@
|
||||
<canvas v-canvas-message="text" class="canvasText" width="0" height="28px" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
<script lang="ts">
|
||||
import Vue, { VNodeDirective } from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "CanvasText",
|
||||
directives: {
|
||||
canvasMessage: function(canvasElement, binding) {
|
||||
var context = canvasElement.getContext("2d");
|
||||
canvasMessage: function(el: HTMLElement, binding: VNodeDirective): void {
|
||||
const canvasElement = el as HTMLCanvasElement,
|
||||
context = canvasElement.getContext("2d");
|
||||
if (!context) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn("Failed to find canvasElement context");
|
||||
return;
|
||||
}
|
||||
context.clearRect(0, 0, canvasElement.width, canvasElement.height);
|
||||
context.fillStyle = "black";
|
||||
context.font = "20px Arial";
|
||||
var textSize = context.measureText(binding.value);
|
||||
const textSize = context.measureText(binding.value);
|
||||
canvasElement.setAttribute("width", textSize.width + 20 + "px");
|
||||
context.font = "20px Arial";
|
||||
context.fillText(binding.value, 15, 20);
|
||||
@ -23,5 +31,5 @@ export default {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "ForkMe",
|
||||
props: {
|
||||
|
||||
@ -39,19 +39,21 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "GeneralInfo",
|
||||
data: function() {
|
||||
return { unfolded: true };
|
||||
},
|
||||
created: function() {
|
||||
var self = this;
|
||||
const self = this;
|
||||
this.$eventHub.$on("foldGeneralInfo", function() {
|
||||
self.unfolded = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "GoOfflineInfo"
|
||||
};
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "SavePageInfo"
|
||||
};
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
<script>
|
||||
import Vue from "vue";
|
||||
<script lang="ts">
|
||||
import Vue, { VNode } from "vue";
|
||||
import ShardQrCode from "./ShardQrCode.vue";
|
||||
|
||||
import ShardQrCode from "./ShardQrCode";
|
||||
|
||||
export default {
|
||||
export default Vue.extend({
|
||||
name: "ShardInfo",
|
||||
components: { ShardQrCode },
|
||||
props: {
|
||||
@ -24,18 +23,23 @@ export default {
|
||||
this.vm.$el.remove();
|
||||
this.vm.$destroy();
|
||||
},
|
||||
render: function() {
|
||||
var element = document.createElement("div");
|
||||
var print = document.getElementById("print");
|
||||
render: function(): VNode {
|
||||
const element = document.createElement("div");
|
||||
const print = document.getElementById("print");
|
||||
if (print) {
|
||||
print.appendChild(element);
|
||||
var passedProps = this.$props;
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn("Failed to find `print` element");
|
||||
}
|
||||
const passedProps = this.$props;
|
||||
this.vm = new Vue({
|
||||
el: element,
|
||||
render: function(h) {
|
||||
return h(ShardQrCode, { props: passedProps });
|
||||
}
|
||||
});
|
||||
return this.vm;
|
||||
return this.vm.$vnode;
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -26,9 +26,10 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import { version } from "../../package.json";
|
||||
export default {
|
||||
export default Vue.extend({
|
||||
name: "ShardQrCode",
|
||||
props: {
|
||||
title: {
|
||||
@ -59,7 +60,7 @@ export default {
|
||||
return process.env.GIT_REVISION;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@ -1,8 +1,18 @@
|
||||
import Vue from "vue";
|
||||
|
||||
declare module "vue/types/vue" {
|
||||
interface Vue {
|
||||
$eventHub: Vue;
|
||||
vm: Vue;
|
||||
isOnline: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
import VueQriously from "vue-qriously";
|
||||
Vue.use(VueQriously);
|
||||
|
||||
// @ts-ignore
|
||||
import QrcodeStream from "vue-qrcode-reader";
|
||||
Vue.use(QrcodeStream);
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { VueConstructor } from "vue";
|
||||
|
||||
const plugin = {
|
||||
install(Vue) {
|
||||
install(Vue: VueConstructor) {
|
||||
const vm = new Vue({
|
||||
data: {
|
||||
online: window.navigator.onLine
|
||||
@ -1,9 +1,9 @@
|
||||
import Vue from "vue";
|
||||
import Router from "vue-router";
|
||||
|
||||
import Info from "./views/Info";
|
||||
import Share from "./views/Share";
|
||||
import Combine from "./views/Combine";
|
||||
import Info from "./views/Info.vue";
|
||||
import Share from "./views/Share.vue";
|
||||
import Combine from "./views/Combine.vue";
|
||||
|
||||
Vue.use(Router);
|
||||
|
||||
@ -4,6 +4,20 @@ const SCRYPT = require("scryptsy");
|
||||
|
||||
const SECRETS = require("secrets.js-grempe");
|
||||
|
||||
export type Shard = {
|
||||
data: string;
|
||||
version: number;
|
||||
title: string;
|
||||
nonce: string;
|
||||
requiredShards: number;
|
||||
};
|
||||
|
||||
type EncryptedData = {
|
||||
value: Uint8Array;
|
||||
nonce: Uint8Array;
|
||||
salt: Uint8Array;
|
||||
};
|
||||
|
||||
const HexEncodeArray = [
|
||||
"0",
|
||||
"1",
|
||||
@ -23,34 +37,34 @@ const HexEncodeArray = [
|
||||
"f"
|
||||
];
|
||||
|
||||
function strToUint8Array(str) {
|
||||
return new TextEncoder("utf-8").encode(str);
|
||||
function strToUint8Array(str: string): Uint8Array {
|
||||
return new TextEncoder().encode(str);
|
||||
}
|
||||
|
||||
function uint8ArrayToStr(arr) {
|
||||
function uint8ArrayToStr(arr: Uint8Array): string {
|
||||
return new TextDecoder("utf-8").decode(arr);
|
||||
}
|
||||
|
||||
function hashString(str) {
|
||||
function hashString(str: string): Uint8Array {
|
||||
return CRYPTO.hash(strToUint8Array(str));
|
||||
}
|
||||
|
||||
function hexify(arr) {
|
||||
var s = "";
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
function hexify(arr: Uint8Array): string {
|
||||
let s = "";
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
// `i` is a numerical counter for the loop and is never changed outside of there
|
||||
// therefore `i` is numerical, and is safe to use as an array index
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
var code = arr[i];
|
||||
const code = arr[i];
|
||||
s += HexEncodeArray[code >>> 4];
|
||||
s += HexEncodeArray[code & 0x0f];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function dehexify(str) {
|
||||
var arr = new Uint8Array(str.length / 2);
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
function dehexify(str: string): Uint8Array {
|
||||
const arr = new Uint8Array(str.length / 2);
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
// `i` is a numerical counter for the loop and is never changed outside of there
|
||||
// therefore `i` is numerical, and is safe to use as an array index
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
@ -59,9 +73,13 @@ function dehexify(str) {
|
||||
return arr;
|
||||
}
|
||||
|
||||
function encrypt(data, salt, passphrase) {
|
||||
var key = SCRYPT(passphrase, Buffer.from(salt), 1 << 15, 8, 1, 32);
|
||||
var nonce = CRYPTO.randomBytes(24);
|
||||
function encrypt(
|
||||
data: string,
|
||||
salt: Uint8Array,
|
||||
passphrase: string
|
||||
): EncryptedData {
|
||||
const key = SCRYPT(passphrase, Buffer.from(salt), 1 << 15, 8, 1, 32);
|
||||
const nonce = CRYPTO.randomBytes(24);
|
||||
return {
|
||||
nonce,
|
||||
salt,
|
||||
@ -69,23 +87,34 @@ function encrypt(data, salt, passphrase) {
|
||||
};
|
||||
}
|
||||
|
||||
function decrypt(data, salt, passphrase, nonce) {
|
||||
var key = SCRYPT(passphrase, Buffer.from(salt.buffer), 1 << 15, 8, 1, 32);
|
||||
function decrypt(
|
||||
data: Uint8Array,
|
||||
salt: Uint8Array,
|
||||
passphrase: string,
|
||||
nonce: Uint8Array
|
||||
): Uint8Array {
|
||||
const key = SCRYPT(passphrase, Buffer.from(salt.buffer), 1 << 15, 8, 1, 32);
|
||||
// This is a false positive, `secretbox.open` is unrelated to `fs.open`
|
||||
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
||||
return CRYPTO.secretbox.open(data, nonce, key);
|
||||
}
|
||||
|
||||
function share(data, title, passphrase, totalShards, requiredShards) {
|
||||
var salt = hashString(title);
|
||||
var encrypted = encrypt(data, salt, passphrase);
|
||||
var nonce = BASE64.fromByteArray(encrypted.nonce);
|
||||
var hexEncrypted = hexify(encrypted.value);
|
||||
function share(
|
||||
data: string,
|
||||
title: string,
|
||||
passphrase: string,
|
||||
totalShards: number,
|
||||
requiredShards: number
|
||||
): string[] {
|
||||
const salt = hashString(title),
|
||||
encrypted = encrypt(data, salt, passphrase),
|
||||
nonce = BASE64.fromByteArray(encrypted.nonce),
|
||||
hexEncrypted = hexify(encrypted.value);
|
||||
return SECRETS.share(hexEncrypted, totalShards, requiredShards).map(function(
|
||||
shard
|
||||
shard: string
|
||||
) {
|
||||
// First char is non-hex (base36) and signifies the bitfield size of our share
|
||||
var encodedShard =
|
||||
const encodedShard =
|
||||
shard[0] + BASE64.fromByteArray(dehexify(shard.slice(1)));
|
||||
|
||||
return JSON.stringify({
|
||||
@ -100,7 +129,7 @@ function share(data, title, passphrase, totalShards, requiredShards) {
|
||||
});
|
||||
}
|
||||
|
||||
function parse(payload) {
|
||||
function parse(payload: string): Shard {
|
||||
let parsed = JSON.parse(payload);
|
||||
return {
|
||||
version: parsed.v || 0, // 'undefined' version is treated as 0
|
||||
@ -111,8 +140,8 @@ function parse(payload) {
|
||||
};
|
||||
}
|
||||
|
||||
function reconstruct(shardObjects, passphrase) {
|
||||
var shardsRequirements = shardObjects.map(shard => shard.requiredShards);
|
||||
function reconstruct(shardObjects: Shard[], passphrase: string): string {
|
||||
const shardsRequirements = shardObjects.map(shard => shard.requiredShards);
|
||||
if (!shardsRequirements.every(r => r === shardsRequirements[0])) {
|
||||
throw "Mismatching min shards requirement among shards!";
|
||||
}
|
||||
@ -122,38 +151,39 @@ function reconstruct(shardObjects, passphrase) {
|
||||
} provided`;
|
||||
}
|
||||
|
||||
var nonces = shardObjects.map(shard => shard.nonce);
|
||||
const nonces = shardObjects.map(shard => shard.nonce);
|
||||
if (!nonces.every(n => n === nonces[0])) {
|
||||
throw "Nonces mismatch among shards!";
|
||||
}
|
||||
|
||||
var titles = shardObjects.map(shard => shard.title);
|
||||
const titles = shardObjects.map(shard => shard.title);
|
||||
if (!titles.every(t => t === titles[0])) {
|
||||
throw "Titles mismatch among shards!";
|
||||
}
|
||||
|
||||
var versions = shardObjects.map(shard => shard.version);
|
||||
const versions = shardObjects.map(shard => shard.version);
|
||||
if (!versions.every(v => v === versions[0])) {
|
||||
throw "Versions mismatch along shards!";
|
||||
}
|
||||
|
||||
switch (versions[0]) {
|
||||
case 0:
|
||||
var shardData = shardObjects.map(shard => shard.data);
|
||||
var encryptedSecret = SECRETS.combine(shardData);
|
||||
var secret = dehexify(encryptedSecret);
|
||||
var nonce = dehexify(nonces[0]);
|
||||
var salt = hashString(titles[0]);
|
||||
var shardData = shardObjects.map(shard => shard.data),
|
||||
encryptedSecret = SECRETS.combine(shardData),
|
||||
secret = dehexify(encryptedSecret),
|
||||
nonce = dehexify(nonces[0]),
|
||||
salt = hashString(titles[0]);
|
||||
return uint8ArrayToStr(decrypt(secret, salt, passphrase, nonce));
|
||||
|
||||
case 1:
|
||||
var shardDataV1 = shardObjects.map(
|
||||
shard => shard.data[0] + hexify(BASE64.toByteArray(shard.data.slice(1)))
|
||||
);
|
||||
var encryptedSecretV1 = SECRETS.combine(shardDataV1);
|
||||
var secretV1 = dehexify(encryptedSecretV1);
|
||||
var nonceV1 = BASE64.toByteArray(nonces[0]);
|
||||
var saltV1 = hashString(titles[0]);
|
||||
shard =>
|
||||
shard.data[0] + hexify(BASE64.toByteArray(shard.data.slice(1)))
|
||||
),
|
||||
encryptedSecretV1 = SECRETS.combine(shardDataV1),
|
||||
secretV1 = dehexify(encryptedSecretV1),
|
||||
nonceV1 = BASE64.toByteArray(nonces[0]),
|
||||
saltV1 = hashString(titles[0]);
|
||||
return uint8ArrayToStr(decrypt(secretV1, saltV1, passphrase, nonceV1));
|
||||
|
||||
default:
|
||||
@ -7778,12 +7778,13 @@ export default {
|
||||
"zoom"
|
||||
],
|
||||
|
||||
generate: function(amount) {
|
||||
const Crypto = window.crypto || window.msCrypto;
|
||||
var keys = new Uint16Array(amount);
|
||||
generate: function(amount: number) {
|
||||
// @ts-ignore
|
||||
const Crypto = window.crypto || window.msCrypto; // for IE 11;
|
||||
const keys = new Uint16Array(amount);
|
||||
Crypto.getRandomValues(keys);
|
||||
|
||||
var wordlist = this.wordlist;
|
||||
const wordlist = this.wordlist;
|
||||
return (
|
||||
Array.from(keys.map(key => key % 2048))
|
||||
// `key` is an element in `keys`, which can only hold Uints;
|
||||
@ -53,33 +53,46 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
/*eslint no-console: ["error", { allow: ["warn", "error"] }] */
|
||||
|
||||
import crypto from "../util/crypto";
|
||||
import crypto, { Shard } from "../util/crypto";
|
||||
import Vue from "vue";
|
||||
|
||||
export default {
|
||||
type CombineData = {
|
||||
title: string;
|
||||
nonce: string;
|
||||
shards: Shard[];
|
||||
qrCodes: Set<string>;
|
||||
requiredShards?: number;
|
||||
passphrase: string;
|
||||
recoveredSecret?: string;
|
||||
PLACEHOLDER_QR_DATA: string;
|
||||
};
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Combine",
|
||||
data: function() {
|
||||
data(): CombineData {
|
||||
return {
|
||||
title: "",
|
||||
nonce: "",
|
||||
shards: new Set(),
|
||||
qrCodes: [],
|
||||
shards: [],
|
||||
qrCodes: new Set(),
|
||||
requiredShards: undefined,
|
||||
passphrase: "",
|
||||
recoveredSecret: undefined
|
||||
recoveredSecret: undefined,
|
||||
PLACEHOLDER_QR_DATA: ""
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
needMoreShards: function() {
|
||||
return !this.requiredShards || this.qrCodes.length < this.requiredShards;
|
||||
needMoreShards(): boolean {
|
||||
return !this.requiredShards || this.shards.length < this.requiredShards;
|
||||
},
|
||||
remainingCodes: function() {
|
||||
remainingCodes(): number {
|
||||
if (!this.requiredShards) {
|
||||
return 0;
|
||||
} else {
|
||||
return this.requiredShards - this.qrCodes.length;
|
||||
return this.requiredShards - this.shards.length;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -87,16 +100,19 @@ export default {
|
||||
this.$eventHub.$emit("foldGeneralInfo");
|
||||
},
|
||||
methods: {
|
||||
onDecode: function(result) {
|
||||
var parsed = crypto.parse(result);
|
||||
if (!this.shards.has(parsed.data)) {
|
||||
if (this.title && this.title != parsed.title) {
|
||||
onDecode: function(result: string) {
|
||||
if (this.qrCodes.has(result)) {
|
||||
console.warn("Shard already seen");
|
||||
return;
|
||||
}
|
||||
const parsed = crypto.parse(result);
|
||||
if (this.title && this.title !== parsed.title) {
|
||||
console.error("title mismatch!");
|
||||
return;
|
||||
} else {
|
||||
this.title = parsed.title;
|
||||
}
|
||||
if (this.nonce && this.nonce != parsed.nonce) {
|
||||
if (this.nonce && this.nonce !== parsed.nonce) {
|
||||
console.error("nonce mismatch!");
|
||||
return;
|
||||
} else {
|
||||
@ -104,18 +120,15 @@ export default {
|
||||
}
|
||||
if (
|
||||
this.requiredShards &&
|
||||
this.requiredShards != parsed.requiredShards
|
||||
this.requiredShards !== parsed.requiredShards
|
||||
) {
|
||||
console.error("requiredShards mismatch");
|
||||
return;
|
||||
} else {
|
||||
this.requiredShards = parsed.requiredShards;
|
||||
}
|
||||
this.qrCodes.push(result);
|
||||
this.shards.add(parsed);
|
||||
} else {
|
||||
console.warn("Shard already seen");
|
||||
}
|
||||
this.qrCodes.add(result);
|
||||
this.shards.push(parsed);
|
||||
},
|
||||
reconstruct: function() {
|
||||
if (!this.passphrase) {
|
||||
@ -125,11 +138,11 @@ export default {
|
||||
.split(" ")
|
||||
.filter(el => el)
|
||||
.join("-");
|
||||
var shards = Array.from(this.shards);
|
||||
const shards = Array.from(this.shards);
|
||||
this.recoveredSecret = crypto.reconstruct(shards, this.passphrase);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
export default {};
|
||||
</script>
|
||||
|
||||
|
||||
@ -69,17 +69,26 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import passPhrase from "../util/passPhrase";
|
||||
import crypto from "../util/crypto";
|
||||
|
||||
import ShardInfo from "../components/ShardInfo";
|
||||
import CanvasText from "../components/CanvasText";
|
||||
import ShardInfo from "../components/ShardInfo.vue";
|
||||
import CanvasText from "../components/CanvasText.vue";
|
||||
import Vue from "vue";
|
||||
|
||||
export default {
|
||||
type ShareData = {
|
||||
title: string;
|
||||
secret: string;
|
||||
totalShards: number;
|
||||
recoveryPassphrase: string;
|
||||
encryptionMode: boolean;
|
||||
};
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Share",
|
||||
components: { ShardInfo, CanvasText },
|
||||
data: function() {
|
||||
data(): ShareData {
|
||||
return {
|
||||
title: "",
|
||||
secret: "",
|
||||
@ -89,13 +98,13 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
secretTooLong: function() {
|
||||
secretTooLong(): boolean {
|
||||
return this.secret.length > 1024;
|
||||
},
|
||||
requiredShards: function() {
|
||||
requiredShards(): number {
|
||||
return Math.floor(this.totalShards / 2) + 1;
|
||||
},
|
||||
shards: function() {
|
||||
shards(): string[] {
|
||||
if (!this.encryptionMode) {
|
||||
return [];
|
||||
}
|
||||
@ -122,7 +131,7 @@ export default {
|
||||
this.encryptionMode = !this.encryptionMode;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
64
tsconfig.json
Normal file
64
tsconfig.json
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
|
||||
"module": "esnext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
"jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
// "outDir": "build", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
"strictNullChecks": true, /* Enable strict null checks. */
|
||||
"strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
"strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
"noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
"resolveJsonModule": true,
|
||||
/* Advanced Options */
|
||||
// "declarationDir": "lib" /* Output directory for generated declaration files. */
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user