Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a2bc4fe72 | ||
| a2e47d8612 |
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "plebeian-signer",
|
"name": "plebeian-signer",
|
||||||
"version": "v1.1.3",
|
"version": "v1.1.5",
|
||||||
"custom": {
|
"custom": {
|
||||||
"chrome": {
|
"chrome": {
|
||||||
"version": "v1.1.3"
|
"version": "v1.1.5"
|
||||||
},
|
},
|
||||||
"firefox": {
|
"firefox": {
|
||||||
"version": "v1.1.3"
|
"version": "v1.1.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "Plebeian Signer - Nostr Identity Manager & Signer",
|
"name": "Plebeian Signer - Nostr Identity Manager & Signer",
|
||||||
"description": "Manage and switch between multiple identities while interacting with Nostr apps",
|
"description": "Manage and switch between multiple identities while interacting with Nostr apps",
|
||||||
"version": "1.1.3",
|
"version": "1.1.5",
|
||||||
"homepage_url": "https://github.com/PlebeianApp/plebeian-signer",
|
"homepage_url": "https://github.com/PlebeianApp/plebeian-signer",
|
||||||
"options_page": "options.html",
|
"options_page": "options.html",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
|
|||||||
@@ -6,16 +6,26 @@
|
|||||||
<span>Get ncryptsec</span>
|
<span>Get ncryptsec</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="description">
|
<!-- QR Code (shown after generation) -->
|
||||||
Enter a password to encrypt your private key. The resulting ncryptsec can be
|
@if (ncryptsec) {
|
||||||
used to securely backup or transfer your key.
|
<div class="qr-container">
|
||||||
</p>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="qr-button"
|
||||||
|
title="Copy to clipboard"
|
||||||
|
(click)="copyToClipboard(ncryptsec); toast.show('Copied to clipboard')"
|
||||||
|
>
|
||||||
|
<img [src]="ncryptsecQr" alt="ncryptsec QR code" class="qr-code" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<!-- PASSWORD INPUT -->
|
<!-- PASSWORD INPUT -->
|
||||||
<div class="password-section">
|
<div class="password-section">
|
||||||
<label for="ncryptsecPasswordInput">Password</label>
|
<label for="ncryptsecPasswordInput">Password</label>
|
||||||
<div class="input-group sam-mt-h">
|
<div class="input-group sam-mt-h">
|
||||||
<input
|
<input
|
||||||
|
#passwordInput
|
||||||
id="ncryptsecPasswordInput"
|
id="ncryptsecPasswordInput"
|
||||||
type="password"
|
type="password"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
@@ -41,35 +51,10 @@
|
|||||||
}
|
}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- NCRYPTSEC OUTPUT -->
|
|
||||||
@if (ncryptsec) {
|
|
||||||
<div class="result-section">
|
|
||||||
<!-- QR Code -->
|
|
||||||
<div class="qr-container">
|
|
||||||
<img [src]="ncryptsecQr" alt="ncryptsec QR code" class="qr-code" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ncryptsec text -->
|
<p class="description">
|
||||||
<div class="ncryptsec-container">
|
Enter a password to encrypt your private key. The resulting ncryptsec can be
|
||||||
<input
|
used to securely backup or transfer your key.
|
||||||
type="text"
|
</p>
|
||||||
class="form-control ncryptsec-output"
|
|
||||||
[value]="ncryptsec"
|
|
||||||
readonly
|
|
||||||
(click)="copyToClipboard(ncryptsec); toast.show('Copied to clipboard')"
|
|
||||||
title="Click to copy"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
class="btn btn-outline-secondary"
|
|
||||||
type="button"
|
|
||||||
(click)="copyToClipboard(ncryptsec); toast.show('Copied to clipboard')"
|
|
||||||
>
|
|
||||||
<i class="bi bi-copy"></i> Copy
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="hint">Tap the text or button to copy to clipboard</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<lib-toast #toast [bottom]="16"></lib-toast>
|
<lib-toast #toast [bottom]="16"></lib-toast>
|
||||||
|
|||||||
@@ -38,52 +38,33 @@
|
|||||||
margin-bottom: var(--size);
|
margin-bottom: var(--size);
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--size);
|
|
||||||
margin-top: var(--size);
|
|
||||||
}
|
|
||||||
|
|
||||||
.qr-container {
|
.qr-container {
|
||||||
background: white;
|
|
||||||
padding: var(--size);
|
|
||||||
border-radius: 8px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin-bottom: var(--size);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-button {
|
||||||
|
background: white;
|
||||||
|
padding: var(--size);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-code {
|
.qr-code {
|
||||||
width: 250px;
|
width: 250px;
|
||||||
height: 250px;
|
height: 250px;
|
||||||
}
|
display: block;
|
||||||
|
|
||||||
.ncryptsec-container {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--size-h);
|
|
||||||
|
|
||||||
.ncryptsec-output {
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
word-break: break-all;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--bs-gray-100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.hint {
|
|
||||||
color: var(--text-muted);
|
|
||||||
font-size: 0.8rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
import { Component, inject, OnInit } from '@angular/core';
|
import {
|
||||||
|
AfterViewInit,
|
||||||
|
Component,
|
||||||
|
ElementRef,
|
||||||
|
inject,
|
||||||
|
OnInit,
|
||||||
|
ViewChild,
|
||||||
|
} from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import {
|
import {
|
||||||
IconButtonComponent,
|
IconButtonComponent,
|
||||||
@@ -16,7 +23,12 @@ import * as QRCode from 'qrcode';
|
|||||||
templateUrl: './ncryptsec.component.html',
|
templateUrl: './ncryptsec.component.html',
|
||||||
styleUrl: './ncryptsec.component.scss',
|
styleUrl: './ncryptsec.component.scss',
|
||||||
})
|
})
|
||||||
export class NcryptsecComponent extends NavComponent implements OnInit {
|
export class NcryptsecComponent
|
||||||
|
extends NavComponent
|
||||||
|
implements OnInit, AfterViewInit
|
||||||
|
{
|
||||||
|
@ViewChild('passwordInput') passwordInput!: ElementRef<HTMLInputElement>;
|
||||||
|
|
||||||
privkeyHex = '';
|
privkeyHex = '';
|
||||||
ncryptsecPassword = '';
|
ncryptsecPassword = '';
|
||||||
ncryptsec = '';
|
ncryptsec = '';
|
||||||
@@ -35,6 +47,10 @@ export class NcryptsecComponent extends NavComponent implements OnInit {
|
|||||||
this.#initialize(identityId);
|
this.#initialize(identityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.passwordInput.nativeElement.focus();
|
||||||
|
}
|
||||||
|
|
||||||
async generateNcryptsec() {
|
async generateNcryptsec() {
|
||||||
if (!this.privkeyHex || !this.ncryptsecPassword) {
|
if (!this.privkeyHex || !this.ncryptsecPassword) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -40,10 +40,13 @@ export interface UnlockResponseMessage {
|
|||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const debug = function (message: any) {
|
// Debug logging disabled - uncomment for development
|
||||||
const dateString = new Date().toISOString();
|
// export const debug = function (message: any) {
|
||||||
console.log(`[Plebeian Signer - ${dateString}]: ${JSON.stringify(message)}`);
|
// const dateString = new Date().toISOString();
|
||||||
};
|
// console.log(`[Plebeian Signer - ${dateString}]: ${JSON.stringify(message)}`);
|
||||||
|
// };
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
|
||||||
|
export const debug = function (_message: any) {};
|
||||||
|
|
||||||
export type PromptResponse =
|
export type PromptResponse =
|
||||||
| 'reject'
|
| 'reject'
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import {
|
import {
|
||||||
backgroundLogNip07Action,
|
|
||||||
backgroundLogPermissionStored,
|
|
||||||
NostrHelper,
|
NostrHelper,
|
||||||
NwcClient,
|
NwcClient,
|
||||||
NwcConnection_DECRYPTED,
|
NwcConnection_DECRYPTED,
|
||||||
@@ -441,7 +439,6 @@ async function processNip07Request(req: BackgroundRequestMessage): Promise<any>
|
|||||||
policy,
|
policy,
|
||||||
req.params?.kind
|
req.params?.kind
|
||||||
);
|
);
|
||||||
await backgroundLogPermissionStored(req.host, req.method, policy, req.params?.kind);
|
|
||||||
} else if (response === 'approve-all') {
|
} else if (response === 'approve-all') {
|
||||||
// P2: Store permission for ALL kinds/uses of this method from this host
|
// P2: Store permission for ALL kinds/uses of this method from this host
|
||||||
await storePermission(
|
await storePermission(
|
||||||
@@ -452,8 +449,6 @@ async function processNip07Request(req: BackgroundRequestMessage): Promise<any>
|
|||||||
'allow',
|
'allow',
|
||||||
undefined // undefined kind = allow all kinds for signEvent
|
undefined // undefined kind = allow all kinds for signEvent
|
||||||
);
|
);
|
||||||
await backgroundLogPermissionStored(req.host, req.method, 'allow', undefined);
|
|
||||||
debug(`Stored approve-all permission for ${req.method} from ${req.host}`);
|
|
||||||
} else if (response === 'reject-all') {
|
} else if (response === 'reject-all') {
|
||||||
// P2: Store deny permission for ALL uses of this method from this host
|
// P2: Store deny permission for ALL uses of this method from this host
|
||||||
await storePermission(
|
await storePermission(
|
||||||
@@ -464,15 +459,9 @@ async function processNip07Request(req: BackgroundRequestMessage): Promise<any>
|
|||||||
'deny',
|
'deny',
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
await backgroundLogPermissionStored(req.host, req.method, 'deny', undefined);
|
|
||||||
debug(`Stored reject-all permission for ${req.method} from ${req.host}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (['reject', 'reject-once', 'reject-all'].includes(response)) {
|
if (['reject', 'reject-once', 'reject-all'].includes(response)) {
|
||||||
await backgroundLogNip07Action(req.method, req.host, false, false, {
|
|
||||||
kind: req.params?.kind,
|
|
||||||
peerPubkey: req.params?.peerPubkey,
|
|
||||||
});
|
|
||||||
throw new Error('Permission denied');
|
throw new Error('Permission denied');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -481,71 +470,47 @@ async function processNip07Request(req: BackgroundRequestMessage): Promise<any>
|
|||||||
}
|
}
|
||||||
|
|
||||||
const relays: Relays = {};
|
const relays: Relays = {};
|
||||||
let result: any;
|
|
||||||
|
|
||||||
switch (req.method) {
|
switch (req.method) {
|
||||||
case 'getPublicKey':
|
case 'getPublicKey':
|
||||||
result = NostrHelper.pubkeyFromPrivkey(currentIdentity.privkey);
|
return NostrHelper.pubkeyFromPrivkey(currentIdentity.privkey);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove);
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'signEvent':
|
case 'signEvent':
|
||||||
result = signEvent(req.params, currentIdentity.privkey);
|
return signEvent(req.params, currentIdentity.privkey);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove, {
|
|
||||||
kind: req.params?.kind,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'getRelays':
|
case 'getRelays':
|
||||||
browserSessionData.relays.forEach((x) => {
|
browserSessionData.relays.forEach((x) => {
|
||||||
relays[x.url] = { read: x.read, write: x.write };
|
relays[x.url] = { read: x.read, write: x.write };
|
||||||
});
|
});
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove);
|
|
||||||
return relays;
|
return relays;
|
||||||
|
|
||||||
case 'nip04.encrypt':
|
case 'nip04.encrypt':
|
||||||
result = await nip04Encrypt(
|
return await nip04Encrypt(
|
||||||
currentIdentity.privkey,
|
currentIdentity.privkey,
|
||||||
req.params.peerPubkey,
|
req.params.peerPubkey,
|
||||||
req.params.plaintext
|
req.params.plaintext
|
||||||
);
|
);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove, {
|
|
||||||
peerPubkey: req.params.peerPubkey,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'nip44.encrypt':
|
case 'nip44.encrypt':
|
||||||
result = await nip44Encrypt(
|
return await nip44Encrypt(
|
||||||
currentIdentity.privkey,
|
currentIdentity.privkey,
|
||||||
req.params.peerPubkey,
|
req.params.peerPubkey,
|
||||||
req.params.plaintext
|
req.params.plaintext
|
||||||
);
|
);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove, {
|
|
||||||
peerPubkey: req.params.peerPubkey,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'nip04.decrypt':
|
case 'nip04.decrypt':
|
||||||
result = await nip04Decrypt(
|
return await nip04Decrypt(
|
||||||
currentIdentity.privkey,
|
currentIdentity.privkey,
|
||||||
req.params.peerPubkey,
|
req.params.peerPubkey,
|
||||||
req.params.ciphertext
|
req.params.ciphertext
|
||||||
);
|
);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove, {
|
|
||||||
peerPubkey: req.params.peerPubkey,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'nip44.decrypt':
|
case 'nip44.decrypt':
|
||||||
result = await nip44Decrypt(
|
return await nip44Decrypt(
|
||||||
currentIdentity.privkey,
|
currentIdentity.privkey,
|
||||||
req.params.peerPubkey,
|
req.params.peerPubkey,
|
||||||
req.params.ciphertext
|
req.params.ciphertext
|
||||||
);
|
);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove, {
|
|
||||||
peerPubkey: req.params.peerPubkey,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Not supported request method '${req.method}'.`);
|
throw new Error(`Not supported request method '${req.method}'.`);
|
||||||
@@ -625,7 +590,6 @@ async function processWeblnRequest(req: BackgroundRequestMessage): Promise<any>
|
|||||||
method,
|
method,
|
||||||
policy
|
policy
|
||||||
);
|
);
|
||||||
await backgroundLogPermissionStored(req.host, method, policy);
|
|
||||||
} else if (response === 'approve-all' && method !== 'webln.sendPayment' && method !== 'webln.keysend') {
|
} else if (response === 'approve-all' && method !== 'webln.sendPayment' && method !== 'webln.keysend') {
|
||||||
// P2: Store permission for all uses of this WebLN method
|
// P2: Store permission for all uses of this WebLN method
|
||||||
await storePermission(
|
await storePermission(
|
||||||
@@ -635,8 +599,6 @@ async function processWeblnRequest(req: BackgroundRequestMessage): Promise<any>
|
|||||||
method,
|
method,
|
||||||
'allow'
|
'allow'
|
||||||
);
|
);
|
||||||
await backgroundLogPermissionStored(req.host, method, 'allow');
|
|
||||||
debug(`Stored approve-all permission for ${method} from ${req.host}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (['reject', 'reject-once', 'reject-all'].includes(response)) {
|
if (['reject', 'reject-once', 'reject-all'].includes(response)) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "Plebeian Signer",
|
"name": "Plebeian Signer",
|
||||||
"description": "Nostr Identity Manager & Signer",
|
"description": "Nostr Identity Manager & Signer",
|
||||||
"version": "1.1.3",
|
"version": "1.1.5",
|
||||||
"homepage_url": "https://github.com/PlebeianApp/plebeian-signer",
|
"homepage_url": "https://github.com/PlebeianApp/plebeian-signer",
|
||||||
"options_page": "options.html",
|
"options_page": "options.html",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
|
|||||||
@@ -6,16 +6,26 @@
|
|||||||
<span>Get ncryptsec</span>
|
<span>Get ncryptsec</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="description">
|
<!-- QR Code (shown after generation) -->
|
||||||
Enter a password to encrypt your private key. The resulting ncryptsec can be
|
@if (ncryptsec) {
|
||||||
used to securely backup or transfer your key.
|
<div class="qr-container">
|
||||||
</p>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="qr-button"
|
||||||
|
title="Copy to clipboard"
|
||||||
|
(click)="copyToClipboard(ncryptsec); toast.show('Copied to clipboard')"
|
||||||
|
>
|
||||||
|
<img [src]="ncryptsecQr" alt="ncryptsec QR code" class="qr-code" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<!-- PASSWORD INPUT -->
|
<!-- PASSWORD INPUT -->
|
||||||
<div class="password-section">
|
<div class="password-section">
|
||||||
<label for="ncryptsecPasswordInput">Password</label>
|
<label for="ncryptsecPasswordInput">Password</label>
|
||||||
<div class="input-group sam-mt-h">
|
<div class="input-group sam-mt-h">
|
||||||
<input
|
<input
|
||||||
|
#passwordInput
|
||||||
id="ncryptsecPasswordInput"
|
id="ncryptsecPasswordInput"
|
||||||
type="password"
|
type="password"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
@@ -41,35 +51,10 @@
|
|||||||
}
|
}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- NCRYPTSEC OUTPUT -->
|
|
||||||
@if (ncryptsec) {
|
|
||||||
<div class="result-section">
|
|
||||||
<!-- QR Code -->
|
|
||||||
<div class="qr-container">
|
|
||||||
<img [src]="ncryptsecQr" alt="ncryptsec QR code" class="qr-code" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ncryptsec text -->
|
<p class="description">
|
||||||
<div class="ncryptsec-container">
|
Enter a password to encrypt your private key. The resulting ncryptsec can be
|
||||||
<input
|
used to securely backup or transfer your key.
|
||||||
type="text"
|
</p>
|
||||||
class="form-control ncryptsec-output"
|
|
||||||
[value]="ncryptsec"
|
|
||||||
readonly
|
|
||||||
(click)="copyToClipboard(ncryptsec); toast.show('Copied to clipboard')"
|
|
||||||
title="Click to copy"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
class="btn btn-outline-secondary"
|
|
||||||
type="button"
|
|
||||||
(click)="copyToClipboard(ncryptsec); toast.show('Copied to clipboard')"
|
|
||||||
>
|
|
||||||
<i class="bi bi-copy"></i> Copy
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="hint">Tap the text or button to copy to clipboard</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<lib-toast #toast [bottom]="16"></lib-toast>
|
<lib-toast #toast [bottom]="16"></lib-toast>
|
||||||
|
|||||||
@@ -38,52 +38,33 @@
|
|||||||
margin-bottom: var(--size);
|
margin-bottom: var(--size);
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--size);
|
|
||||||
margin-top: var(--size);
|
|
||||||
}
|
|
||||||
|
|
||||||
.qr-container {
|
.qr-container {
|
||||||
background: white;
|
|
||||||
padding: var(--size);
|
|
||||||
border-radius: 8px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin-bottom: var(--size);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-button {
|
||||||
|
background: white;
|
||||||
|
padding: var(--size);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-code {
|
.qr-code {
|
||||||
width: 250px;
|
width: 250px;
|
||||||
height: 250px;
|
height: 250px;
|
||||||
}
|
display: block;
|
||||||
|
|
||||||
.ncryptsec-container {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--size-h);
|
|
||||||
|
|
||||||
.ncryptsec-output {
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
word-break: break-all;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--bs-gray-100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.hint {
|
|
||||||
color: var(--text-muted);
|
|
||||||
font-size: 0.8rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
import { Component, inject, OnInit } from '@angular/core';
|
import {
|
||||||
|
AfterViewInit,
|
||||||
|
Component,
|
||||||
|
ElementRef,
|
||||||
|
inject,
|
||||||
|
OnInit,
|
||||||
|
ViewChild,
|
||||||
|
} from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import {
|
import {
|
||||||
IconButtonComponent,
|
IconButtonComponent,
|
||||||
@@ -16,7 +23,12 @@ import * as QRCode from 'qrcode';
|
|||||||
templateUrl: './ncryptsec.component.html',
|
templateUrl: './ncryptsec.component.html',
|
||||||
styleUrl: './ncryptsec.component.scss',
|
styleUrl: './ncryptsec.component.scss',
|
||||||
})
|
})
|
||||||
export class NcryptsecComponent extends NavComponent implements OnInit {
|
export class NcryptsecComponent
|
||||||
|
extends NavComponent
|
||||||
|
implements OnInit, AfterViewInit
|
||||||
|
{
|
||||||
|
@ViewChild('passwordInput') passwordInput!: ElementRef<HTMLInputElement>;
|
||||||
|
|
||||||
privkeyHex = '';
|
privkeyHex = '';
|
||||||
ncryptsecPassword = '';
|
ncryptsecPassword = '';
|
||||||
ncryptsec = '';
|
ncryptsec = '';
|
||||||
@@ -35,6 +47,10 @@ export class NcryptsecComponent extends NavComponent implements OnInit {
|
|||||||
this.#initialize(identityId);
|
this.#initialize(identityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.passwordInput.nativeElement.focus();
|
||||||
|
}
|
||||||
|
|
||||||
async generateNcryptsec() {
|
async generateNcryptsec() {
|
||||||
if (!this.privkeyHex || !this.ncryptsecPassword) {
|
if (!this.privkeyHex || !this.ncryptsecPassword) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -41,10 +41,13 @@ export interface UnlockResponseMessage {
|
|||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const debug = function (message: any) {
|
// Debug logging disabled - uncomment for development
|
||||||
const dateString = new Date().toISOString();
|
// export const debug = function (message: any) {
|
||||||
console.log(`[Plebeian Signer - ${dateString}]: ${JSON.stringify(message)}`);
|
// const dateString = new Date().toISOString();
|
||||||
};
|
// console.log(`[Plebeian Signer - ${dateString}]: ${JSON.stringify(message)}`);
|
||||||
|
// };
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
|
||||||
|
export const debug = function (_message: any) {};
|
||||||
|
|
||||||
export type PromptResponse =
|
export type PromptResponse =
|
||||||
| 'reject'
|
| 'reject'
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import {
|
import {
|
||||||
backgroundLogNip07Action,
|
|
||||||
backgroundLogPermissionStored,
|
|
||||||
NostrHelper,
|
NostrHelper,
|
||||||
NwcClient,
|
NwcClient,
|
||||||
NwcConnection_DECRYPTED,
|
NwcConnection_DECRYPTED,
|
||||||
@@ -441,7 +439,6 @@ async function processNip07Request(req: BackgroundRequestMessage): Promise<any>
|
|||||||
policy,
|
policy,
|
||||||
req.params?.kind
|
req.params?.kind
|
||||||
);
|
);
|
||||||
await backgroundLogPermissionStored(req.host, req.method, policy, req.params?.kind);
|
|
||||||
} else if (response === 'approve-all') {
|
} else if (response === 'approve-all') {
|
||||||
// P2: Store permission for ALL kinds/uses of this method from this host
|
// P2: Store permission for ALL kinds/uses of this method from this host
|
||||||
await storePermission(
|
await storePermission(
|
||||||
@@ -452,8 +449,6 @@ async function processNip07Request(req: BackgroundRequestMessage): Promise<any>
|
|||||||
'allow',
|
'allow',
|
||||||
undefined // undefined kind = allow all kinds for signEvent
|
undefined // undefined kind = allow all kinds for signEvent
|
||||||
);
|
);
|
||||||
await backgroundLogPermissionStored(req.host, req.method, 'allow', undefined);
|
|
||||||
debug(`Stored approve-all permission for ${req.method} from ${req.host}`);
|
|
||||||
} else if (response === 'reject-all') {
|
} else if (response === 'reject-all') {
|
||||||
// P2: Store deny permission for ALL uses of this method from this host
|
// P2: Store deny permission for ALL uses of this method from this host
|
||||||
await storePermission(
|
await storePermission(
|
||||||
@@ -464,15 +459,9 @@ async function processNip07Request(req: BackgroundRequestMessage): Promise<any>
|
|||||||
'deny',
|
'deny',
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
await backgroundLogPermissionStored(req.host, req.method, 'deny', undefined);
|
|
||||||
debug(`Stored reject-all permission for ${req.method} from ${req.host}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (['reject', 'reject-once', 'reject-all'].includes(response)) {
|
if (['reject', 'reject-once', 'reject-all'].includes(response)) {
|
||||||
await backgroundLogNip07Action(req.method, req.host, false, false, {
|
|
||||||
kind: req.params?.kind,
|
|
||||||
peerPubkey: req.params?.peerPubkey,
|
|
||||||
});
|
|
||||||
throw new Error('Permission denied');
|
throw new Error('Permission denied');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -481,71 +470,47 @@ async function processNip07Request(req: BackgroundRequestMessage): Promise<any>
|
|||||||
}
|
}
|
||||||
|
|
||||||
const relays: Relays = {};
|
const relays: Relays = {};
|
||||||
let result: any;
|
|
||||||
|
|
||||||
switch (req.method) {
|
switch (req.method) {
|
||||||
case 'getPublicKey':
|
case 'getPublicKey':
|
||||||
result = NostrHelper.pubkeyFromPrivkey(currentIdentity.privkey);
|
return NostrHelper.pubkeyFromPrivkey(currentIdentity.privkey);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove);
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'signEvent':
|
case 'signEvent':
|
||||||
result = signEvent(req.params, currentIdentity.privkey);
|
return signEvent(req.params, currentIdentity.privkey);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove, {
|
|
||||||
kind: req.params?.kind,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'getRelays':
|
case 'getRelays':
|
||||||
browserSessionData.relays.forEach((x) => {
|
browserSessionData.relays.forEach((x) => {
|
||||||
relays[x.url] = { read: x.read, write: x.write };
|
relays[x.url] = { read: x.read, write: x.write };
|
||||||
});
|
});
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove);
|
|
||||||
return relays;
|
return relays;
|
||||||
|
|
||||||
case 'nip04.encrypt':
|
case 'nip04.encrypt':
|
||||||
result = await nip04Encrypt(
|
return await nip04Encrypt(
|
||||||
currentIdentity.privkey,
|
currentIdentity.privkey,
|
||||||
req.params.peerPubkey,
|
req.params.peerPubkey,
|
||||||
req.params.plaintext
|
req.params.plaintext
|
||||||
);
|
);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove, {
|
|
||||||
peerPubkey: req.params.peerPubkey,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'nip44.encrypt':
|
case 'nip44.encrypt':
|
||||||
result = await nip44Encrypt(
|
return await nip44Encrypt(
|
||||||
currentIdentity.privkey,
|
currentIdentity.privkey,
|
||||||
req.params.peerPubkey,
|
req.params.peerPubkey,
|
||||||
req.params.plaintext
|
req.params.plaintext
|
||||||
);
|
);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove, {
|
|
||||||
peerPubkey: req.params.peerPubkey,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'nip04.decrypt':
|
case 'nip04.decrypt':
|
||||||
result = await nip04Decrypt(
|
return await nip04Decrypt(
|
||||||
currentIdentity.privkey,
|
currentIdentity.privkey,
|
||||||
req.params.peerPubkey,
|
req.params.peerPubkey,
|
||||||
req.params.ciphertext
|
req.params.ciphertext
|
||||||
);
|
);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove, {
|
|
||||||
peerPubkey: req.params.peerPubkey,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
|
|
||||||
case 'nip44.decrypt':
|
case 'nip44.decrypt':
|
||||||
result = await nip44Decrypt(
|
return await nip44Decrypt(
|
||||||
currentIdentity.privkey,
|
currentIdentity.privkey,
|
||||||
req.params.peerPubkey,
|
req.params.peerPubkey,
|
||||||
req.params.ciphertext
|
req.params.ciphertext
|
||||||
);
|
);
|
||||||
await backgroundLogNip07Action(req.method, req.host, true, recklessApprove, {
|
|
||||||
peerPubkey: req.params.peerPubkey,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Not supported request method '${req.method}'.`);
|
throw new Error(`Not supported request method '${req.method}'.`);
|
||||||
@@ -625,7 +590,6 @@ async function processWeblnRequest(req: BackgroundRequestMessage): Promise<any>
|
|||||||
method,
|
method,
|
||||||
policy
|
policy
|
||||||
);
|
);
|
||||||
await backgroundLogPermissionStored(req.host, method, policy);
|
|
||||||
} else if (response === 'approve-all' && method !== 'webln.sendPayment' && method !== 'webln.keysend') {
|
} else if (response === 'approve-all' && method !== 'webln.sendPayment' && method !== 'webln.keysend') {
|
||||||
// P2: Store permission for all uses of this WebLN method
|
// P2: Store permission for all uses of this WebLN method
|
||||||
await storePermission(
|
await storePermission(
|
||||||
@@ -635,8 +599,6 @@ async function processWeblnRequest(req: BackgroundRequestMessage): Promise<any>
|
|||||||
method,
|
method,
|
||||||
'allow'
|
'allow'
|
||||||
);
|
);
|
||||||
await backgroundLogPermissionStored(req.host, method, 'allow');
|
|
||||||
debug(`Stored approve-all permission for ${method} from ${req.host}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (['reject', 'reject-once', 'reject-all'].includes(response)) {
|
if (['reject', 'reject-once', 'reject-all'].includes(response)) {
|
||||||
|
|||||||
Binary file not shown.
BIN
releases/plebeian-signer-chrome-v1.1.4.tar.gz
Normal file
BIN
releases/plebeian-signer-chrome-v1.1.4.tar.gz
Normal file
Binary file not shown.
BIN
releases/plebeian-signer-chrome-v1.1.5.zip
Normal file
BIN
releases/plebeian-signer-chrome-v1.1.5.zip
Normal file
Binary file not shown.
Binary file not shown.
BIN
releases/plebeian-signer-firefox-v1.1.4.tar.gz
Normal file
BIN
releases/plebeian-signer-firefox-v1.1.4.tar.gz
Normal file
Binary file not shown.
BIN
releases/plebeian-signer-firefox-v1.1.5.zip
Normal file
BIN
releases/plebeian-signer-firefox-v1.1.5.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user