rx-nostr
Version:
A library based on RxJS, which allows Nostr applications to easily communicate with relays.
89 lines (72 loc) • 1.99 kB
text/typescript
import { Subject } from "rxjs";
import type { Authenticator, FilledRxNostrConfig } from "../config/index.js";
import type { RelayConnection } from "./relay.js";
export class AuthProxy {
private relay: RelayConnection;
private config: FilledRxNostrConfig;
private authenticator: Authenticator;
private ongoings = new Set<string>();
private authResult$ = new Subject<boolean>();
private disposed = false;
constructor(params: {
relay: RelayConnection;
config: FilledRxNostrConfig;
authenticator: Authenticator;
}) {
this.relay = params.relay;
this.config = params.config;
this.authenticator = params.authenticator;
const listenOK = this.relay.getOKObservable().subscribe((result) => {
const { eventId, ok } = result;
if (!this.ongoings.has(eventId)) {
return;
}
this.ongoings.delete(eventId);
this.authResult$.next(ok);
if (!ok) {
listenOK.unsubscribe();
listenAUTH.unsubscribe();
}
});
const listenAUTH = this.relay
.getAUTHObservable()
.subscribe(({ challenge }) => {
this.challenge(challenge);
});
}
getAuthResultObservable() {
return this.authResult$.asObservable();
}
private async challenge(challenge: string): Promise<void> {
try {
const event = await this.signer.signEvent({
kind: 22242,
content: "",
tags: [
["relay", this.relay.url],
["challenge", challenge],
],
});
this.ongoings.add(event.id);
this.relay.send(["AUTH", event]);
} catch {
this.authResult$.next(false);
}
}
private get signer() {
return this.authenticator.signer ?? this.config.signer;
}
dispose() {
this[Symbol.dispose]();
}
[Symbol.dispose](): void {
if (this.disposed) {
return;
}
this.disposed = true;
const subjects = [this.authResult$];
for (const sub of subjects) {
sub.complete();
}
}
}