mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
wizard encrypt
This commit is contained in:
committed by
Aiden McClelland
parent
a4b769f982
commit
c278e7fbc2
@@ -1,7 +1,7 @@
|
|||||||
import { Component } from '@angular/core'
|
import { Component } from '@angular/core'
|
||||||
import { iosTransitionAnimation, LoadingController, NavController } from '@ionic/angular'
|
import { iosTransitionAnimation, LoadingController, NavController } from '@ionic/angular'
|
||||||
import { ApiService } from 'src/app/services/api/api.service'
|
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'
|
import { StateService } from 'src/app/services/state.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -18,15 +18,10 @@ export class ProductKeyPage {
|
|||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private loadingCtrl: LoadingController,
|
private loadingCtrl: LoadingController,
|
||||||
|
private httpService: HttpService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async submit () {
|
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"
|
if(!this.productKey) return this.error = "Must enter product key"
|
||||||
|
|
||||||
const loader = await this.loadingCtrl.create({
|
const loader = await this.loadingCtrl.create({
|
||||||
@@ -36,7 +31,7 @@ export class ProductKeyPage {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const state = await this.apiService.verifyProductKey(this.productKey)
|
const state = await this.apiService.verifyProductKey(this.productKey)
|
||||||
this.stateService.productKey = this.productKey
|
this.httpService.productKey = this.productKey
|
||||||
if(state['is-recovering']) {
|
if(state['is-recovering']) {
|
||||||
await this.navCtrl.navigateForward(`/loading`, { animationDirection: 'forward', animation: iosTransitionAnimation })
|
await this.navCtrl.navigateForward(`/loading`, { animationDirection: 'forward', animation: iosTransitionAnimation })
|
||||||
} else if (!!state['tor-address']) {
|
} else if (!!state['tor-address']) {
|
||||||
@@ -47,6 +42,7 @@ export class ProductKeyPage {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = e.message
|
this.error = e.message
|
||||||
|
this.httpService.productKey = undefined
|
||||||
} finally {
|
} finally {
|
||||||
loader.dismiss()
|
loader.dismiss()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,24 +3,33 @@ import { Subject } from 'rxjs'
|
|||||||
export abstract class ApiService {
|
export abstract class ApiService {
|
||||||
protected error$: Subject<string> = new Subject();
|
protected error$: Subject<string> = new Subject();
|
||||||
watchError$ = this.error$.asObservable();
|
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 getEmbassyDrives (): Promise<EmbassyDrive[]>;
|
||||||
abstract getRecoveryDrives (): Promise<RecoveryDrive[]>;
|
abstract getRecoveryDrives (): Promise<RecoveryDrive[]>;
|
||||||
abstract getDataTransferProgress (): Promise<TransferProgress>;
|
abstract getDataTransferProgress (): Promise<TransferProgressRes>;
|
||||||
abstract verifyRecoveryPassword (logicalname: string, password: string): Promise<boolean>;
|
abstract verifyRecoveryPassword (logicalname: string, password: string): Promise<boolean>;
|
||||||
abstract setupEmbassy (setupInfo: {
|
abstract setupEmbassy (setupInfo: {
|
||||||
embassyLogicalname: string,
|
embassyLogicalname: string,
|
||||||
embassyPassword: string
|
embassyPassword: string
|
||||||
recoveryLogicalname?: string,
|
recoveryLogicalname?: string,
|
||||||
recoveryPassword?: 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;
|
'bytes-transfered': number;
|
||||||
'total-bytes': number;
|
'total-bytes': number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SetupEmbassyRes {
|
||||||
|
"tor-address": string
|
||||||
|
}
|
||||||
|
|
||||||
export interface EmbassyDrive {
|
export interface EmbassyDrive {
|
||||||
logicalname: string;
|
logicalname: string;
|
||||||
labels: string[];
|
labels: string[];
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { map, take } from 'rxjs/operators'
|
|||||||
export class HttpService {
|
export class HttpService {
|
||||||
private unauthorizedApiResponse$ = new Subject()
|
private unauthorizedApiResponse$ = new Subject()
|
||||||
fullUrl: string
|
fullUrl: string
|
||||||
|
productKey: string
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private readonly http: HttpClient,
|
private readonly http: HttpClient,
|
||||||
@@ -21,11 +22,11 @@ export class HttpService {
|
|||||||
return this.unauthorizedApiResponse$.asObservable()
|
return this.unauthorizedApiResponse$.asObservable()
|
||||||
}
|
}
|
||||||
|
|
||||||
async rpcRequest<T> (rpcOpts: RPCOptions): Promise<T> {
|
async rpcRequest<T> (body: RPCOptions): Promise<T> {
|
||||||
rpcOpts.params = rpcOpts.params || { }
|
|
||||||
const httpOpts = {
|
const httpOpts = {
|
||||||
method: Method.POST,
|
method: Method.POST,
|
||||||
body: rpcOpts,
|
body,
|
||||||
url: `this.fullUrl`,
|
url: `this.fullUrl`,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,45 +40,35 @@ export class HttpService {
|
|||||||
if (isRpcSuccess(res)) return res.result
|
if (isRpcSuccess(res)) return res.result
|
||||||
}
|
}
|
||||||
|
|
||||||
async httpRequest<T> (httpOpts: HttpOptions): Promise<T> {
|
async httpRequest<T> (httpOpts: {
|
||||||
if (httpOpts.withCredentials !== false) {
|
body: RPCOptions;
|
||||||
httpOpts.withCredentials = true
|
url: string;
|
||||||
}
|
}): Promise<T> {
|
||||||
|
|
||||||
const urlIsRelative = httpOpts.url.startsWith('/')
|
const urlIsRelative = httpOpts.url.startsWith('/')
|
||||||
const url = urlIsRelative ?
|
const url = urlIsRelative ?
|
||||||
this.fullUrl + httpOpts.url :
|
this.fullUrl + httpOpts.url :
|
||||||
httpOpts.url
|
httpOpts.url
|
||||||
|
|
||||||
Object.keys(httpOpts.params || { }).forEach(key => {
|
|
||||||
if (httpOpts.params[key] === undefined) {
|
|
||||||
delete httpOpts.params[key]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
responseType: httpOpts.responseType || 'json',
|
responseType: 'arraybuffer',
|
||||||
body: httpOpts.body,
|
body: await AES_CTR.encryptPbkdf2( 'asdf', encodeUtf8( JSON.stringify(httpOpts.body))),
|
||||||
observe: 'events',
|
observe: 'events',
|
||||||
reportProgress: false,
|
reportProgress: false,
|
||||||
withCredentials: httpOpts.withCredentials,
|
headers: {
|
||||||
headers: httpOpts.headers,
|
'Content-Encoding': 'aesctr256',
|
||||||
params: httpOpts.params,
|
'Content-Type': 'application/json'
|
||||||
timeout: httpOpts.timeout,
|
},
|
||||||
|
// one minute
|
||||||
|
timeout: 60000,
|
||||||
} as any
|
} as any
|
||||||
|
|
||||||
let req: Observable<{ body: T }>
|
const req = this.http.post(url, httpOpts.body, options)
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
return (httpOpts.timeout ? withTimeout(req, httpOpts.timeout) : req)
|
return (withTimeout(req, 60000))
|
||||||
.toPromise()
|
.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) })
|
.catch(e => { throw new HttpError(e) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,8 +169,8 @@ function withTimeout<U> (req: Observable<U>, timeout: number): Observable<U> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AES_CTR = {
|
type AES_CTR = {
|
||||||
encryptPbkdf2: (secretKey: string, messageBuffer: Uint8Array) => Promise<{ cipher: Uint8Array, counter: Uint8Array, salt: Uint8Array }>
|
encryptPbkdf2: (secretKey: string, messageBuffer: Uint8Array) => Promise<Uint8Array>
|
||||||
decryptPbkdf2: (secretKey, a: { cipher: Uint8Array, counter: Uint8Array, salt: Uint8Array }) => Promise<Uint8Array>
|
decryptPbkdf2: (secretKey, arr: Uint8Array) => Promise<Uint8Array>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AES_CTR: AES_CTR = {
|
export const AES_CTR: AES_CTR = {
|
||||||
@@ -191,10 +182,12 @@ export const AES_CTR: AES_CTR = {
|
|||||||
|
|
||||||
return window.crypto.subtle.encrypt(algorithm, key, messageBuffer)
|
return window.crypto.subtle.encrypt(algorithm, key, messageBuffer)
|
||||||
.then(encrypted => new Uint8Array(encrypted))
|
.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 }) => {
|
decryptPbkdf2: async (secretKey: string, arr: Uint8Array) => {
|
||||||
const { cipher, counter, salt } = a
|
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 { key } = await pbkdf2(secretKey, { name: 'AES-CTR', length: 256 }, salt)
|
||||||
const algorithm = { name: 'AES-CTR', counter, length: 64 };
|
const algorithm = { name: 'AES-CTR', counter, length: 64 };
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { pauseFor } from '../state.service'
|
import { ApiService, EmbassyDrive, RecoveryDrive, SetupEmbassyRes, TransferProgressRes, VerifyProductKeyRes } from './api.service'
|
||||||
import { ApiService } from './api.service'
|
|
||||||
import { HttpService } from './http.service'
|
import { HttpService } from './http.service'
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@@ -12,64 +11,45 @@ export class LiveApiService extends ApiService {
|
|||||||
private readonly http: HttpService
|
private readonly http: HttpService
|
||||||
) { super() }
|
) { super() }
|
||||||
|
|
||||||
async verifyProductKey(key) {
|
async verifyProductKey() {
|
||||||
await pauseFor(2000)
|
return this.http.rpcRequest<VerifyProductKeyRes>({
|
||||||
return {
|
method: 'verifyProductKey',
|
||||||
"is-recovering": false,
|
params: {}
|
||||||
"tor-address": null
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDataTransferProgress() {
|
async getDataTransferProgress() {
|
||||||
tries = Math.min(tries + 1, 4)
|
return this.http.rpcRequest<TransferProgressRes>({
|
||||||
return {
|
method: 'getDataTransferProgress',
|
||||||
'bytes-transfered': tries,
|
params: {}
|
||||||
'total-bytes': 4
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getEmbassyDrives() {
|
async getEmbassyDrives() {
|
||||||
return [
|
return this.http.rpcRequest<EmbassyDrive[]>({
|
||||||
{
|
method: 'getEmbassyDrives',
|
||||||
logicalname: 'Name1',
|
params: {}
|
||||||
labels: ['label 1', 'label 2'],
|
})
|
||||||
capacity: 1600.66666,
|
|
||||||
used: 200.1255312,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
logicalname: 'Name2',
|
|
||||||
labels: [],
|
|
||||||
capacity: 1600.01234,
|
|
||||||
used: 0.00,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRecoveryDrives() {
|
async getRecoveryDrives() {
|
||||||
await pauseFor(2000)
|
return this.http.rpcRequest<RecoveryDrive[]>({
|
||||||
return [
|
method: 'getRecoveryDrives',
|
||||||
{
|
params: {}
|
||||||
logicalname: 'Name1',
|
})
|
||||||
version: '0.3.3',
|
|
||||||
name: 'My Embassy'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
logicalname: 'Name2',
|
|
||||||
version: '0.2.7',
|
|
||||||
name: 'My Embassy'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async verifyRecoveryPassword(logicalname, password) {
|
async verifyRecoveryPassword(logicalname, password) {
|
||||||
await pauseFor(2000)
|
return this.http.rpcRequest<boolean>({
|
||||||
return password.length > 8
|
method: 'verifyRecoveryPassword',
|
||||||
|
params: {logicalname, password}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async setupEmbassy (setupInfo) {
|
async setupEmbassy (setupInfo) {
|
||||||
await pauseFor(2000)
|
return this.http.rpcRequest<SetupEmbassyRes>({
|
||||||
return { "tor-address": 'asdfasdfasdf.onion' }
|
method: 'setupEmbassy',
|
||||||
|
params: setupInfo
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tries = 0
|
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import { ApiService, EmbassyDrive, RecoveryDrive } from './api/api.service'
|
|||||||
export class StateService {
|
export class StateService {
|
||||||
polling = false
|
polling = false
|
||||||
|
|
||||||
productKey: string
|
|
||||||
|
|
||||||
embassyDrive: EmbassyDrive;
|
embassyDrive: EmbassyDrive;
|
||||||
embassyPassword: string
|
embassyPassword: string
|
||||||
recoveryDrive: RecoveryDrive;
|
recoveryDrive: RecoveryDrive;
|
||||||
|
|||||||
Reference in New Issue
Block a user