All files / src/server/auth createJws.ts

0% Statements 0/18
0% Branches 0/1
0% Functions 0/6
0% Lines 0/18

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82                                                                                                                                                                   
import nacl from 'tweetnacl'
import asn from 'asn1.js'
import * as jose from 'jose'
 
//TODO: support other types of key
//https://github.com/hashgraph/hedera-sdk-js/blob/e0cd39c84ab189d59a6bcedcf16e4102d7bb8beb/packages/cryptography/src/Ed25519PrivateKey.js
 
/*
 * create KeyObject
 *  - https://github.com/panva/paseto/issues/8#issuecomment-633647614
 *  - https://github.com/panva/jose/blob/main/docs/types/types.KeyLike.md
 *  - https://nodejs.org/api/crypto.html#class-keyobject
 */
 
//https://github.com/hashgraph/hedera-sdk-js/blob/develop/packages/cryptography/src/Ed25519PrivateKey.js
//https://github.com/hashgraph/hedera-sdk-js/blob/develop/packages/cryptography/src/Ed25519PublicKey.js
async function createPrivateKey(cryptoAccountPrivateKey: string) {
  Iif (globalThis.crypto)
    throw new Error('Not supported in a browser environment')
 
  const crypto = await import('node:crypto')
 
  // asn
  const OneAsymmetricKey = asn.define('OneAsymmetricKey', function () {
    this.seq().obj(
      this.key('version').int(),
      this.key('algorithm').use(
        asn.define('AlgorithmIdentifier', function () {
          this.seq().obj(this.key('algorithm').objid())
        })
      ),
      this.key('privateKey').use(
        asn.define('PrivateKey', function () {
          this.octstr().contains().obj(this.key('privateKey').octstr())
        })
      )
    )
  })
 
  //https://github.com/hashgraph/hedera-sdk-js/blob/e0cd39c84ab189d59a6bcedcf16e4102d7bb8beb/packages/cryptography/src/Ed25519PrivateKey.js#L108
  const keyPair = nacl.sign.keyPair.fromSeed(
    Buffer.from(cryptoAccountPrivateKey, 'hex').subarray(16)
  )
 
  const keyData = OneAsymmetricKey.encode(
    {
      version: 0,
      privateKey: {privateKey: Buffer.from(keyPair.secretKey.slice(0, 32))},
      algorithm: {algorithm: '1.3.101.112'.split('.')},
    },
    'der'
  )
  keyData.write('04', 12, 1, 'hex')
 
  return crypto.createPrivateKey({
    key: keyData,
    format: 'der',
    type: 'pkcs8',
  })
}
 
export default async function createJws(
  cryptoAccountPrivateKey: string,
  cryptoAccountPublicKey: string,
  options: {
    issuer: string // account id
    claims: Record<string, unknown> // https://tools.ietf.org/html/rfc7519#section-4.1
    audience: string // https://tools.ietf.org/html/rfc7519#section-4.1.3
    expirationTime: string // https://tools.ietf.org/html/rfc7519#section-4.1.4
  }
) {
  const keyLike = await createPrivateKey(cryptoAccountPrivateKey)
  const {claims, issuer, audience, expirationTime} = options
 
  return await new jose.SignJWT(claims)
    .setProtectedHeader({alg: 'EdDSA', kid: cryptoAccountPublicKey})
    .setIssuer(issuer)
    .setAudience(audience)
    .setExpirationTime(expirationTime)
    .sign(keyLike)
}