@micro-cms/crypto-auth-node 1.0.33 → 1.0.34
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.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var j=Object.create;var
|
|
1
|
+
"use strict";var j=Object.create;var f=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var V=(r,e)=>{for(var n in e)f(r,n,{get:e[n],enumerable:!0})},p=(r,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of E(e))!C.call(r,t)&&t!==n&&f(r,t,{get:()=>e[t],enumerable:!(o=M(e,t))||o.enumerable});return r};var y=(r,e,n)=>(n=r!=null?j(x(r)):{},p(e||!r||!r.__esModule?f(n,"default",{value:r,enumerable:!0}):n,r)),k=r=>p(f({},"__esModule",{value:!0}),r);var b={};V(b,{default:()=>P});module.exports=k(b);var m=y(require("bs58")),v=require("viem"),w=y(require("jsonwebtoken")),d=class{constructor(e){this.options=e;this.nonces=new Map}generateNonce(e){let n=Math.floor(Math.random()*1e6).toString();return this.nonces.set(e,n),n}async verifySolana(e,n){let o=this.nonces.get(e);if(!o)return console.warn("[@micro-cms/crypto-auth-node] No nonce found for address:",e),null;try{let t=new TextEncoder().encode(`Sign this message to authenticate: ${o}`),s=m.default.decode(n),i=m.default.decode(e);if(await this.verifySolanaSignature(t,s,i))return this.nonces.delete(e),this.issueToken(e,"solana")}catch(t){console.error("Solana verification error:",t)}return null}async verifySolanaSignature(e,n,o){try{let t=await import("tweetnacl"),s=t.sign||t.default?.sign;if(!s||!s.detached)throw new Error("tweetnacl sign.detached not found");return s.detached.verify(e,n,o)}catch(t){return console.error("[@micro-cms/crypto-auth-node] Internal verification error:",t.message),!1}}async verifyEVM(e,n){let o=e.toLowerCase(),t=this.nonces.get(o);if(!t)return console.warn("[@micro-cms/crypto-auth-node] No nonce found for EVM address:",o),null;try{let s=`Sign this message to authenticate: ${t}`;if(await(0,v.verifyMessage)({address:e,message:s,signature:n}))return this.nonces.delete(o),this.issueToken(e,"evm")}catch(s){console.error("EVM verification error:",s)}return null}issueToken(e,n){let o={expiresIn:this.options.jwtExpiresIn||"24h"};return w.default.sign({address:e,network:n},this.options.jwtSecret,o)}};var P={manifest:{name:"@micro-cms/crypto-auth-node",version:"1.0.0",provides:["authentication","route-provider"],requires:[]},async load(r){let{jwtSecret:e,jwtExpiresIn:n,onVerified:o}=r.config;e||console.warn("[@micro-cms/crypto-auth-node] jwtSecret not provided in config.");let t=new d({jwtSecret:e||"fallback-secret",jwtExpiresIn:n});r.runtime.register("authentication",{verifySolana:(i,a)=>t.verifySolana(i,a),verifyEVM:(i,a)=>t.verifyEVM(i,a),generateNonce:i=>t.generateNonce(i)});let s=[{method:"POST",path:"/api/auth/crypto/nonce",handler:async(i,a)=>{let{address:c}=i.body;if(!c)return a.status(400).json({error:"Address required"});let u=t.generateNonce(c);a.json({nonce:u})}},{method:"POST",path:"/api/auth/crypto/verify",handler:async(i,a)=>{let{address:c,signature:u,network:g}=i.body;if(!c||!u||!g)return a.status(400).json({error:"Address, signature and network required"});let l=null;if(g==="solana"?l=await t.verifySolana(c,u):l=await t.verifyEVM(c,u),l){let h=null;if(o)try{h=await o({address:c,network:g,token:l,req:i})}catch(S){console.error("[@micro-cms/crypto-auth-node] onVerified hook failed:",S.message)}a.json({token:l,user:h})}else a.status(401).json({error:"Verification failed"})}}];r.runtime.register("route-provider",{getRoutes:()=>s})}};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/auth.service.ts"],"sourcesContent":["import { CmsContext, CmsModule, RouteProvider, RouteDefinition } from '@micro-cms/types';\nimport { CryptoAuthService } from './auth.service';\n\nexport default {\n manifest: {\n name: '@micro-cms/crypto-auth-node',\n version: '1.0.0',\n provides: ['authentication', 'route-provider'],\n requires: []\n },\n\n async load(context: CmsContext) {\n const { jwtSecret, jwtExpiresIn, onVerified } = context.config;\n \n if (!jwtSecret) {\n console.warn('[@micro-cms/crypto-auth-node] jwtSecret not provided in config.');\n }\n\n const authService = new CryptoAuthService({ \n jwtSecret: jwtSecret || 'fallback-secret',\n jwtExpiresIn \n });\n\n context.runtime.register('authentication', {\n verifySolana: (address: string, signature: string) => authService.verifySolana(address, signature),\n verifyEVM: (address: string, signature: string) => authService.verifyEVM(address, signature),\n generateNonce: (address: string) => authService.generateNonce(address)\n });\n\n const routes: RouteDefinition[] = [\n {\n method: 'POST',\n path: '/api/auth/crypto/nonce',\n handler: async (req: any, res: any) => {\n const { address } = req.body;\n if (!address) return res.status(400).json({ error: 'Address required' });\n const nonce = authService.generateNonce(address);\n res.json({ nonce });\n }\n },\n {\n method: 'POST',\n path: '/api/auth/crypto/verify',\n handler: async (req: any, res: any) => {\n const { address, signature, network } = req.body;\n if (!address || !signature || !network) {\n return res.status(400).json({ error: 'Address, signature and network required' });\n }\n\n let token: string | null = null;\n if (network === 'solana') {\n token = await authService.verifySolana(address, signature);\n } else {\n token = await authService.verifyEVM(address, signature);\n }\n\n if (token) {\n // Optional hook to provision user in DB\n let user = null;\n if (onVerified) {\n try {\n user = await onVerified({ address, network, token, req });\n } catch (e: any) {\n console.error('[@micro-cms/crypto-auth-node] onVerified hook failed:', e.message);\n }\n }\n res.json({ token, user });\n } else {\n res.status(401).json({ error: 'Verification failed' });\n }\n }\n }\n ];\n\n context.runtime.register('route-provider', {\n getRoutes: () => routes\n } as RouteProvider);\n }\n} as CmsModule;\n","import { PublicKey } from '@solana/web3.js';\nimport bs58 from 'bs58';\nimport { verifyMessage } from 'viem';\nimport jwt from 'jsonwebtoken';\n\nexport interface CryptoAuthOptions {\n jwtSecret: string;\n jwtExpiresIn?: string;\n}\n\nexport class CryptoAuthService {\n private nonces = new Map<string, string>();\n\n constructor(private options: CryptoAuthOptions) {}\n\n generateNonce(address: string): string {\n const nonce = Math.floor(Math.random() * 1000000).toString();\n this.nonces.set(address
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/auth.service.ts"],"sourcesContent":["import { CmsContext, CmsModule, RouteProvider, RouteDefinition } from '@micro-cms/types';\nimport { CryptoAuthService } from './auth.service';\n\nexport default {\n manifest: {\n name: '@micro-cms/crypto-auth-node',\n version: '1.0.0',\n provides: ['authentication', 'route-provider'],\n requires: []\n },\n\n async load(context: CmsContext) {\n const { jwtSecret, jwtExpiresIn, onVerified } = context.config;\n \n if (!jwtSecret) {\n console.warn('[@micro-cms/crypto-auth-node] jwtSecret not provided in config.');\n }\n\n const authService = new CryptoAuthService({ \n jwtSecret: jwtSecret || 'fallback-secret',\n jwtExpiresIn \n });\n\n context.runtime.register('authentication', {\n verifySolana: (address: string, signature: string) => authService.verifySolana(address, signature),\n verifyEVM: (address: string, signature: string) => authService.verifyEVM(address, signature),\n generateNonce: (address: string) => authService.generateNonce(address)\n });\n\n const routes: RouteDefinition[] = [\n {\n method: 'POST',\n path: '/api/auth/crypto/nonce',\n handler: async (req: any, res: any) => {\n const { address } = req.body;\n if (!address) return res.status(400).json({ error: 'Address required' });\n const nonce = authService.generateNonce(address);\n res.json({ nonce });\n }\n },\n {\n method: 'POST',\n path: '/api/auth/crypto/verify',\n handler: async (req: any, res: any) => {\n const { address, signature, network } = req.body;\n if (!address || !signature || !network) {\n return res.status(400).json({ error: 'Address, signature and network required' });\n }\n\n let token: string | null = null;\n if (network === 'solana') {\n token = await authService.verifySolana(address, signature);\n } else {\n token = await authService.verifyEVM(address, signature);\n }\n\n if (token) {\n // Optional hook to provision user in DB\n let user = null;\n if (onVerified) {\n try {\n user = await onVerified({ address, network, token, req });\n } catch (e: any) {\n console.error('[@micro-cms/crypto-auth-node] onVerified hook failed:', e.message);\n }\n }\n res.json({ token, user });\n } else {\n res.status(401).json({ error: 'Verification failed' });\n }\n }\n }\n ];\n\n context.runtime.register('route-provider', {\n getRoutes: () => routes\n } as RouteProvider);\n }\n} as CmsModule;\n","import { PublicKey } from '@solana/web3.js';\nimport bs58 from 'bs58';\nimport { verifyMessage } from 'viem';\nimport jwt from 'jsonwebtoken';\n\nexport interface CryptoAuthOptions {\n jwtSecret: string;\n jwtExpiresIn?: string;\n}\n\nexport class CryptoAuthService {\n private nonces = new Map<string, string>();\n\n constructor(private options: CryptoAuthOptions) {}\n\n generateNonce(address: string): string {\n const nonce = Math.floor(Math.random() * 1000000).toString();\n // Use raw address for map key to handle case-sensitive Solana addresses\n this.nonces.set(address, nonce);\n return nonce;\n }\n\n async verifySolana(address: string, signature: string): Promise<string | null> {\n const nonce = this.nonces.get(address);\n if (!nonce) {\n console.warn('[@micro-cms/crypto-auth-node] No nonce found for address:', address);\n return null;\n }\n\n try {\n const message = new TextEncoder().encode(`Sign this message to authenticate: ${nonce}`);\n const signatureUint8 = bs58.decode(signature);\n const publicKeyUint8 = bs58.decode(address);\n \n const verified = await this.verifySolanaSignature(message, signatureUint8, publicKeyUint8);\n \n if (verified) {\n this.nonces.delete(address);\n return this.issueToken(address, 'solana');\n }\n } catch (e) {\n console.error('Solana verification error:', e);\n }\n return null;\n }\n\n private async verifySolanaSignature(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): Promise<boolean> {\n try {\n const nacl = await import('tweetnacl');\n // Handle both ES module and CommonJS styles\n const sign = nacl.sign || (nacl as any).default?.sign;\n \n if (!sign || !sign.detached) {\n throw new Error('tweetnacl sign.detached not found');\n }\n \n return sign.detached.verify(message, signature, publicKey);\n } catch (e: any) {\n console.error('[@micro-cms/crypto-auth-node] Internal verification error:', e.message);\n return false;\n }\n }\n\n async verifyEVM(address: string, signature: string): Promise<string | null> {\n const addrKey = address.toLowerCase();\n const nonce = this.nonces.get(addrKey);\n if (!nonce) {\n console.warn('[@micro-cms/crypto-auth-node] No nonce found for EVM address:', addrKey);\n return null;\n }\n\n try {\n const message = `Sign this message to authenticate: ${nonce}`;\n const verified = await verifyMessage({\n address: address as `0x${string}`,\n message,\n signature: signature as `0x${string}`,\n });\n\n if (verified) {\n this.nonces.delete(addrKey);\n return this.issueToken(address, 'evm');\n }\n } catch (e) {\n console.error('EVM verification error:', e);\n }\n return null;\n }\n\n private issueToken(address: string, network: string): string {\n const options: any = { \n expiresIn: this.options.jwtExpiresIn || '24h' \n };\n return jwt.sign(\n { address, network },\n this.options.jwtSecret,\n options\n );\n }\n}\n"],"mappings":"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","names":["index_exports","__export","index_default","__toCommonJS","import_bs58","import_viem","import_jsonwebtoken","CryptoAuthService","options","address","nonce","signature","message","signatureUint8","bs58","publicKeyUint8","e","publicKey","nacl","sign","addrKey","network","jwt","index_default","context","jwtSecret","jwtExpiresIn","onVerified","authService","CryptoAuthService","address","signature","routes","req","res","nonce","network","token","user","e"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import y from"bs58";import{verifyMessage as h}from"viem";import p from"jsonwebtoken";var f=class{constructor(e){this.options=e;this.nonces=new Map}generateNonce(e){let o=Math.floor(Math.random()*1e6).toString();return this.nonces.set(e,o),o}async verifySolana(e,o){let n=this.nonces.get(e);if(!n)return console.warn("[@micro-cms/crypto-auth-node] No nonce found for address:",e),null;try{let t=new TextEncoder().encode(`Sign this message to authenticate: ${n}`),i=y.decode(o),r=y.decode(e);if(await this.verifySolanaSignature(t,i,r))return this.nonces.delete(e),this.issueToken(e,"solana")}catch(t){console.error("Solana verification error:",t)}return null}async verifySolanaSignature(e,o,n){try{let t=await import("tweetnacl"),i=t.sign||t.default?.sign;if(!i||!i.detached)throw new Error("tweetnacl sign.detached not found");return i.detached.verify(e,o,n)}catch(t){return console.error("[@micro-cms/crypto-auth-node] Internal verification error:",t.message),!1}}async verifyEVM(e,o){let n=e.toLowerCase(),t=this.nonces.get(n);if(!t)return console.warn("[@micro-cms/crypto-auth-node] No nonce found for EVM address:",n),null;try{let i=`Sign this message to authenticate: ${t}`;if(await h({address:e,message:i,signature:o}))return this.nonces.delete(n),this.issueToken(e,"evm")}catch(i){console.error("EVM verification error:",i)}return null}issueToken(e,o){let n={expiresIn:this.options.jwtExpiresIn||"24h"};return p.sign({address:e,network:o},this.options.jwtSecret,n)}};var E={manifest:{name:"@micro-cms/crypto-auth-node",version:"1.0.0",provides:["authentication","route-provider"],requires:[]},async load(l){let{jwtSecret:e,jwtExpiresIn:o,onVerified:n}=l.config;e||console.warn("[@micro-cms/crypto-auth-node] jwtSecret not provided in config.");let t=new f({jwtSecret:e||"fallback-secret",jwtExpiresIn:o});l.runtime.register("authentication",{verifySolana:(r,s)=>t.verifySolana(r,s),verifyEVM:(r,s)=>t.verifyEVM(r,s),generateNonce:r=>t.generateNonce(r)});let i=[{method:"POST",path:"/api/auth/crypto/nonce",handler:async(r,s)=>{let{address:a}=r.body;if(!a)return s.status(400).json({error:"Address required"});let c=t.generateNonce(a);s.json({nonce:c})}},{method:"POST",path:"/api/auth/crypto/verify",handler:async(r,s)=>{let{address:a,signature:c,network:d}=r.body;if(!a||!c||!d)return s.status(400).json({error:"Address, signature and network required"});let u=null;if(d==="solana"?u=await t.verifySolana(a,c):u=await t.verifyEVM(a,c),u){let g=null;if(n)try{g=await n({address:a,network:d,token:u,req:r})}catch(m){console.error("[@micro-cms/crypto-auth-node] onVerified hook failed:",m.message)}s.json({token:u,user:g})}else s.status(401).json({error:"Verification failed"})}}];l.runtime.register("route-provider",{getRoutes:()=>i})}};export{E as default};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth.service.ts","../src/index.ts"],"sourcesContent":["import { PublicKey } from '@solana/web3.js';\nimport bs58 from 'bs58';\nimport { verifyMessage } from 'viem';\nimport jwt from 'jsonwebtoken';\n\nexport interface CryptoAuthOptions {\n jwtSecret: string;\n jwtExpiresIn?: string;\n}\n\nexport class CryptoAuthService {\n private nonces = new Map<string, string>();\n\n constructor(private options: CryptoAuthOptions) {}\n\n generateNonce(address: string): string {\n const nonce = Math.floor(Math.random() * 1000000).toString();\n this.nonces.set(address
|
|
1
|
+
{"version":3,"sources":["../src/auth.service.ts","../src/index.ts"],"sourcesContent":["import { PublicKey } from '@solana/web3.js';\nimport bs58 from 'bs58';\nimport { verifyMessage } from 'viem';\nimport jwt from 'jsonwebtoken';\n\nexport interface CryptoAuthOptions {\n jwtSecret: string;\n jwtExpiresIn?: string;\n}\n\nexport class CryptoAuthService {\n private nonces = new Map<string, string>();\n\n constructor(private options: CryptoAuthOptions) {}\n\n generateNonce(address: string): string {\n const nonce = Math.floor(Math.random() * 1000000).toString();\n // Use raw address for map key to handle case-sensitive Solana addresses\n this.nonces.set(address, nonce);\n return nonce;\n }\n\n async verifySolana(address: string, signature: string): Promise<string | null> {\n const nonce = this.nonces.get(address);\n if (!nonce) {\n console.warn('[@micro-cms/crypto-auth-node] No nonce found for address:', address);\n return null;\n }\n\n try {\n const message = new TextEncoder().encode(`Sign this message to authenticate: ${nonce}`);\n const signatureUint8 = bs58.decode(signature);\n const publicKeyUint8 = bs58.decode(address);\n \n const verified = await this.verifySolanaSignature(message, signatureUint8, publicKeyUint8);\n \n if (verified) {\n this.nonces.delete(address);\n return this.issueToken(address, 'solana');\n }\n } catch (e) {\n console.error('Solana verification error:', e);\n }\n return null;\n }\n\n private async verifySolanaSignature(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): Promise<boolean> {\n try {\n const nacl = await import('tweetnacl');\n // Handle both ES module and CommonJS styles\n const sign = nacl.sign || (nacl as any).default?.sign;\n \n if (!sign || !sign.detached) {\n throw new Error('tweetnacl sign.detached not found');\n }\n \n return sign.detached.verify(message, signature, publicKey);\n } catch (e: any) {\n console.error('[@micro-cms/crypto-auth-node] Internal verification error:', e.message);\n return false;\n }\n }\n\n async verifyEVM(address: string, signature: string): Promise<string | null> {\n const addrKey = address.toLowerCase();\n const nonce = this.nonces.get(addrKey);\n if (!nonce) {\n console.warn('[@micro-cms/crypto-auth-node] No nonce found for EVM address:', addrKey);\n return null;\n }\n\n try {\n const message = `Sign this message to authenticate: ${nonce}`;\n const verified = await verifyMessage({\n address: address as `0x${string}`,\n message,\n signature: signature as `0x${string}`,\n });\n\n if (verified) {\n this.nonces.delete(addrKey);\n return this.issueToken(address, 'evm');\n }\n } catch (e) {\n console.error('EVM verification error:', e);\n }\n return null;\n }\n\n private issueToken(address: string, network: string): string {\n const options: any = { \n expiresIn: this.options.jwtExpiresIn || '24h' \n };\n return jwt.sign(\n { address, network },\n this.options.jwtSecret,\n options\n );\n }\n}\n","import { CmsContext, CmsModule, RouteProvider, RouteDefinition } from '@micro-cms/types';\nimport { CryptoAuthService } from './auth.service';\n\nexport default {\n manifest: {\n name: '@micro-cms/crypto-auth-node',\n version: '1.0.0',\n provides: ['authentication', 'route-provider'],\n requires: []\n },\n\n async load(context: CmsContext) {\n const { jwtSecret, jwtExpiresIn, onVerified } = context.config;\n \n if (!jwtSecret) {\n console.warn('[@micro-cms/crypto-auth-node] jwtSecret not provided in config.');\n }\n\n const authService = new CryptoAuthService({ \n jwtSecret: jwtSecret || 'fallback-secret',\n jwtExpiresIn \n });\n\n context.runtime.register('authentication', {\n verifySolana: (address: string, signature: string) => authService.verifySolana(address, signature),\n verifyEVM: (address: string, signature: string) => authService.verifyEVM(address, signature),\n generateNonce: (address: string) => authService.generateNonce(address)\n });\n\n const routes: RouteDefinition[] = [\n {\n method: 'POST',\n path: '/api/auth/crypto/nonce',\n handler: async (req: any, res: any) => {\n const { address } = req.body;\n if (!address) return res.status(400).json({ error: 'Address required' });\n const nonce = authService.generateNonce(address);\n res.json({ nonce });\n }\n },\n {\n method: 'POST',\n path: '/api/auth/crypto/verify',\n handler: async (req: any, res: any) => {\n const { address, signature, network } = req.body;\n if (!address || !signature || !network) {\n return res.status(400).json({ error: 'Address, signature and network required' });\n }\n\n let token: string | null = null;\n if (network === 'solana') {\n token = await authService.verifySolana(address, signature);\n } else {\n token = await authService.verifyEVM(address, signature);\n }\n\n if (token) {\n // Optional hook to provision user in DB\n let user = null;\n if (onVerified) {\n try {\n user = await onVerified({ address, network, token, req });\n } catch (e: any) {\n console.error('[@micro-cms/crypto-auth-node] onVerified hook failed:', e.message);\n }\n }\n res.json({ token, user });\n } else {\n res.status(401).json({ error: 'Verification failed' });\n }\n }\n }\n ];\n\n context.runtime.register('route-provider', {\n getRoutes: () => routes\n } as RouteProvider);\n }\n} as CmsModule;\n"],"mappings":"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","names":["bs58","verifyMessage","jwt","CryptoAuthService","options","address","nonce","signature","message","signatureUint8","publicKeyUint8","e","publicKey","nacl","sign","addrKey","network","index_default","context","jwtSecret","jwtExpiresIn","onVerified","authService","CryptoAuthService","address","signature","routes","req","res","nonce","network","token","user","e"]}
|