applesauce-signers 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/interop.d.ts +49 -0
- package/dist/interop.js +19 -0
- package/dist/signers/amber-clipboard-signer.d.ts +1 -1
- package/dist/signers/extension-signer.d.ts +1 -1
- package/dist/signers/nostr-connect-provider.d.ts +5 -12
- package/dist/signers/nostr-connect-provider.js +41 -41
- package/dist/signers/nostr-connect-signer.d.ts +10 -25
- package/dist/signers/nostr-connect-signer.js +26 -26
- package/dist/signers/password-signer.d.ts +1 -1
- package/dist/signers/readonly-signer.d.ts +1 -1
- package/dist/signers/serial-port-signer.d.ts +1 -1
- package/dist/signers/serial-port-signer.js +3 -0
- package/dist/signers/simple-signer.d.ts +1 -1
- package/package.json +17 -5
- package/dist/helpers/observable.d.ts +0 -11
- package/dist/helpers/observable.js +0 -2
- package/dist/interface.d.ts +0 -15
- package/dist/interface.js +0 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { EventTemplate, Filter, NostrEvent } from "nostr-tools";
|
|
2
|
+
import { ObservableInput } from "rxjs";
|
|
3
|
+
export type ISigner = {
|
|
4
|
+
getPublicKey: () => Promise<string>;
|
|
5
|
+
signEvent: (template: EventTemplate) => Promise<NostrEvent>;
|
|
6
|
+
nip04?: {
|
|
7
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string>;
|
|
8
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string>;
|
|
9
|
+
};
|
|
10
|
+
nip44?: {
|
|
11
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string>;
|
|
12
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string>;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
/** @deprecated Use ISigner instead */
|
|
16
|
+
export type Nip07Interface = ISigner;
|
|
17
|
+
/** A method used to subscribe to events on a set of relays */
|
|
18
|
+
export type NostrSubscriptionMethod = (relays: string[], filters: Filter[]) => ObservableInput<NostrEvent | string>;
|
|
19
|
+
/** A method used for publishing an event, can return a Promise that completes when published or an Observable that completes when published*/
|
|
20
|
+
export type NostrPublishMethod = (relays: string[], event: NostrEvent) => Promise<any> | ObservableInput<any>;
|
|
21
|
+
/** A simple pool type that combines the subscription and publish methods */
|
|
22
|
+
export type NostrPool = {
|
|
23
|
+
subscription: NostrSubscriptionMethod;
|
|
24
|
+
publish: NostrPublishMethod;
|
|
25
|
+
};
|
|
26
|
+
/** Options for setting the subscription and publish methods */
|
|
27
|
+
export type NostrConnectionMethodsOptions = {
|
|
28
|
+
/** An optional method for subscribing to relays */
|
|
29
|
+
subscriptionMethod?: NostrSubscriptionMethod;
|
|
30
|
+
/** An optional method for publishing events */
|
|
31
|
+
publishMethod?: NostrPublishMethod;
|
|
32
|
+
/** An optional pool for connection methods */
|
|
33
|
+
pool?: NostrPool;
|
|
34
|
+
};
|
|
35
|
+
/** A class that implements has global fallback methods for subscription and publish methods */
|
|
36
|
+
export interface NostrConnectionClassMethods {
|
|
37
|
+
new (...args: any[]): any;
|
|
38
|
+
/** A fallback method to use for subscriptionMethod if none is passed in when creating the client */
|
|
39
|
+
subscriptionMethod: NostrSubscriptionMethod | undefined;
|
|
40
|
+
/** A fallback method to use for publishMethod if none is passed in when creating the client */
|
|
41
|
+
publishMethod: NostrPublishMethod | undefined;
|
|
42
|
+
/** A fallback pool to use if none is pass in when creating the signer */
|
|
43
|
+
pool: NostrPool | undefined;
|
|
44
|
+
}
|
|
45
|
+
/** Get the subscription and publish methods for a NostrConnect class */
|
|
46
|
+
export declare function getConnectionMethods(options: NostrConnectionMethodsOptions, cls?: NostrConnectionClassMethods): {
|
|
47
|
+
subscriptionMethod: NostrSubscriptionMethod;
|
|
48
|
+
publishMethod: NostrPublishMethod;
|
|
49
|
+
};
|
package/dist/interop.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Get the subscription and publish methods for a NostrConnect class */
|
|
2
|
+
export function getConnectionMethods(options, cls) {
|
|
3
|
+
const subscriptionMethod = options.subscriptionMethod ||
|
|
4
|
+
options.pool?.subscription.bind(options.pool) ||
|
|
5
|
+
cls?.subscriptionMethod ||
|
|
6
|
+
cls?.pool?.subscription.bind(cls.pool);
|
|
7
|
+
if (!subscriptionMethod)
|
|
8
|
+
throw new Error("Missing subscriptionMethod, either pass a method or set subscriptionMethod globally on the class");
|
|
9
|
+
const publishMethod = options.publishMethod ||
|
|
10
|
+
options.pool?.publish.bind(options.pool) ||
|
|
11
|
+
cls?.publishMethod ||
|
|
12
|
+
cls?.pool?.publish.bind(cls.pool);
|
|
13
|
+
if (!publishMethod)
|
|
14
|
+
throw new Error("Missing publishMethod, either pass a method or set publishMethod globally on the class");
|
|
15
|
+
return {
|
|
16
|
+
subscriptionMethod,
|
|
17
|
+
publishMethod,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventTemplate, VerifiedEvent, verifyEvent } from "nostr-tools";
|
|
2
|
-
import { ISigner } from "../
|
|
2
|
+
import { ISigner } from "../interop.js";
|
|
3
3
|
/**
|
|
4
4
|
* A Signer for [amber](https://github.com/greenart7c3/Amber) clipboard API
|
|
5
5
|
* @see https://github.com/greenart7c3/Amber/blob/master/docs/web-apps.md
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventTemplate, VerifiedEvent } from "nostr-tools";
|
|
2
|
-
import { ISigner } from "../
|
|
2
|
+
import { ISigner } from "../interop.js";
|
|
3
3
|
/** AN error that is throw when the window.nostr extension is missing */
|
|
4
4
|
export declare class ExtensionMissingError extends Error {
|
|
5
5
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { EventTemplate, NostrEvent } from "nostr-tools";
|
|
2
|
+
import { Subscription } from "rxjs";
|
|
2
3
|
import { ConnectRequestParams, ConnectResponseResults, NostrConnectMethod, NostrConnectResponse, NostrConnectURI } from "../helpers/nostr-connect.js";
|
|
3
|
-
import { ISigner } from "../
|
|
4
|
-
import { Unsubscribable } from "../helpers/observable.js";
|
|
5
|
-
import { NostrPool, NostrPublishMethod, NostrSubscriptionMethod } from "./nostr-connect-signer.js";
|
|
4
|
+
import { ISigner, NostrConnectionMethodsOptions, NostrPool, NostrPublishMethod, NostrSubscriptionMethod } from "../interop.js";
|
|
6
5
|
export interface ProviderAuthorization {
|
|
7
6
|
/** A method used to accept or reject `connect` requests */
|
|
8
7
|
onConnect?: (client: string, permissions: string[]) => boolean | Promise<boolean>;
|
|
@@ -17,7 +16,7 @@ export interface ProviderAuthorization {
|
|
|
17
16
|
/** A method used to accept or reject `nip44_decrypt` requests */
|
|
18
17
|
onNip44Decrypt?: (pubkey: string, ciphertext: string, client: string) => boolean | Promise<boolean>;
|
|
19
18
|
}
|
|
20
|
-
export type NostrConnectProviderOptions = ProviderAuthorization & {
|
|
19
|
+
export type NostrConnectProviderOptions = ProviderAuthorization & NostrConnectionMethodsOptions & {
|
|
21
20
|
/** The relays to communicate over */
|
|
22
21
|
relays: string[];
|
|
23
22
|
/** The signer to use for signing events and encryption */
|
|
@@ -30,12 +29,6 @@ export type NostrConnectProviderOptions = ProviderAuthorization & {
|
|
|
30
29
|
onClientConnect?: (client: string) => any;
|
|
31
30
|
/** Callback for when a client disconnects (previously connected and the provider stops) */
|
|
32
31
|
onClientDisconnect?: (client: string) => void;
|
|
33
|
-
/** A method for subscribing to relays */
|
|
34
|
-
subscriptionMethod?: NostrSubscriptionMethod;
|
|
35
|
-
/** A method for publishing events */
|
|
36
|
-
publishMethod?: NostrPublishMethod;
|
|
37
|
-
/** A pool of methods to use if none are passed in when creating the provider */
|
|
38
|
-
pool?: NostrPool;
|
|
39
32
|
};
|
|
40
33
|
export declare class NostrConnectProvider implements ProviderAuthorization {
|
|
41
34
|
/** A fallback method to use for subscriptionMethod if none is passed in when creating the provider */
|
|
@@ -81,9 +74,9 @@ export declare class NostrConnectProvider implements ProviderAuthorization {
|
|
|
81
74
|
onNip44Encrypt?: (pubkey: string, plaintext: string, client: string) => boolean | Promise<boolean>;
|
|
82
75
|
/** A method used to accept or reject `nip44_decrypt` requests */
|
|
83
76
|
onNip44Decrypt?: (pubkey: string, ciphertext: string, client: string) => boolean | Promise<boolean>;
|
|
84
|
-
constructor(
|
|
77
|
+
constructor(options: NostrConnectProviderOptions);
|
|
85
78
|
/** The currently active REQ subscription */
|
|
86
|
-
protected req?:
|
|
79
|
+
protected req?: Subscription;
|
|
87
80
|
/** Updates the relay subscription to listen for request events */
|
|
88
81
|
protected updateSubscription(): Promise<void>;
|
|
89
82
|
/**
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { logger } from "applesauce-core";
|
|
2
2
|
import { getEncryptedContentEncryptionMethods, getHiddenContent, isEvent, unixNow, unlockHiddenContent, } from "applesauce-core/helpers";
|
|
3
3
|
import { createDefer } from "applesauce-core/promise";
|
|
4
|
-
import { kinds, verifyEvent } from "nostr-tools";
|
|
5
4
|
import { nanoid } from "nanoid";
|
|
5
|
+
import { kinds, verifyEvent } from "nostr-tools";
|
|
6
|
+
import { filter, from, repeat, retry } from "rxjs";
|
|
6
7
|
import { isNIP04 } from "../helpers/encryption.js";
|
|
7
8
|
import { createBunkerURI, NostrConnectMethod, parseNostrConnectURI, } from "../helpers/nostr-connect.js";
|
|
9
|
+
import { getConnectionMethods, } from "../interop.js";
|
|
8
10
|
import { SimpleSigner } from "./simple-signer.js";
|
|
9
11
|
export class NostrConnectProvider {
|
|
10
12
|
/** A fallback method to use for subscriptionMethod if none is passed in when creating the provider */
|
|
@@ -50,45 +52,34 @@ export class NostrConnectProvider {
|
|
|
50
52
|
onNip44Encrypt;
|
|
51
53
|
/** A method used to accept or reject `nip44_decrypt` requests */
|
|
52
54
|
onNip44Decrypt;
|
|
53
|
-
constructor(
|
|
54
|
-
this.relays =
|
|
55
|
-
this.upstream =
|
|
56
|
-
this.signer =
|
|
57
|
-
this.secret =
|
|
55
|
+
constructor(options) {
|
|
56
|
+
this.relays = options.relays;
|
|
57
|
+
this.upstream = options.upstream;
|
|
58
|
+
this.signer = options.signer ?? new SimpleSigner();
|
|
59
|
+
this.secret = options.secret;
|
|
58
60
|
// Get the subscription and publish methods
|
|
59
|
-
const subscriptionMethod =
|
|
60
|
-
opts.pool?.subscription ||
|
|
61
|
-
NostrConnectProvider.subscriptionMethod ||
|
|
62
|
-
NostrConnectProvider.pool?.subscription;
|
|
63
|
-
if (!subscriptionMethod)
|
|
64
|
-
throw new Error("Missing subscriptionMethod, either pass a method or set NostrConnectProvider.subscriptionMethod");
|
|
65
|
-
const publishMethod = opts.publishMethod ||
|
|
66
|
-
opts.pool?.publish ||
|
|
67
|
-
NostrConnectProvider.publishMethod ||
|
|
68
|
-
NostrConnectProvider.pool?.publish;
|
|
69
|
-
if (!publishMethod)
|
|
70
|
-
throw new Error("Missing publishMethod, either pass a method or set NostrConnectProvider.publishMethod");
|
|
61
|
+
const { subscriptionMethod, publishMethod } = getConnectionMethods(options, NostrConnectProvider);
|
|
71
62
|
// Use arrow functions so "this" isn't bound to the signer
|
|
72
63
|
this.subscriptionMethod = (relays, filters) => subscriptionMethod(relays, filters);
|
|
73
64
|
this.publishMethod = (relays, event) => publishMethod(relays, event);
|
|
74
65
|
// Set client connection callbacks
|
|
75
|
-
if (
|
|
76
|
-
this.onClientConnect =
|
|
77
|
-
if (
|
|
78
|
-
this.onClientDisconnect =
|
|
66
|
+
if (options.onClientConnect)
|
|
67
|
+
this.onClientConnect = options.onClientConnect;
|
|
68
|
+
if (options.onClientDisconnect)
|
|
69
|
+
this.onClientDisconnect = options.onClientDisconnect;
|
|
79
70
|
// Set authorization callbacks
|
|
80
|
-
if (
|
|
81
|
-
this.onConnect =
|
|
82
|
-
if (
|
|
83
|
-
this.onSignEvent =
|
|
84
|
-
if (
|
|
85
|
-
this.onNip04Encrypt =
|
|
86
|
-
if (
|
|
87
|
-
this.onNip04Decrypt =
|
|
88
|
-
if (
|
|
89
|
-
this.onNip44Encrypt =
|
|
90
|
-
if (
|
|
91
|
-
this.onNip44Decrypt =
|
|
71
|
+
if (options.onConnect)
|
|
72
|
+
this.onConnect = options.onConnect;
|
|
73
|
+
if (options.onSignEvent)
|
|
74
|
+
this.onSignEvent = options.onSignEvent;
|
|
75
|
+
if (options.onNip04Encrypt)
|
|
76
|
+
this.onNip04Encrypt = options.onNip04Encrypt;
|
|
77
|
+
if (options.onNip04Decrypt)
|
|
78
|
+
this.onNip04Decrypt = options.onNip04Decrypt;
|
|
79
|
+
if (options.onNip44Encrypt)
|
|
80
|
+
this.onNip44Encrypt = options.onNip44Encrypt;
|
|
81
|
+
if (options.onNip44Decrypt)
|
|
82
|
+
this.onNip44Decrypt = options.onNip44Decrypt;
|
|
92
83
|
}
|
|
93
84
|
/** The currently active REQ subscription */
|
|
94
85
|
req;
|
|
@@ -98,7 +89,7 @@ export class NostrConnectProvider {
|
|
|
98
89
|
this.req.unsubscribe();
|
|
99
90
|
const pubkey = await this.signer.getPublicKey();
|
|
100
91
|
// Setup subscription to listen for requests
|
|
101
|
-
this.req = this.subscriptionMethod(this.relays, [
|
|
92
|
+
this.req = from(this.subscriptionMethod(this.relays, [
|
|
102
93
|
// If client is known, only listen for requests from the client
|
|
103
94
|
this.client
|
|
104
95
|
? {
|
|
@@ -111,9 +102,15 @@ export class NostrConnectProvider {
|
|
|
111
102
|
kinds: [kinds.NostrConnect],
|
|
112
103
|
"#p": [pubkey],
|
|
113
104
|
},
|
|
114
|
-
])
|
|
115
|
-
|
|
116
|
-
|
|
105
|
+
]))
|
|
106
|
+
.pipe(
|
|
107
|
+
// Keep the connection open indefinitely
|
|
108
|
+
repeat(),
|
|
109
|
+
// Retry on connection failure
|
|
110
|
+
retry(),
|
|
111
|
+
// Ignore strings (support for applesauce-relay)
|
|
112
|
+
filter((event) => typeof event !== "string"))
|
|
113
|
+
.subscribe(this.handleEvent.bind(this));
|
|
117
114
|
}
|
|
118
115
|
/**
|
|
119
116
|
* Start the provider
|
|
@@ -254,9 +251,12 @@ export class NostrConnectProvider {
|
|
|
254
251
|
const providerPubkey = await this.signer.getPublicKey();
|
|
255
252
|
if (target !== providerPubkey)
|
|
256
253
|
throw new Error("Invalid target pubkey");
|
|
257
|
-
// If
|
|
258
|
-
if (this.
|
|
259
|
-
throw new Error("
|
|
254
|
+
// If the client is already known, ensure that it matches the new client
|
|
255
|
+
if (this.client && this.client !== client)
|
|
256
|
+
throw new Error("Only one client can connect at a time");
|
|
257
|
+
// If this is the first `connect` request, check that the secret matches
|
|
258
|
+
if (this.secret && !this.client && this.secret !== secret)
|
|
259
|
+
throw new Error("Invalid connection secret");
|
|
260
260
|
// Handle authorization if callback is provided
|
|
261
261
|
if (this.onConnect) {
|
|
262
262
|
const authorized = await this.onConnect(client, permissions);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Deferred } from "applesauce-core/promise";
|
|
2
|
-
import { ISigner, SimpleSigner } from "applesauce-signers";
|
|
3
|
-
import { EventTemplate,
|
|
2
|
+
import { ISigner, NostrConnectionMethodsOptions, NostrPool, NostrPublishMethod, NostrSubscriptionMethod, SimpleSigner } from "applesauce-signers";
|
|
3
|
+
import { EventTemplate, NostrEvent, verifyEvent } from "nostr-tools";
|
|
4
|
+
import { Subscription } from "rxjs";
|
|
4
5
|
import { BunkerURI, NostrConnectAppMetadata } from "../helpers/nostr-connect.js";
|
|
5
|
-
|
|
6
|
-
export type NostrConnectSignerOptions = {
|
|
6
|
+
export type NostrConnectSignerOptions = NostrConnectionMethodsOptions & {
|
|
7
7
|
/** The relays to communicate over */
|
|
8
8
|
relays: string[];
|
|
9
9
|
/** A {@link SimpleSigner} for this client */
|
|
@@ -16,33 +16,18 @@ export type NostrConnectSignerOptions = {
|
|
|
16
16
|
secret?: string;
|
|
17
17
|
/** A method for handling "auth" requests */
|
|
18
18
|
onAuth?: (url: string) => Promise<void>;
|
|
19
|
-
/** A method for subscribing to relays */
|
|
20
|
-
subscriptionMethod?: NostrSubscriptionMethod;
|
|
21
|
-
/** A method for publishing events */
|
|
22
|
-
publishMethod?: NostrPublishMethod;
|
|
23
|
-
/** A pool of methods to use if none are passed in when creating the signer */
|
|
24
|
-
pool?: NostrPool;
|
|
25
|
-
};
|
|
26
|
-
/** A method used to subscribe to events on a set of relays */
|
|
27
|
-
export type NostrSubscriptionMethod = (relays: string[], filters: Filter[]) => Subscribable<NostrEvent | string>;
|
|
28
|
-
/** A method used for publishing an event, can return a Promise that completes when published or an Observable that completes when published*/
|
|
29
|
-
export type NostrPublishMethod = (relays: string[], event: NostrEvent) => Promise<any> | Subscribable<any>;
|
|
30
|
-
/** A simple pool type that combines the subscription and publish methods */
|
|
31
|
-
export type NostrPool = {
|
|
32
|
-
subscription: NostrSubscriptionMethod;
|
|
33
|
-
publish: NostrPublishMethod;
|
|
34
19
|
};
|
|
35
20
|
export declare class NostrConnectSigner implements ISigner {
|
|
36
|
-
/** A method that is called when an event needs to be published */
|
|
37
|
-
protected publishMethod: NostrPublishMethod;
|
|
38
|
-
/** The active nostr subscription */
|
|
39
|
-
protected subscriptionMethod: NostrSubscriptionMethod;
|
|
40
21
|
/** A fallback method to use for subscriptionMethod if none is pass in when creating the signer */
|
|
41
22
|
static subscriptionMethod: NostrSubscriptionMethod | undefined;
|
|
42
23
|
/** A fallback method to use for publishMethod if none is pass in when creating the signer */
|
|
43
24
|
static publishMethod: NostrPublishMethod | undefined;
|
|
44
25
|
/** A fallback pool to use if none is pass in when creating the signer */
|
|
45
26
|
static pool: NostrPool | undefined;
|
|
27
|
+
/** A method that is called when an event needs to be published */
|
|
28
|
+
protected publishMethod: NostrPublishMethod;
|
|
29
|
+
/** The active nostr subscription */
|
|
30
|
+
protected subscriptionMethod: NostrSubscriptionMethod;
|
|
46
31
|
protected log: import("debug").Debugger;
|
|
47
32
|
/** The local client signer */
|
|
48
33
|
signer: SimpleSigner;
|
|
@@ -71,9 +56,9 @@ export declare class NostrConnectSigner implements ISigner {
|
|
|
71
56
|
encrypt: (pubkey: string, plaintext: string) => Promise<string>;
|
|
72
57
|
decrypt: (pubkey: string, ciphertext: string) => Promise<string>;
|
|
73
58
|
} | undefined;
|
|
74
|
-
constructor(
|
|
59
|
+
constructor(options: NostrConnectSignerOptions);
|
|
75
60
|
/** The currently active REQ subscription */
|
|
76
|
-
protected req?:
|
|
61
|
+
protected req?: Subscription;
|
|
77
62
|
/** Open the connection */
|
|
78
63
|
open(): Promise<void>;
|
|
79
64
|
/** Close the connection */
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import { logger } from "applesauce-core";
|
|
2
2
|
import { getHiddenContent, unixNow } from "applesauce-core/helpers";
|
|
3
3
|
import { createDefer } from "applesauce-core/promise";
|
|
4
|
-
import { SimpleSigner } from "applesauce-signers";
|
|
4
|
+
import { SimpleSigner, getConnectionMethods, } from "applesauce-signers";
|
|
5
5
|
import { nanoid } from "nanoid";
|
|
6
6
|
import { getPublicKey, kinds, verifyEvent } from "nostr-tools";
|
|
7
|
+
import { filter, from, repeat, retry } from "rxjs";
|
|
7
8
|
import { isNIP04 } from "../helpers/encryption.js";
|
|
8
9
|
import { NostrConnectMethod, buildSigningPermissions, createNostrConnectURI, parseBunkerURI, } from "../helpers/nostr-connect.js";
|
|
9
10
|
async function defaultHandleAuth(url) {
|
|
10
11
|
window.open(url, "auth", "width=400,height=600,resizable=no,status=no,location=no,toolbar=no,menubar=no");
|
|
11
12
|
}
|
|
12
13
|
export class NostrConnectSigner {
|
|
13
|
-
/** A method that is called when an event needs to be published */
|
|
14
|
-
publishMethod;
|
|
15
|
-
/** The active nostr subscription */
|
|
16
|
-
subscriptionMethod;
|
|
17
14
|
/** A fallback method to use for subscriptionMethod if none is pass in when creating the signer */
|
|
18
15
|
static subscriptionMethod = undefined;
|
|
19
16
|
/** A fallback method to use for publishMethod if none is pass in when creating the signer */
|
|
20
17
|
static publishMethod = undefined;
|
|
21
18
|
/** A fallback pool to use if none is pass in when creating the signer */
|
|
22
19
|
static pool = undefined;
|
|
20
|
+
/** A method that is called when an event needs to be published */
|
|
21
|
+
publishMethod;
|
|
22
|
+
/** The active nostr subscription */
|
|
23
|
+
subscriptionMethod;
|
|
23
24
|
log = logger.extend("NostrConnectSigner");
|
|
24
25
|
/** The local client signer */
|
|
25
26
|
signer;
|
|
@@ -44,27 +45,20 @@ export class NostrConnectSigner {
|
|
|
44
45
|
secret;
|
|
45
46
|
nip04;
|
|
46
47
|
nip44;
|
|
47
|
-
constructor(
|
|
48
|
-
this.relays =
|
|
49
|
-
this.pubkey =
|
|
50
|
-
this.remote =
|
|
51
|
-
this.secret =
|
|
48
|
+
constructor(options) {
|
|
49
|
+
this.relays = options.relays;
|
|
50
|
+
this.pubkey = options.pubkey;
|
|
51
|
+
this.remote = options.remote;
|
|
52
|
+
this.secret = options.secret || nanoid(12);
|
|
52
53
|
// Get the subscription and publish methods
|
|
53
|
-
const subscriptionMethod =
|
|
54
|
-
opts.pool?.subscription ||
|
|
55
|
-
NostrConnectSigner.subscriptionMethod ||
|
|
56
|
-
NostrConnectSigner.pool?.subscription;
|
|
57
|
-
if (!subscriptionMethod)
|
|
58
|
-
throw new Error("Missing subscriptionMethod, either pass a method or set NostrConnectSigner.subscriptionMethod");
|
|
59
|
-
const publishMethod = opts.publishMethod || opts.pool?.publish || NostrConnectSigner.publishMethod || NostrConnectSigner.pool?.publish;
|
|
60
|
-
if (!publishMethod)
|
|
61
|
-
throw new Error("Missing publishMethod, either pass a method or set NostrConnectSigner.publishMethod");
|
|
54
|
+
const { subscriptionMethod, publishMethod } = getConnectionMethods(options, NostrConnectSigner);
|
|
62
55
|
// Use arrow functions so "this" isn't bound to the signer
|
|
63
56
|
this.subscriptionMethod = (relays, filters) => subscriptionMethod(relays, filters);
|
|
64
57
|
this.publishMethod = (relays, event) => publishMethod(relays, event);
|
|
65
|
-
if (
|
|
66
|
-
this.onAuth =
|
|
67
|
-
|
|
58
|
+
if (options.onAuth)
|
|
59
|
+
this.onAuth = options.onAuth;
|
|
60
|
+
// Get or create the local signer
|
|
61
|
+
this.signer = options?.signer || new SimpleSigner();
|
|
68
62
|
this.nip04 = {
|
|
69
63
|
encrypt: this.nip04Encrypt.bind(this),
|
|
70
64
|
decrypt: this.nip04Decrypt.bind(this),
|
|
@@ -83,14 +77,20 @@ export class NostrConnectSigner {
|
|
|
83
77
|
this.listening = true;
|
|
84
78
|
const pubkey = await this.signer.getPublicKey();
|
|
85
79
|
// Setup subscription
|
|
86
|
-
this.req = this.subscriptionMethod(this.relays, [
|
|
80
|
+
this.req = from(this.subscriptionMethod(this.relays, [
|
|
87
81
|
{
|
|
88
82
|
kinds: [kinds.NostrConnect],
|
|
89
83
|
"#p": [pubkey],
|
|
90
84
|
},
|
|
91
|
-
])
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
]))
|
|
86
|
+
.pipe(
|
|
87
|
+
// Keep the connection open indefinitely
|
|
88
|
+
repeat(),
|
|
89
|
+
// Retry on connection failure
|
|
90
|
+
retry(),
|
|
91
|
+
// Ignore strings (support for applesauce-relay)
|
|
92
|
+
filter((event) => typeof event !== "string"))
|
|
93
|
+
.subscribe(this.handleEvent.bind(this));
|
|
94
94
|
this.log("Opened", this.relays);
|
|
95
95
|
}
|
|
96
96
|
/** Close the connection */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EventTemplate } from "nostr-tools";
|
|
2
2
|
import { Deferred } from "applesauce-core/promise";
|
|
3
|
-
import { ISigner } from "../
|
|
3
|
+
import { ISigner } from "../interop.js";
|
|
4
4
|
/** A NIP-49 (Private Key Encryption) signer */
|
|
5
5
|
export declare class PasswordSigner implements ISigner {
|
|
6
6
|
key: Uint8Array | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { VerifiedEvent } from "nostr-tools";
|
|
2
|
-
import { ISigner } from "../
|
|
2
|
+
import { ISigner } from "../interop.js";
|
|
3
3
|
/** A signer that only implements getPublicKey and throws on ever other method */
|
|
4
4
|
export declare class ReadonlySigner implements ISigner {
|
|
5
5
|
private pubkey;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Deferred } from "applesauce-core/promise";
|
|
2
2
|
import { EventTemplate, verifyEvent } from "nostr-tools";
|
|
3
|
-
import { ISigner } from "../
|
|
3
|
+
import { ISigner } from "../interop.js";
|
|
4
4
|
type Callback = () => void;
|
|
5
5
|
type DeviceOpts = {
|
|
6
6
|
onConnect?: Callback;
|
|
@@ -169,6 +169,7 @@ export class SerialPortSigner {
|
|
|
169
169
|
const sharedSecret = hexToBytes(sharedSecretStr);
|
|
170
170
|
let iv = Uint8Array.from(randomBytes(16));
|
|
171
171
|
let plaintext = utf8Encoder.encode(text);
|
|
172
|
+
// @ts-ignore
|
|
172
173
|
let cryptoKey = await crypto.subtle.importKey("raw", sharedSecret, { name: "AES-CBC" }, false, ["encrypt"]);
|
|
173
174
|
let ciphertext = await crypto.subtle.encrypt({ name: "AES-CBC", iv }, cryptoKey, plaintext);
|
|
174
175
|
let ctb64 = base64.encode(new Uint8Array(ciphertext));
|
|
@@ -179,9 +180,11 @@ export class SerialPortSigner {
|
|
|
179
180
|
let [ctb64, ivb64] = data.split("?iv=");
|
|
180
181
|
const sharedSecretStr = await this.callMethodOnDevice(SerialPortSigner.METHOD_SHARED_SECRET, [xOnlyToXY(pubkey)]);
|
|
181
182
|
const sharedSecret = hexToBytes(sharedSecretStr);
|
|
183
|
+
// @ts-ignore
|
|
182
184
|
let cryptoKey = await crypto.subtle.importKey("raw", sharedSecret, { name: "AES-CBC" }, false, ["decrypt"]);
|
|
183
185
|
let ciphertext = base64.decode(ctb64);
|
|
184
186
|
let iv = base64.decode(ivb64);
|
|
187
|
+
// @ts-ignore
|
|
185
188
|
let plaintext = await crypto.subtle.decrypt({ name: "AES-CBC", iv }, cryptoKey, ciphertext);
|
|
186
189
|
let text = utf8Decoder.decode(plaintext);
|
|
187
190
|
return text;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "applesauce-signers",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Signer classes for applesauce",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
"author": "hzrd149",
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"files": [
|
|
17
|
-
"dist"
|
|
18
|
-
"applesauce"
|
|
17
|
+
"dist"
|
|
19
18
|
],
|
|
20
19
|
"exports": {
|
|
21
20
|
".": {
|
|
@@ -32,20 +31,32 @@
|
|
|
32
31
|
"import": "./dist/signers/*.js",
|
|
33
32
|
"require": "./dist/signers/*.js",
|
|
34
33
|
"types": "./dist/signers/*.d.ts"
|
|
34
|
+
},
|
|
35
|
+
"./helpers": {
|
|
36
|
+
"import": "./dist/helpers/index.js",
|
|
37
|
+
"require": "./dist/helpers/index.js",
|
|
38
|
+
"types": "./dist/helpers/index.d.ts"
|
|
39
|
+
},
|
|
40
|
+
"./helpers/*": {
|
|
41
|
+
"import": "./dist/helpers/*.js",
|
|
42
|
+
"require": "./dist/helpers/*.js",
|
|
43
|
+
"types": "./dist/helpers/*.d.ts"
|
|
35
44
|
}
|
|
36
45
|
},
|
|
37
46
|
"dependencies": {
|
|
38
47
|
"@noble/hashes": "^1.7.1",
|
|
39
48
|
"@noble/secp256k1": "^1.7.1",
|
|
40
49
|
"@scure/base": "^1.2.4",
|
|
41
|
-
"applesauce-core": "^
|
|
50
|
+
"applesauce-core": "^4.0.0",
|
|
42
51
|
"debug": "^4.4.0",
|
|
43
52
|
"nanoid": "^5.0.9",
|
|
44
|
-
"nostr-tools": "
|
|
53
|
+
"nostr-tools": "~2.17",
|
|
54
|
+
"rxjs": "^7.8.2"
|
|
45
55
|
},
|
|
46
56
|
"devDependencies": {
|
|
47
57
|
"@types/debug": "^4.1.12",
|
|
48
58
|
"@types/dom-serial": "^1.0.6",
|
|
59
|
+
"rimraf": "^6.0.1",
|
|
49
60
|
"typescript": "^5.8.3",
|
|
50
61
|
"vitest": "^3.1.3",
|
|
51
62
|
"vitest-websocket-mock": "^0.5.0"
|
|
@@ -55,6 +66,7 @@
|
|
|
55
66
|
"url": "lightning:nostrudel@geyser.fund"
|
|
56
67
|
},
|
|
57
68
|
"scripts": {
|
|
69
|
+
"prebuild": "rimraf dist",
|
|
58
70
|
"build": "tsc",
|
|
59
71
|
"watch:build": "tsc --watch > /dev/null",
|
|
60
72
|
"test": "vitest run --passWithNoTests",
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export interface Unsubscribable {
|
|
2
|
-
unsubscribe(): void;
|
|
3
|
-
}
|
|
4
|
-
export interface Observer<T> {
|
|
5
|
-
next: (value: T) => void;
|
|
6
|
-
error: (err: any) => void;
|
|
7
|
-
complete: () => void;
|
|
8
|
-
}
|
|
9
|
-
export type Subscribable<T extends unknown> = {
|
|
10
|
-
subscribe: (observer: Partial<Observer<T>>) => Unsubscribable;
|
|
11
|
-
};
|
package/dist/interface.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { EventTemplate, NostrEvent } from "nostr-tools";
|
|
2
|
-
export type ISigner = {
|
|
3
|
-
getPublicKey: () => Promise<string>;
|
|
4
|
-
signEvent: (template: EventTemplate) => Promise<NostrEvent>;
|
|
5
|
-
nip04?: {
|
|
6
|
-
encrypt: (pubkey: string, plaintext: string) => Promise<string>;
|
|
7
|
-
decrypt: (pubkey: string, ciphertext: string) => Promise<string>;
|
|
8
|
-
};
|
|
9
|
-
nip44?: {
|
|
10
|
-
encrypt: (pubkey: string, plaintext: string) => Promise<string>;
|
|
11
|
-
decrypt: (pubkey: string, ciphertext: string) => Promise<string>;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
/** @deprecated Use ISigner instead */
|
|
15
|
-
export type Nip07Interface = ISigner;
|
package/dist/interface.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|