Add DELETE for names and PUT for name transfer

This commit is contained in:
artur 2024-02-16 09:24:08 +03:00
parent 43151f36b6
commit b42621cb23
2 changed files with 242 additions and 48 deletions

View File

@ -781,15 +781,6 @@ app.post(NAME_PATH, async (req, res) => {
return;
}
const { type } = nip19.decode(npub);
if (type !== "npub") {
console.log("bad npub", npub);
res.status(400).send({
error: "Bad npub",
});
return;
}
const minPow = getMinPow(name, req);
if (!(await verifyAuthNostr(req, npub, NAME_PATH, minPow))) {
@ -876,6 +867,104 @@ app.get(NAME_PATH, async (req, res) => {
}
});
app.delete(NAME_PATH, async (req, res) => {
try {
const { npub, name } = req.body;
if (!(await verifyAuthNostr(req, npub, NAME_PATH))) {
console.log("auth failed", npub);
res.status(403).send({
error: `Bad auth`
});
return;
}
try {
const deletedName = await prisma.names.delete({
where: {
npub,
name,
},
});
console.log({ deletedName });
} catch (e) {
console.log("Failed to delete name", name, npub);
res.status(404).send({
error: "Name not found",
});
return;
}
// reply ok
res.status(200).send({
ok: true,
});
} catch (e) {
console.log(new Date(), "error req from ", req.ip, e.toString());
res.status(500).send({
error: "Internal error",
});
}
});
app.put(NAME_PATH, async (req, res) => {
try {
const { npub, name, newNpub } = req.body;
if (!(await verifyAuthNostr(req, npub, NAME_PATH))) {
console.log("auth failed", npub);
res.status(403).send({
error: `Bad auth`
});
return;
}
try {
const deletedName = await prisma.names.delete({
where: {
npub,
name,
},
});
console.log({ deletedName });
} catch (e) {
console.log("Failed to delete name", name, npub);
res.status(404).send({
error: "Name not found",
});
return;
}
try {
const dbr = await prisma.names.create({
data: {
npub: newNpub,
name,
timestamp: Date.now(),
},
});
console.log({ dbr });
} catch (e) {
res.status(400).send({
error: "Name taken",
});
return;
}
// reply ok
res.status(201).send({
ok: true,
});
} catch (e) {
console.log(new Date(), "error req from ", req.ip, e.toString());
res.status(500).send({
error: "Internal error",
});
}
});
const JSON_PATH = "/.well-known/nostr.json";
app.get(JSON_PATH, async (req, res) => {
try {

View File

@ -15,10 +15,10 @@ const ndk = new NDK({
explicitRelayUrls: ["wss://relay.nsec.app"],
});
const LOCAL = false;
const LOCAL = true;
const BUNKER_PUBKEY = LOCAL
? "44f9def756f8575aed604408a5c8f5a09d01633015fc65894fdd12af77457f3a"
: "e24a86943d37a91ab485d6f9a7c66097c25ddd67e8bd1b75ed252a3c266cf9bb"
: "e24a86943d37a91ab485d6f9a7c66097c25ddd67e8bd1b75ed252a3c266cf9bb";
const sk = generatePrivateKey();
console.log("test pubkey", getPublicKey(sk));
@ -33,32 +33,69 @@ async function sendPost({ url, method, headers, body }) {
const r = await fetch(url, {
method,
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
...headers,
},
body,
})
});
if (r.status !== 200 && r.status !== 201) {
console.log('Fetch error', url, method, r.status)
const body = await r.json()
throw new Error('Failed to fetch ' + url, { cause: body })
console.log("Fetch error", url, method, r.status);
const body = await r.json();
throw new Error("Failed to fetch " + url, { cause: body });
}
return await r.json()
return await r.json();
}
async function sha256(data) {
return createHash('sha256').update(data, 'utf8').digest().toString('hex')
function sha256(data) {
return createHash("sha256").update(data, "utf8").digest().toString("hex");
}
function countLeadingZeros(hex) {
let count = 0
for (let i = 0; i < hex.length; i++) {
const nibble = parseInt(hex[i], 16)
if (nibble === 0) {
count += 4
} else {
count += Math.clz32(nibble) - 28
break
}
}
return count
}
function minePow(e, target) {
let ctr = 0
let nonceTagIdx = e.tags.findIndex((a) => a[0] === 'nonce')
if (nonceTagIdx === -1) {
nonceTagIdx = e.tags.length
e.tags.push(['nonce', ctr.toString(), target.toString()])
}
do {
e.tags[nonceTagIdx][1] = (++ctr).toString()
e.id = createId(e)
} while (countLeadingZeros(e.id) < target)
return e
}
function createId(e) {
const payload = [0, e.pubkey, e.created_at, e.kind, e.tags, e.content]
return sha256(JSON.stringify(payload))
}
async function sendPostAuthd({
sk,
url,
method = 'GET',
body = ''
body = '',
pow = 0,
}) {
const pubkey = getPublicKey(sk)
const pubkey = getPublicKey(sk);
const signer = new NDKPrivateKeySigner(sk);
const authEvent = new NDKEvent(ndk, {
@ -73,9 +110,20 @@ async function sendPostAuthd({
})
if (body) authEvent.tags.push(['payload', await sha256(body)])
authEvent.sig = await authEvent.sign(signer)
// generate pow on auth evevnt
if (pow) {
const start = Date.now()
const powEvent = authEvent.rawEvent()
const minedEvent = minePow(powEvent, pow)
console.log('mined pow of', pow, 'in', Date.now() - start, 'ms', minedEvent)
authEvent.tags = minedEvent.tags
}
const auth = Buffer.from(JSON.stringify(authEvent.rawEvent())).toString('base64')
authEvent.sig = await authEvent.sign(signer);
const auth = Buffer.from(JSON.stringify(authEvent.rawEvent())).toString(
"base64"
);
return await sendPost({
url,
@ -87,39 +135,96 @@ async function sendPostAuthd({
})
}
// OAuth flow
signer.on("authUrl", async (url) => {
console.log("nostr login auth url", url);
const u = new URL(url);
const token = u.searchParams.get('token');
const token = u.searchParams.get("token");
console.log({ token });
const sk = generatePrivateKey();
console.log("created account", getPublicKey(sk));
await sendPostAuthd({
sk,
method: 'POST',
url: LOCAL ? 'http://localhost:8000/created' : 'https://noauthd.nsec.app/created',
method: "POST",
url: LOCAL
? "http://localhost:8000/created"
: "https://noauthd.nsec.app/created",
body: JSON.stringify({
npub: nip19.npubEncode(getPublicKey(sk)),
token,
})
})
}),
});
});
const params = [
if (process.argv.length >= 3) {
if (process.argv[2] === "check_names") {
const sk = generatePrivateKey();
const npub = nip19.npubEncode(getPublicKey(sk))
const sk1 = generatePrivateKey();
const npub1 = nip19.npubEncode(getPublicKey(sk1))
const name = npub.substring(0, 10);
console.log("create name", npub, name);
const test = async () => {
await sendPostAuthd({
sk,
method: "POST",
url: LOCAL
? "http://localhost:8000/name"
: "https://noauthd.nsec.app/name",
body: JSON.stringify({
npub,
name,
}),
pow: 15
});
console.log("created");
await sendPostAuthd({
sk,
method: "PUT",
url: LOCAL
? "http://localhost:8000/name"
: "https://noauthd.nsec.app/name",
body: JSON.stringify({
npub,
name: name,
newNpub: npub1
}),
});
console.log("transferred")
await sendPostAuthd({
sk: sk1,
method: "DELETE",
url: LOCAL
? "http://localhost:8000/name"
: "https://noauthd.nsec.app/name",
body: JSON.stringify({
npub: npub1,
name: name,
}),
});
console.log("deleted");
}
test()
}
} else {
const params = [
"test",
"nsec.app",
// email?
];
ndk
];
ndk
.connect()
.then(async () => {
console.log("sending", params);
signer.rpc.sendRequest(
BUNKER_PUBKEY, "create_account", params, undefined,
BUNKER_PUBKEY,
"create_account",
params,
undefined,
(res) => {
console.log({ res });
});
}
);
})
.then(console.log);
}