wizard encrypt

This commit is contained in:
Drew Ansbacher
2021-08-26 13:54:23 -06:00
committed by Aiden McClelland
parent a4b769f982
commit c278e7fbc2
5 changed files with 70 additions and 94 deletions

View File

@@ -1,7 +1,7 @@
import { Component } from '@angular/core'
import { iosTransitionAnimation, LoadingController, NavController } from '@ionic/angular'
import { ApiService } from 'src/app/services/api/api.service'
import { AES_CTR, decodeUtf8, encodeUtf8 } from 'src/app/services/api/http.service'
import { HttpService } from 'src/app/services/api/http.service'
import { StateService } from 'src/app/services/state.service'
@Component({
@@ -18,15 +18,10 @@ export class ProductKeyPage {
private stateService: StateService,
private apiService: ApiService,
private loadingCtrl: LoadingController,
private httpService: HttpService
) {}
async submit () {
const ret = await AES_CTR.encryptPbkdf2(this.productKey, encodeUtf8('hello world'))
const arr = await AES_CTR.decryptPbkdf2(this.productKey, ret)
console.log(decodeUtf8(arr))
if(!this.productKey) return this.error = "Must enter product key"
const loader = await this.loadingCtrl.create({
@@ -36,7 +31,7 @@ export class ProductKeyPage {
try {
const state = await this.apiService.verifyProductKey(this.productKey)
this.stateService.productKey = this.productKey
this.httpService.productKey = this.productKey
if(state['is-recovering']) {
await this.navCtrl.navigateForward(`/loading`, { animationDirection: 'forward', animation: iosTransitionAnimation })
} else if (!!state['tor-address']) {
@@ -47,6 +42,7 @@ export class ProductKeyPage {
}
} catch (e) {
this.error = e.message
this.httpService.productKey = undefined
} finally {
loader.dismiss()
}

View File

@@ -3,24 +3,33 @@ import { Subject } from 'rxjs'
export abstract class ApiService {
protected error$: Subject<string> = new Subject();
watchError$ = this.error$.asObservable();
abstract verifyProductKey (key: string): Promise<{ "is-recovering": boolean, "tor-address": string }>;
abstract verifyProductKey (key: string): Promise<VerifyProductKeyRes>;
abstract getEmbassyDrives (): Promise<EmbassyDrive[]>;
abstract getRecoveryDrives (): Promise<RecoveryDrive[]>;
abstract getDataTransferProgress (): Promise<TransferProgress>;
abstract getDataTransferProgress (): Promise<TransferProgressRes>;
abstract verifyRecoveryPassword (logicalname: string, password: string): Promise<boolean>;
abstract setupEmbassy (setupInfo: {
embassyLogicalname: string,
embassyPassword: string
recoveryLogicalname?: string,
recoveryPassword?: string
}): Promise<{ "tor-address": string }>
}): Promise<SetupEmbassyRes>
}
export interface TransferProgress {
export interface VerifyProductKeyRes {
"is-recovering": boolean
"tor-address": string
}
export interface TransferProgressRes {
'bytes-transfered': number;
'total-bytes': number;
}
export interface SetupEmbassyRes {
"tor-address": string
}
export interface EmbassyDrive {
logicalname: string;
labels: string[];

View File

@@ -9,6 +9,7 @@ import { map, take } from 'rxjs/operators'
export class HttpService {
private unauthorizedApiResponse$ = new Subject()
fullUrl: string
productKey: string
constructor (
private readonly http: HttpClient,
@@ -21,11 +22,11 @@ export class HttpService {
return this.unauthorizedApiResponse$.asObservable()
}
async rpcRequest<T> (rpcOpts: RPCOptions): Promise<T> {
rpcOpts.params = rpcOpts.params || { }
async rpcRequest<T> (body: RPCOptions): Promise<T> {
const httpOpts = {
method: Method.POST,
body: rpcOpts,
body,
url: `this.fullUrl`,
}
@@ -39,45 +40,35 @@ export class HttpService {
if (isRpcSuccess(res)) return res.result
}
async httpRequest<T> (httpOpts: HttpOptions): Promise<T> {
if (httpOpts.withCredentials !== false) {
httpOpts.withCredentials = true
}
async httpRequest<T> (httpOpts: {
body: RPCOptions;
url: string;
}): Promise<T> {
const urlIsRelative = httpOpts.url.startsWith('/')
const url = urlIsRelative ?
this.fullUrl + httpOpts.url :
httpOpts.url
Object.keys(httpOpts.params || { }).forEach(key => {
if (httpOpts.params[key] === undefined) {
delete httpOpts.params[key]
}
})
const options = {
responseType: httpOpts.responseType || 'json',
body: httpOpts.body,
responseType: 'arraybuffer',
body: await AES_CTR.encryptPbkdf2( 'asdf', encodeUtf8( JSON.stringify(httpOpts.body))),
observe: 'events',
reportProgress: false,
withCredentials: httpOpts.withCredentials,
headers: httpOpts.headers,
params: httpOpts.params,
timeout: httpOpts.timeout,
headers: {
'Content-Encoding': 'aesctr256',
'Content-Type': 'application/json'
},
// one minute
timeout: 60000,
} as any
let req: Observable<{ body: T }>
switch (httpOpts.method) {
case Method.GET: req = this.http.get(url, options) as any; break
case Method.POST: req = this.http.post(url, httpOpts.body, options) as any; break
case Method.PUT: req = this.http.put(url, httpOpts.body, options) as any; break
case Method.PATCH: req = this.http.patch(url, httpOpts.body, options) as any; break
case Method.DELETE: req = this.http.delete(url, options) as any; break
}
const req = this.http.post(url, httpOpts.body, options)
return (httpOpts.timeout ? withTimeout(req, httpOpts.timeout) : req)
return (withTimeout(req, 60000))
.toPromise()
.then(res => res.body)
.then(res => AES_CTR.decryptPbkdf2('asdf', new Uint8Array(res)))
.then(res => JSON.parse(decodeUtf8(res)))
.catch(e => { throw new HttpError(e) })
}
}
@@ -178,8 +169,8 @@ function withTimeout<U> (req: Observable<U>, timeout: number): Observable<U> {
}
type AES_CTR = {
encryptPbkdf2: (secretKey: string, messageBuffer: Uint8Array) => Promise<{ cipher: Uint8Array, counter: Uint8Array, salt: Uint8Array }>
decryptPbkdf2: (secretKey, a: { cipher: Uint8Array, counter: Uint8Array, salt: Uint8Array }) => Promise<Uint8Array>
encryptPbkdf2: (secretKey: string, messageBuffer: Uint8Array) => Promise<Uint8Array>
decryptPbkdf2: (secretKey, arr: Uint8Array) => Promise<Uint8Array>
}
export const AES_CTR: AES_CTR = {
@@ -191,10 +182,12 @@ export const AES_CTR: AES_CTR = {
return window.crypto.subtle.encrypt(algorithm, key, messageBuffer)
.then(encrypted => new Uint8Array(encrypted))
.then(cipher => ({ cipher, counter, salt }))
.then(cipher => new Uint8Array([...counter,...salt,...cipher]))
},
decryptPbkdf2: async (secretKey: string, a: { cipher: Uint8Array, counter: Uint8Array, salt: Uint8Array }) => {
const { cipher, counter, salt } = a
decryptPbkdf2: async (secretKey: string, arr: Uint8Array) => {
const counter = arr.slice(0, 16)
const salt = arr.slice(16, 32)
const cipher = arr.slice(32)
const { key } = await pbkdf2(secretKey, { name: 'AES-CTR', length: 256 }, salt)
const algorithm = { name: 'AES-CTR', counter, length: 64 };

View File

@@ -1,6 +1,5 @@
import { Injectable } from '@angular/core'
import { pauseFor } from '../state.service'
import { ApiService } from './api.service'
import { ApiService, EmbassyDrive, RecoveryDrive, SetupEmbassyRes, TransferProgressRes, VerifyProductKeyRes } from './api.service'
import { HttpService } from './http.service'
@Injectable({
@@ -12,64 +11,45 @@ export class LiveApiService extends ApiService {
private readonly http: HttpService
) { super() }
async verifyProductKey(key) {
await pauseFor(2000)
return {
"is-recovering": false,
"tor-address": null
}
async verifyProductKey() {
return this.http.rpcRequest<VerifyProductKeyRes>({
method: 'verifyProductKey',
params: {}
})
}
async getDataTransferProgress() {
tries = Math.min(tries + 1, 4)
return {
'bytes-transfered': tries,
'total-bytes': 4
}
return this.http.rpcRequest<TransferProgressRes>({
method: 'getDataTransferProgress',
params: {}
})
}
async getEmbassyDrives() {
return [
{
logicalname: 'Name1',
labels: ['label 1', 'label 2'],
capacity: 1600.66666,
used: 200.1255312,
},
{
logicalname: 'Name2',
labels: [],
capacity: 1600.01234,
used: 0.00,
}
]
return this.http.rpcRequest<EmbassyDrive[]>({
method: 'getEmbassyDrives',
params: {}
})
}
async getRecoveryDrives() {
await pauseFor(2000)
return [
{
logicalname: 'Name1',
version: '0.3.3',
name: 'My Embassy'
},
{
logicalname: 'Name2',
version: '0.2.7',
name: 'My Embassy'
}
]
return this.http.rpcRequest<RecoveryDrive[]>({
method: 'getRecoveryDrives',
params: {}
})
}
async verifyRecoveryPassword(logicalname, password) {
await pauseFor(2000)
return password.length > 8
return this.http.rpcRequest<boolean>({
method: 'verifyRecoveryPassword',
params: {logicalname, password}
})
}
async setupEmbassy (setupInfo) {
await pauseFor(2000)
return { "tor-address": 'asdfasdfasdf.onion' }
return this.http.rpcRequest<SetupEmbassyRes>({
method: 'setupEmbassy',
params: setupInfo
})
}
}
let tries = 0

View File

@@ -8,8 +8,6 @@ import { ApiService, EmbassyDrive, RecoveryDrive } from './api/api.service'
export class StateService {
polling = false
productKey: string
embassyDrive: EmbassyDrive;
embassyPassword: string
recoveryDrive: RecoveryDrive;