Skip to content

Commit

Permalink
feat: allow revoking linked signing key with the signing key or linke…
Browse files Browse the repository at this point in the history
…d account key
  • Loading branch information
mistakia committed Jun 17, 2024
1 parent 0b31620 commit e633e74
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 125 deletions.
54 changes: 26 additions & 28 deletions api/routes/auth/revoke.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import express from 'express'
import {
verify_nano_community_revoke_key_signature,
is_nano_address_valid,
decode_nano_address
} from '#common'

Expand All @@ -12,18 +11,14 @@ const SIGNATURE_RE = /^[0-9a-fA-F]{128}$/
router.post('/key/?', async (req, res) => {
const { logger, db } = req.app.locals
try {
const required = ['account', 'public_key', 'signature']
const required = ['public_key', 'signature']
for (const prop of required) {
if (!req.body[prop]) {
return res.status(400).send({ error: `missing ${prop} param` })
}
}

const { account, public_key, signature } = req.body

if (!is_nano_address_valid(account)) {
return res.status(401).send({ error: 'invalid account param' })
}
const { public_key, signature } = req.body

if (typeof public_key !== 'string' || !PUBLIC_KEY_RE.test(public_key)) {
return res.status(401).send({ error: 'invalid public_key param' })
Expand All @@ -33,27 +28,10 @@ router.post('/key/?', async (req, res) => {
return res.status(401).send({ error: 'invalid signature param' })
}

const { public_key: account_public_key } = decode_nano_address({
address: account
})
const valid_signature = verify_nano_community_revoke_key_signature({
linked_public_key: public_key,
nano_account: account,
nano_account_public_key: account_public_key,
signature
})
if (!valid_signature) {
return res.status(401).send({ error: 'invalid signature' })
}

const linked_key = await db('account_keys')
.where({ account, public_key })
.first()
const linked_key = await db('account_keys').where({ public_key }).first()

if (!linked_key) {
return res
.status(401)
.send({ error: `key ${public_key} not linked to account ${account}` })
return res.status(401).send({ error: `key ${public_key} not found` })
}

if (linked_key.revoked_at) {
Expand All @@ -62,13 +40,33 @@ router.post('/key/?', async (req, res) => {
.send({ error: `key ${public_key} already revoked` })
}

const valid_signing_key_signature =
verify_nano_community_revoke_key_signature({
linked_public_key: public_key,
either_public_key: public_key,
signature
})
const { public_key: account_public_key } = decode_nano_address({
address: linked_key.account
})
const valid_account_key_signature =
verify_nano_community_revoke_key_signature({
linked_public_key: public_key,
either_public_key: account_public_key,
signature
})

if (!valid_signing_key_signature && !valid_account_key_signature) {
return res.status(401).send({ error: 'invalid signature' })
}

const revoked_at = Math.floor(Date.now() / 1000)
await db('account_keys')
.update({ revoked_at, revoke_signature: signature })
.where({ account, public_key })
.where({ account: linked_key.account, public_key })

res.status(200).send({
account,
account: linked_key.account,
public_key,
signature,
created_at: linked_key.created_at,
Expand Down
13 changes: 5 additions & 8 deletions cli/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ const is_test = process.env.NODE_ENV === 'test'
const base_url = is_test ? 'http://localhost:8080' : 'https://nano.community'

const load_private_key = async () => {
let private_key = process.env.NANO_PRIVATE_KEY
let private_key = process.env.NC_CLI_NANO_PRIVATE_KEY
if (private_key) {
console.log('Private key found in environment variable.')
} else {
console.log(
'No private key found in environment variable (NANO_PRIVATE_KEY).'
'No private key found in environment variable (NC_CLI_NANO_PRIVATE_KEY).'
)
// Restore stdin for inquirer
const answers = await inquirer.prompt([
Expand Down Expand Up @@ -98,8 +98,7 @@ const revoke_signing_key = {
type: 'string'
}),
handler: async ({ linked_public_key }) => {
const { private_key, public_key, nano_account_address } =
await load_private_key()
const { private_key, public_key } = await load_private_key()

// Confirm revocation
const answers = await inquirer.prompt([
Expand All @@ -115,13 +114,11 @@ const revoke_signing_key = {
console.log('Revoking signing key...')
const signature = sign_nano_community_revoke_key({
linked_public_key,
nano_account: nano_account_address,
nano_account_private_key: private_key,
nano_account_public_key: public_key
either_private_key: private_key,
either_public_key: public_key
})

const payload = {
account: nano_account_address,
public_key: linked_public_key.toString('hex'),
signature: signature.toString('hex')
}
Expand Down
25 changes: 8 additions & 17 deletions common/sign-nano-community-revoke-key.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,24 @@ import ed25519 from '@trashman/ed25519-blake2b'

export default function sign_nano_community_revoke_key({
linked_public_key,
nano_account,
nano_account_private_key,
nano_account_public_key
either_private_key,
either_public_key
}) {
if (!linked_public_key) {
throw new Error('linked_public_key is required')
}

if (!nano_account) {
throw new Error('nano_account is required')
if (!either_private_key) {
throw new Error('either_private_key is required')
}

if (!nano_account_private_key) {
throw new Error('nano_account_private_key is required')
if (!either_public_key) {
throw new Error('either_public_key is required')
}

if (!nano_account_public_key) {
throw new Error('nano_account_public_key is required')
}

const data = Buffer.from(['REVOKE', nano_account, linked_public_key])
const data = Buffer.from(['REVOKE', linked_public_key])

const message_hash = ed25519.hash(data)

return ed25519.sign(
message_hash,
nano_account_private_key,
nano_account_public_key
)
return ed25519.sign(message_hash, either_private_key, either_public_key)
}
15 changes: 5 additions & 10 deletions common/verify-nano-community-revoke-key-signature.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,23 @@ import ed25519 from '@trashman/ed25519-blake2b'

export default function verify_nano_community_revoke_key_signature({
linked_public_key,
nano_account,
nano_account_public_key,
either_public_key,
signature
}) {
if (!linked_public_key) {
throw new Error('linked_public_key is required')
}

if (!nano_account) {
throw new Error('nano_account is required')
}

if (!nano_account_public_key) {
throw new Error('nano_account_public_key is required')
if (!either_public_key) {
throw new Error('either_public_key is required')
}

if (!signature) {
throw new Error('signature is required')
}

const data = Buffer.from(['REVOKE', nano_account, linked_public_key])
const data = Buffer.from(['REVOKE', linked_public_key])

const message_hash = ed25519.hash(data)
return ed25519.verify(signature, message_hash, nano_account_public_key)
return ed25519.verify(signature, message_hash, either_public_key)
}
Loading

0 comments on commit e633e74

Please sign in to comment.