A bit of half-backed wallet sync stuff, but commented out.

This commit is contained in:
Daniel Krol 2022-05-05 13:30:07 -04:00
parent dadeb066c8
commit 205411adda
5 changed files with 187 additions and 29 deletions

View file

@ -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,
},
);
}
} }

View file

@ -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
}
} }

View file

@ -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>

View file

@ -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,
});
}
} }

View file

@ -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',
}; };
/* /*