A bit of half-backed wallet sync stuff, but commented out.
This commit is contained in:
parent
dadeb066c8
commit
205411adda
5 changed files with 187 additions and 29 deletions
|
@ -19,6 +19,8 @@ export class User {
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class BackendAPIService {
|
export class BackendAPIService {
|
||||||
|
walletSyncEndpoint = `https://${environment.walletSyncHostname}/api/v0`;
|
||||||
|
|
||||||
endpoint = `https://${environment.nodeHostname}/api/v0`;
|
endpoint = `https://${environment.nodeHostname}/api/v0`;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -67,4 +69,34 @@ export class BackendAPIService {
|
||||||
return of(usernames);
|
return of(usernames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO - WIP, not using for now.
|
||||||
|
|
||||||
|
// This isn't what the current wallet sync API looks like, but it will
|
||||||
|
// likely change anyway. So this is an approximation with a stub for the time being.
|
||||||
|
WalletSyncLogin(
|
||||||
|
username: string,
|
||||||
|
password: string,
|
||||||
|
): Observable<{bodyJson: string, signature: string} | null> {
|
||||||
|
|
||||||
|
// A stub for now
|
||||||
|
const wallet : object | null = this.cryptoService.getWallet(this.globalVars.hostname);
|
||||||
|
if (wallet === null) {
|
||||||
|
return of(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return of({
|
||||||
|
bodyJson: JSON.stringify(wallet, null, 2),
|
||||||
|
signature: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Later we'll do something like this...
|
||||||
|
return this.httpClient.post<any>(
|
||||||
|
`${this.walletSyncEndpoint}/log-in`,
|
||||||
|
{
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import HDNode from 'hdkey';
|
|
||||||
import * as bip39 from 'bip39';
|
|
||||||
import HDKey from 'hdkey';
|
|
||||||
import {ec as EC} from 'elliptic';
|
import {ec as EC} from 'elliptic';
|
||||||
import bs58check from 'bs58check';
|
import bs58check from 'bs58check';
|
||||||
import {CookieService} from 'ngx-cookie';
|
import {CookieService} from 'ngx-cookie';
|
||||||
import {createHmac, createCipher, createDecipher, randomBytes} from 'crypto';
|
import {createHmac, createCipher, createDecipher, randomBytes} from 'crypto';
|
||||||
import {AccessLevel, Network} from '../types/identity';
|
import {AccessLevel, PrivateAccountInfo} from '../types/identity';
|
||||||
import { GlobalVarsService } from './global-vars.service';
|
import { GlobalVarsService } from './global-vars.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
|
@ -76,7 +73,8 @@ export class CryptoService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getWallet(hostname: string): object | null {
|
// TODO define a wallet type, and/or use a type defined by json-schema
|
||||||
|
getWallet(hostname: string): {accounts: [PrivateAccountInfo]} | null {
|
||||||
const storageKey = this.walletStorageKey(hostname);
|
const storageKey = this.walletStorageKey(hostname);
|
||||||
let walletStr
|
let walletStr
|
||||||
if (this.mustUseStorageAccess()) {
|
if (this.mustUseStorageAccess()) {
|
||||||
|
@ -169,4 +167,16 @@ export class CryptoService {
|
||||||
|
|
||||||
return new Buffer(publicKeyEC.getPublic('array'));
|
return new Buffer(publicKeyEC.getPublic('array'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO check that the signature for the walletStr is valid
|
||||||
|
checkSig(walletStr: string, walletSignature: string): boolean {
|
||||||
|
throw "implement me"
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO find errors in the wallet. missing fields, etc. json-schema
|
||||||
|
validateWallet(wallet: object): string | null {
|
||||||
|
throw "implement me"
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,51 @@
|
||||||
<p>
|
<app-banner></app-banner>
|
||||||
<b>wallet me</b>: <textarea id="wallet" rows="20" cols="150"></textarea><button type="button" (click)="saveWallet()">Go.</button>
|
|
||||||
</p>
|
<div class="page-container" *ngIf="globalVars.inTab || globalVars.webview || globalVars.callback">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<div class="title-text">
|
||||||
|
Log into the LBRY wallet sync service
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="main-text mb-20px">
|
||||||
|
Log in to {{ globalVars.environment.walletSyncHostname }}:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div *ngIf="loginError" class="alert alert-danger mt-15px">
|
||||||
|
{{ loginError }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-input-container">
|
||||||
|
<textarea [(ngModel)]="loginUsername"
|
||||||
|
class="text-input"
|
||||||
|
rows="4"
|
||||||
|
placeholder="Username"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-input-container">
|
||||||
|
<textarea [(ngModel)]="loginPassword"
|
||||||
|
class="text-input"
|
||||||
|
rows="4"
|
||||||
|
placeholder="Password"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button (click)="clickLogin()"
|
||||||
|
class="button button-primary button-large">
|
||||||
|
Log In
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="title-text">
|
||||||
|
Paste your wallet directly
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<textarea [value]="walletDumpInitial" id="wallet-dump" rows="20" cols="150"></textarea>
|
||||||
|
<button (click)="loginWithWalletDump()"
|
||||||
|
class="button button-primary button-large">
|
||||||
|
Log In
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import {BackendAPIService} from '../backend-api.service';
|
||||||
import { CryptoService } from '../crypto.service';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import { SigningService } from '../signing.service';
|
import {CryptoService} from '../crypto.service';
|
||||||
import { IdentityService } from '../identity.service';
|
import {GlobalVarsService} from '../global-vars.service';
|
||||||
import { GlobalVarsService } from '../global-vars.service';
|
import {Router} from '@angular/router';
|
||||||
|
import {RouteNames} from '../app-routing.module';
|
||||||
|
import {of} from 'rxjs';
|
||||||
|
|
||||||
|
// This is logging into the wallet sync, not the app
|
||||||
|
// TODO rename this component to wallet-sync-log-in
|
||||||
|
|
||||||
|
// This component handles two ways of logging in:
|
||||||
|
// * Wallet Sync (currently commented out)
|
||||||
|
// * Paste Wallet (temporary measure for initial version)
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-test-lbry-log-in',
|
selector: 'app-test-lbry-log-in',
|
||||||
|
@ -10,32 +19,90 @@ import { GlobalVarsService } from '../global-vars.service';
|
||||||
styleUrls: ['./test-lbry-log-in.component.scss']
|
styleUrls: ['./test-lbry-log-in.component.scss']
|
||||||
})
|
})
|
||||||
export class TestLbryLogInComponent implements OnInit {
|
export class TestLbryLogInComponent implements OnInit {
|
||||||
|
walletDumpInitial = this.getWalletDumpInitial();
|
||||||
|
|
||||||
|
loginError = '';
|
||||||
|
loginUsername = '';
|
||||||
|
loginPassword = '';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private backendApi: BackendAPIService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private signingService: SigningService,
|
public globalVars: GlobalVarsService,
|
||||||
private identityService: IdentityService,
|
private router: Router,
|
||||||
private globalVars: GlobalVarsService,
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {}
|
||||||
const wallet : object | null = this.cryptoService.getWallet(this.globalVars.hostname);
|
|
||||||
(<HTMLInputElement>document.getElementById("wallet")).value = JSON.stringify(wallet, null, 2) || "";
|
// Wallet Sync (WIP, unused atm)
|
||||||
|
|
||||||
|
clickLogin() {
|
||||||
|
// Store username and password locally because we clear them below and otherwise
|
||||||
|
// they don't get saved in local storage reliably
|
||||||
|
const loginUsername = this.loginUsername;
|
||||||
|
const loginPassword = this.loginPassword;
|
||||||
|
|
||||||
|
if (loginUsername.length === 0) {
|
||||||
|
this.loginError = 'Enter a username';
|
||||||
|
return of();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loginPassword.length === 0) {
|
||||||
|
this.loginError = 'Enter a password';
|
||||||
|
return of();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returning the observable only because I'm in the habit of returning
|
||||||
|
// promises. But maybe it's not needed here.
|
||||||
|
return this.backendApi.WalletSyncLogin(loginUsername, loginPassword).subscribe(
|
||||||
|
(res => {
|
||||||
|
if (res === null) {
|
||||||
|
this.loginError = "Login Error. Try again?"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const walletStr = res.bodyJson
|
||||||
|
const walletSignature = res.signature
|
||||||
|
|
||||||
|
if (!this.cryptoService.checkSig(walletStr, walletSignature)) {
|
||||||
|
this.loginError = 'Wallet signature failed!';
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const wallet = JSON.parse(res.bodyJson)
|
||||||
|
const walletError: string | null = this.cryptoService.validateWallet(wallet);
|
||||||
|
|
||||||
|
if (walletError !== null) {
|
||||||
|
this.loginError = "Wallet error: " + walletError;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cryptoService.putWallet(this.globalVars.hostname, wallet);
|
||||||
|
|
||||||
|
// Clear the form
|
||||||
|
this.loginUsername = '';
|
||||||
|
this.loginPassword = '';
|
||||||
|
|
||||||
|
this.router.navigate(['/', RouteNames.LOG_IN], {queryParamsHandling: 'merge'});
|
||||||
|
}),
|
||||||
|
(() => {
|
||||||
|
this.loginError = "Login Error. Try again?"
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveWallet(): void {
|
// Paste Wallet (temporary measure for initial version)
|
||||||
const walletStr = (<HTMLInputElement>document.getElementById("wallet")).value;
|
|
||||||
|
getWalletDumpInitial() {
|
||||||
|
const wallet : object | null = this.cryptoService.getWallet(this.globalVars.hostname);
|
||||||
|
return JSON.stringify(wallet, null, 2) || ""
|
||||||
|
}
|
||||||
|
|
||||||
|
loginWithWalletDump(): void {
|
||||||
|
const walletStr = (<HTMLInputElement>document.getElementById("wallet-dump")).value;
|
||||||
const wallet = JSON.parse(walletStr)
|
const wallet = JSON.parse(walletStr)
|
||||||
this.cryptoService.putWallet(this.globalVars.hostname, wallet);
|
this.cryptoService.putWallet(this.globalVars.hostname, wallet);
|
||||||
|
|
||||||
const addresses = this.signingService.getAddresses(wallet)
|
this.router.navigate(['/', RouteNames.LOG_IN], {queryParamsHandling: 'merge'});
|
||||||
this.finishFlow(addresses)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finishFlow(addresses: string[]): void {
|
|
||||||
this.identityService.login({
|
|
||||||
accounts: this.accountService.getPublicAccounts(),
|
|
||||||
addresses,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
hostname: 'localhost:4201',
|
hostname: 'localhost:4201',
|
||||||
nodeHostname: 'node.deso.org', // TODO deleteme
|
nodeHostname: 'node.deso.org', // TODO deleteme
|
||||||
|
walletSyncHostname: 'localhost:8091',
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue