Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@keystonehq/base-eth-keyring

Package Overview
Dependencies
Maintainers
4
Versions
63
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@keystonehq/base-eth-keyring - npm Package Compare versions

Comparing version 0.7.1-alpha.0 to 0.7.1

25

dist/base-eth-keyring.cjs.development.js

@@ -8,3 +8,4 @@ 'use strict';

var HDKey = _interopDefault(require('hdkey'));
var ethereumjsUtil = require('ethereumjs-util');
var util = require('@ethereumjs/util');
var rlp = _interopDefault(require('rlp'));
var tx = require('@ethereumjs/tx');

@@ -127,3 +128,3 @@ var bcUrRegistryEth = require('@keystonehq/bc-ur-registry-eth');

const path = `M/${cryptoHDKey.getOrigin().getPath()}`;
const address = "0x" + ethereumjsUtil.publicToAddress(key, true).toString("hex");
const address = "0x" + util.publicToAddress(key, true).toString("hex");
this.name = cryptoHDKey.getName();

@@ -135,7 +136,7 @@

if (this.paths[ethereumjsUtil.toChecksumAddress(address)] === undefined) {
if (this.paths[util.toChecksumAddress(address)] === undefined) {
changed = true;
}
this.paths[ethereumjsUtil.toChecksumAddress(address)] = path;
this.paths[util.toChecksumAddress(address)] = path;
}

@@ -186,3 +187,3 @@ } catch (e) {

});
this.indexes[ethereumjsUtil.toChecksumAddress(address)] = i;
this.indexes[util.toChecksumAddress(address)] = i;
}

@@ -223,4 +224,4 @@

const dkey = this.hdk.derive(`${pb}/${childrenPath}`);
const address = "0x" + ethereumjsUtil.publicToAddress(dkey.publicKey, true).toString("hex");
return ethereumjsUtil.toChecksumAddress(address);
const address = "0x" + util.publicToAddress(dkey.publicKey, true).toString("hex");
return util.toChecksumAddress(address);
} else {

@@ -230,3 +231,3 @@ const result = Object.keys(this.paths)[i];

if (result) {
return ethereumjsUtil.toChecksumAddress(result);
return util.toChecksumAddress(result);
} else {

@@ -397,3 +398,3 @@ throw new Error(`KeystoneError#pubkey_account.no_expected_account`);

if (tx$1.type === 0) {
messageToSign = ethereumjsUtil.rlp.encode(tx$1.getMessageToSign(false));
messageToSign = Buffer.from(rlp.encode(tx$1.getMessageToSign(false)));
} else {

@@ -427,3 +428,3 @@ messageToSign = tx$1.getMessageToSign(false);

async signPersonalMessage(withAccount, messageHex) {
const usignedHex = ethereumjsUtil.stripHexPrefix(messageHex);
const usignedHex = util.stripHexPrefix(messageHex);
const hdPath = await this._pathFromAddress(withAccount);

@@ -454,3 +455,3 @@ const requestId = uuid.v4();

if (this.keyringMode === KEYRING_MODE.hd) {
const checksummedAddress = ethereumjsUtil.toChecksumAddress(address);
const checksummedAddress = util.toChecksumAddress(address);
let index = this.indexes[checksummedAddress];

@@ -473,3 +474,3 @@

} else {
const checksummedAddress = ethereumjsUtil.toChecksumAddress(address);
const checksummedAddress = util.toChecksumAddress(address);
const path = this.paths[checksummedAddress];

@@ -476,0 +477,0 @@

@@ -1,2 +0,2 @@

"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t,r,i=(e=require("hdkey"))&&"object"==typeof e&&"default"in e?e.default:e,s=require("ethereumjs-util"),n=require("@ethereumjs/tx"),a=require("@keystonehq/bc-ur-registry-eth"),o=require("uuid");!function(e){e.hd="hd",e.pubkey="pubkey"}(t||(t={})),function(e){e.standard="account.standard",e.ledger_live="account.ledger_live",e.ledger_legacy="account.ledger_legacy"}(r||(r={}));class h{constructor(e){this.version=1,this.getInteraction=()=>{throw new Error("KeystoneError#invalid_extends: method getInteraction not implemented, please extend BaseKeyring by overwriting this method.")},this.type="QR Hardware Wallet Device",this.requestSignature=async(e,t,r,i)=>{const s=await this.getInteraction().requestSignature(t,r,i),n=s.getRequestId(),a=s.getSignature();if(n&&o.stringify(n)!==e)throw new Error("KeystoneError#invalid_data: read signature error: mismatched requestId");return{r:a.slice(0,32),s:a.slice(32,64),v:a.slice(64)}},this.__readCryptoHDKey=e=>{var t,i;const s="m/"+e.getOrigin().getPath(),n=null==(t=e.getOrigin().getSourceFingerprint())?void 0:t.toString("hex"),a=(null==(i=e.getChildren())?void 0:i.getPath())||"0/*",o=e.getName();if(e.getNote()===r.standard?this.keyringAccount=r.standard:e.getNote()===r.ledger_legacy&&(this.keyringAccount=r.ledger_legacy),!n)throw new Error("KeystoneError#invalid_data: invalid crypto-hdkey, cannot get source fingerprint");const h=e.getBip32Key();this.xfp=n,this.xpub=h,this.hdPath=s,this.childrenPath=a,void 0!==o&&""!==o&&(this.name=o),this.initialized=!0},this.__readCryptoAccount=e=>{var t,i;const n=null==(t=e.getMasterFingerprint())?void 0:t.toString("hex");if(!n)throw new Error("KeystoneError#invalid_data: invalid crypto-account, cannot get master fingerprint");this.xfp=n,this.initialized=!0;let a=!1;const o=e.getOutputDescriptors();if(!o||0===o.length)throw new Error("KeystoneError#invalid_data: invalid crypto-account, no crypto output found");if(o.length%5!=0)throw new Error("KeystoneError#invalid_data: only support 5x pubkey accounts for now");return null==(i=e.getOutputDescriptors())||i.forEach(e=>{try{const t=e.getHDKey();if(t){const e=t.getKey(),i="M/"+t.getOrigin().getPath(),n="0x"+s.publicToAddress(e,!0).toString("hex");this.name=t.getName(),t.getNote()===r.ledger_live&&(this.keyringAccount=r.ledger_live),void 0===this.paths[s.toChecksumAddress(n)]&&(a=!0),this.paths[s.toChecksumAddress(n)]=i}}catch(e){throw new Error("KeystoneError#invalid_data: "+e)}}),a},this.getName=()=>this.name,this.setAccountToUnlock=e=>{this.unlockedAccount=parseInt(e,10)},this.__getNormalPage=async e=>{this.page+=e,this.page<=0&&(this.page=1);const t=(this.page-1)*this.perPage,r=t+this.perPage,i=[];for(let e=t;e<r;e++){const t=await this.__addressFromIndex("m",e);i.push({address:t,balance:null,index:e}),this.indexes[s.toChecksumAddress(t)]=e}return i},this.__getLedgerLivePage=async e=>{const t=(this.page+e-1)*this.perPage,r=t+this.perPage,i=[];for(let e=t;e<r;e++){const t=await this.__addressFromIndex("m",e);i.push({address:t,balance:null,index:e})}return this.page+=e,i},this.__addressFromIndex=async(e,r)=>{if(this.keyringMode===t.hd){this.checkKeyring(),this.hdk||(this.hdk=i.fromExtendedKey(this.xpub));const t=this.childrenPath.replace("*",String(r)).replace(/\*/g,"0"),n=this.hdk.derive(`${e}/${t}`),a="0x"+s.publicToAddress(n.publicKey,!0).toString("hex");return s.toChecksumAddress(a)}{const e=Object.keys(this.paths)[r];if(e)return s.toChecksumAddress(e);throw new Error("KeystoneError#pubkey_account.no_expected_account")}},this.page=0,this.perPage=5,this.accounts=[],this.currentAccount=0,this.unlockedAccount=0,this.name="QR Hardware",this.keyringMode=t.hd,this.keyringAccount=r.standard,this.initialized=!1,this.xfp="",this.xpub="",this.hdPath="",this.childrenPath="0/*",this.indexes={},this.paths={},this.deserialize(e)}async readKeyring(){const e=await this.getInteraction().readCryptoHDKeyOrCryptoAccount();this.syncKeyring(e)}syncKeyring(e){e.getRegistryType().getType()===a.extend.RegistryTypes.CRYPTO_HDKEY.getType()?(this.keyringMode=t.hd,this.__readCryptoHDKey(e)):(this.keyringMode=t.pubkey,this.__readCryptoAccount(e))}checkKeyring(){if(!this.xfp||!this.xpub||!this.hdPath)throw new Error("KeystoneError#invalid_keyring: keyring not fulfilled, please call function `readKeyring` firstly")}serialize(){return Promise.resolve({initialized:this.initialized,accounts:this.accounts,currentAccount:this.currentAccount,page:this.page,perPage:this.perPage,keyringAccount:this.keyringAccount,keyringMode:this.keyringMode,name:this.name,version:this.version,xfp:this.xfp,xpub:this.xpub,hdPath:this.hdPath,childrenPath:this.childrenPath,indexes:this.indexes,paths:this.paths})}deserialize(e){e&&(this.accounts=e.accounts,this.currentAccount=e.currentAccount,this.page=e.page,this.perPage=e.perPage,this.name=e.name,this.initialized=e.initialized,this.keyringMode=e.keyringMode||t.hd,this.keyringAccount=e.keyringAccount||r.standard,this.xfp=e.xfp,this.xpub=e.xpub,this.hdPath=e.hdPath,this.indexes=e.indexes,this.paths=e.paths,this.childrenPath=e.childrenPath||"0/*")}setCurrentAccount(e){this.currentAccount=e}getCurrentAccount(){return this.currentAccount}getCurrentAddress(){return this.accounts[this.currentAccount]}async addAccounts(e=1){const t=this.unlockedAccount,r=t+e,i=[];for(let e=t;e<r;e++){const t=await this.__addressFromIndex("m",e);i.push(t),this.page=0,this.unlockedAccount++}return this.accounts=this.accounts.concat(i),this.accounts}getFirstPage(){return this.page=0,this.__getPage(1)}getNextPage(){return this.__getPage(1)}getPreviousPage(){return this.__getPage(-1)}async __getPage(e){return this.initialized||await this.readKeyring(),this.keyringMode===t.hd?this.__getNormalPage(e):this.__getLedgerLivePage(e)}getAccounts(){return Promise.resolve(this.accounts)}removeAccount(e){if(!this.accounts.map(e=>e.toLowerCase()).includes(e.toLowerCase()))throw new Error(`Address ${e} not found in this keyring`);this.accounts=this.accounts.filter(t=>t.toLowerCase()!==e.toLowerCase())}async signTransaction(e,t){const r=0===t.type?a.DataType.transaction:a.DataType.typedTransaction;let i;i=0===t.type?s.rlp.encode(t.getMessageToSign(!1)):t.getMessageToSign(!1);const h=await this._pathFromAddress(e),c=t.common.chainId(),d=o.v4(),u=a.EthSignRequest.constructETHRequest(i,r,h,this.xfp,d,c),{r:g,s:y,v:p}=await this.requestSignature(d,u,"Scan with your Keystone",'After your Keystone has signed the transaction, click on "Scan Keystone" to receive the signature');return n.TransactionFactory.fromTxData({...t.toJSON(),type:t.type,r:g,s:y,v:p},{common:t.common})}signMessage(e,t){return this.signPersonalMessage(e,t)}async signPersonalMessage(e,t){const r=s.stripHexPrefix(t),i=await this._pathFromAddress(e),n=o.v4(),h=a.EthSignRequest.constructETHRequest(Buffer.from(r,"hex"),a.DataType.personalMessage,i,this.xfp,n,void 0,e),{r:c,s:d,v:u}=await this.requestSignature(n,h,"Scan with your Keystone",'After your Keystone has signed this message, click on "Scan Keystone" to receive the signature');return"0x"+Buffer.concat([c,d,u]).toString("hex")}async signTypedData(e,t){const r=await this._pathFromAddress(e),i=o.v4(),s=a.EthSignRequest.constructETHRequest(Buffer.from(JSON.stringify(t),"utf-8"),a.DataType.typedData,r,this.xfp,i,void 0,e),{r:n,s:h,v:c}=await this.requestSignature(i,s,"Scan with your Keystone",'After your Keystone has signed this data, click on "Scan Keystone" to receive the signature');return"0x"+Buffer.concat([n,h,c]).toString("hex")}async _pathFromAddress(e){if(this.keyringMode===t.hd){const t=s.toChecksumAddress(e);let r=this.indexes[t];if(void 0===r)for(let e=0;e<1e3;e++)if(t===await this.__addressFromIndex("m",e)){r=e;break}if(void 0===r)throw new Error("Unknown address");return`${this.hdPath}/${this.childrenPath.replace("*",r.toString()).replace(/\*/g,"0")}`}{const t=s.toChecksumAddress(e),r=this.paths[t];if(void 0===r)throw new Error("Unknown address");return r}}}h.type="QR Hardware Wallet Device",exports.BaseKeyring=h;
"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0});var t,r,i=e(require("hdkey")),s=require("@ethereumjs/util"),n=e(require("rlp")),a=require("@ethereumjs/tx"),o=require("@keystonehq/bc-ur-registry-eth"),h=require("uuid");!function(e){e.hd="hd",e.pubkey="pubkey"}(t||(t={})),function(e){e.standard="account.standard",e.ledger_live="account.ledger_live",e.ledger_legacy="account.ledger_legacy"}(r||(r={}));class c{constructor(e){this.version=1,this.getInteraction=()=>{throw new Error("KeystoneError#invalid_extends: method getInteraction not implemented, please extend BaseKeyring by overwriting this method.")},this.type="QR Hardware Wallet Device",this.requestSignature=async(e,t,r,i)=>{const s=await this.getInteraction().requestSignature(t,r,i),n=s.getRequestId(),a=s.getSignature();if(n&&h.stringify(n)!==e)throw new Error("KeystoneError#invalid_data: read signature error: mismatched requestId");return{r:a.slice(0,32),s:a.slice(32,64),v:a.slice(64)}},this.__readCryptoHDKey=e=>{var t,i;const s="m/"+e.getOrigin().getPath(),n=null==(t=e.getOrigin().getSourceFingerprint())?void 0:t.toString("hex"),a=(null==(i=e.getChildren())?void 0:i.getPath())||"0/*",o=e.getName();if(e.getNote()===r.standard?this.keyringAccount=r.standard:e.getNote()===r.ledger_legacy&&(this.keyringAccount=r.ledger_legacy),!n)throw new Error("KeystoneError#invalid_data: invalid crypto-hdkey, cannot get source fingerprint");const h=e.getBip32Key();this.xfp=n,this.xpub=h,this.hdPath=s,this.childrenPath=a,void 0!==o&&""!==o&&(this.name=o),this.initialized=!0},this.__readCryptoAccount=e=>{var t,i;const n=null==(t=e.getMasterFingerprint())?void 0:t.toString("hex");if(!n)throw new Error("KeystoneError#invalid_data: invalid crypto-account, cannot get master fingerprint");this.xfp=n,this.initialized=!0;let a=!1;const o=e.getOutputDescriptors();if(!o||0===o.length)throw new Error("KeystoneError#invalid_data: invalid crypto-account, no crypto output found");if(o.length%5!=0)throw new Error("KeystoneError#invalid_data: only support 5x pubkey accounts for now");return null==(i=e.getOutputDescriptors())||i.forEach(e=>{try{const t=e.getHDKey();if(t){const e=t.getKey(),i="M/"+t.getOrigin().getPath(),n="0x"+s.publicToAddress(e,!0).toString("hex");this.name=t.getName(),t.getNote()===r.ledger_live&&(this.keyringAccount=r.ledger_live),void 0===this.paths[s.toChecksumAddress(n)]&&(a=!0),this.paths[s.toChecksumAddress(n)]=i}}catch(e){throw new Error("KeystoneError#invalid_data: "+e)}}),a},this.getName=()=>this.name,this.setAccountToUnlock=e=>{this.unlockedAccount=parseInt(e,10)},this.__getNormalPage=async e=>{this.page+=e,this.page<=0&&(this.page=1);const t=(this.page-1)*this.perPage,r=t+this.perPage,i=[];for(let e=t;e<r;e++){const t=await this.__addressFromIndex("m",e);i.push({address:t,balance:null,index:e}),this.indexes[s.toChecksumAddress(t)]=e}return i},this.__getLedgerLivePage=async e=>{const t=(this.page+e-1)*this.perPage,r=t+this.perPage,i=[];for(let e=t;e<r;e++){const t=await this.__addressFromIndex("m",e);i.push({address:t,balance:null,index:e})}return this.page+=e,i},this.__addressFromIndex=async(e,r)=>{if(this.keyringMode===t.hd){this.checkKeyring(),this.hdk||(this.hdk=i.fromExtendedKey(this.xpub));const t=this.childrenPath.replace("*",String(r)).replace(/\*/g,"0"),n=this.hdk.derive(`${e}/${t}`),a="0x"+s.publicToAddress(n.publicKey,!0).toString("hex");return s.toChecksumAddress(a)}{const e=Object.keys(this.paths)[r];if(e)return s.toChecksumAddress(e);throw new Error("KeystoneError#pubkey_account.no_expected_account")}},this.page=0,this.perPage=5,this.accounts=[],this.currentAccount=0,this.unlockedAccount=0,this.name="QR Hardware",this.keyringMode=t.hd,this.keyringAccount=r.standard,this.initialized=!1,this.xfp="",this.xpub="",this.hdPath="",this.childrenPath="0/*",this.indexes={},this.paths={},this.deserialize(e)}async readKeyring(){const e=await this.getInteraction().readCryptoHDKeyOrCryptoAccount();this.syncKeyring(e)}syncKeyring(e){e.getRegistryType().getType()===o.extend.RegistryTypes.CRYPTO_HDKEY.getType()?(this.keyringMode=t.hd,this.__readCryptoHDKey(e)):(this.keyringMode=t.pubkey,this.__readCryptoAccount(e))}checkKeyring(){if(!this.xfp||!this.xpub||!this.hdPath)throw new Error("KeystoneError#invalid_keyring: keyring not fulfilled, please call function `readKeyring` firstly")}serialize(){return Promise.resolve({initialized:this.initialized,accounts:this.accounts,currentAccount:this.currentAccount,page:this.page,perPage:this.perPage,keyringAccount:this.keyringAccount,keyringMode:this.keyringMode,name:this.name,version:this.version,xfp:this.xfp,xpub:this.xpub,hdPath:this.hdPath,childrenPath:this.childrenPath,indexes:this.indexes,paths:this.paths})}deserialize(e){e&&(this.accounts=e.accounts,this.currentAccount=e.currentAccount,this.page=e.page,this.perPage=e.perPage,this.name=e.name,this.initialized=e.initialized,this.keyringMode=e.keyringMode||t.hd,this.keyringAccount=e.keyringAccount||r.standard,this.xfp=e.xfp,this.xpub=e.xpub,this.hdPath=e.hdPath,this.indexes=e.indexes,this.paths=e.paths,this.childrenPath=e.childrenPath||"0/*")}setCurrentAccount(e){this.currentAccount=e}getCurrentAccount(){return this.currentAccount}getCurrentAddress(){return this.accounts[this.currentAccount]}async addAccounts(e=1){const t=this.unlockedAccount,r=t+e,i=[];for(let e=t;e<r;e++){const t=await this.__addressFromIndex("m",e);i.push(t),this.page=0,this.unlockedAccount++}return this.accounts=this.accounts.concat(i),this.accounts}getFirstPage(){return this.page=0,this.__getPage(1)}getNextPage(){return this.__getPage(1)}getPreviousPage(){return this.__getPage(-1)}async __getPage(e){return this.initialized||await this.readKeyring(),this.keyringMode===t.hd?this.__getNormalPage(e):this.__getLedgerLivePage(e)}getAccounts(){return Promise.resolve(this.accounts)}removeAccount(e){if(!this.accounts.map(e=>e.toLowerCase()).includes(e.toLowerCase()))throw new Error(`Address ${e} not found in this keyring`);this.accounts=this.accounts.filter(t=>t.toLowerCase()!==e.toLowerCase())}async signTransaction(e,t){const r=0===t.type?o.DataType.transaction:o.DataType.typedTransaction;let i;i=0===t.type?Buffer.from(n.encode(t.getMessageToSign(!1))):t.getMessageToSign(!1);const s=await this._pathFromAddress(e),c=t.common.chainId(),d=h.v4(),u=o.EthSignRequest.constructETHRequest(i,r,s,this.xfp,d,c),{r:g,s:y,v:p}=await this.requestSignature(d,u,"Scan with your Keystone",'After your Keystone has signed the transaction, click on "Scan Keystone" to receive the signature');return a.TransactionFactory.fromTxData({...t.toJSON(),type:t.type,r:g,s:y,v:p},{common:t.common})}signMessage(e,t){return this.signPersonalMessage(e,t)}async signPersonalMessage(e,t){const r=s.stripHexPrefix(t),i=await this._pathFromAddress(e),n=h.v4(),a=o.EthSignRequest.constructETHRequest(Buffer.from(r,"hex"),o.DataType.personalMessage,i,this.xfp,n,void 0,e),{r:c,s:d,v:u}=await this.requestSignature(n,a,"Scan with your Keystone",'After your Keystone has signed this message, click on "Scan Keystone" to receive the signature');return"0x"+Buffer.concat([c,d,u]).toString("hex")}async signTypedData(e,t){const r=await this._pathFromAddress(e),i=h.v4(),s=o.EthSignRequest.constructETHRequest(Buffer.from(JSON.stringify(t),"utf-8"),o.DataType.typedData,r,this.xfp,i,void 0,e),{r:n,s:a,v:c}=await this.requestSignature(i,s,"Scan with your Keystone",'After your Keystone has signed this data, click on "Scan Keystone" to receive the signature');return"0x"+Buffer.concat([n,a,c]).toString("hex")}async _pathFromAddress(e){if(this.keyringMode===t.hd){const t=s.toChecksumAddress(e);let r=this.indexes[t];if(void 0===r)for(let e=0;e<1e3;e++)if(t===await this.__addressFromIndex("m",e)){r=e;break}if(void 0===r)throw new Error("Unknown address");return`${this.hdPath}/${this.childrenPath.replace("*",r.toString()).replace(/\*/g,"0")}`}{const t=s.toChecksumAddress(e),r=this.paths[t];if(void 0===r)throw new Error("Unknown address");return r}}}c.type="QR Hardware Wallet Device",exports.BaseKeyring=c;
//# sourceMappingURL=base-eth-keyring.cjs.production.min.js.map
import HDKey from 'hdkey';
import { publicToAddress, toChecksumAddress, rlp, stripHexPrefix } from 'ethereumjs-util';
import { publicToAddress, toChecksumAddress, stripHexPrefix } from '@ethereumjs/util';
import rlp from 'rlp';
import { TransactionFactory } from '@ethereumjs/tx';

@@ -385,3 +386,3 @@ import { extend, EthSignRequest, DataType } from '@keystonehq/bc-ur-registry-eth';

if (tx.type === 0) {
messageToSign = rlp.encode(tx.getMessageToSign(false));
messageToSign = Buffer.from(rlp.encode(tx.getMessageToSign(false)));
} else {

@@ -388,0 +389,0 @@ messageToSign = tx.getMessageToSign(false);

{
"name": "@keystonehq/base-eth-keyring",
"version": "0.7.1-alpha.0",
"version": "0.7.1",
"description": "base eth keyring",

@@ -30,5 +30,6 @@ "author": "aaronisme <aarondongchen@gmail.com>",

"@ethereumjs/tx": "3.5.1",
"@keystonehq/bc-ur-registry-eth": "^0.12.1-alpha.0",
"ethereumjs-util": "^7.0.8",
"@ethereumjs/util": "^8.0.0",
"@keystonehq/bc-ur-registry-eth": "^0.12.1",
"hdkey": "^2.0.1",
"rlp": "^3.0.0",
"uuid": "^8.3.2"

@@ -45,3 +46,3 @@ },

},
"gitHead": "3874845672c0ff7ec6aaf00878aea629ed18e7f5"
"gitHead": "55e22e56753d5f7dd04eeb14c83f3917aa754358"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc