Socket
Socket
Sign inDemoInstall

@metamask/onboarding

Package Overview
Dependencies
Maintainers
7
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@metamask/onboarding - npm Package Compare versions

Comparing version 1.0.0 to 1.0.1

27

CHANGELOG.md
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.0.1]
### Changed
- Update various dependencies ([#49](https://github.com/MetaMask/metamask-onboarding/pull/49), [#68](https://github.com/MetaMask/metamask-onboarding/pull/68), [#71](https://github.com/MetaMask/metamask-onboarding/pull/71))
- Use `@lavamoat/allow-scripts` for improved security ([#67](https://github.com/MetaMask/metamask-onboarding/pull/67))
- Remove unused dependencies ([#66](https://github.com/MetaMask/metamask-onboarding/pull/66))
- Switch from CircleCI to GitHub Actions ([#64](https://github.com/MetaMask/metamask-onboarding/pull/64))
- Update Node.js used for CI from v10 to v12 ([#59](https://github.com/MetaMask/metamask-onboarding/pull/59), [#73](https://github.com/MetaMask/metamask-onboarding/pull/73))
- Refactor to improve readability ([#45](https://github.com/MetaMask/metamask-onboarding/pull/45), [#47](https://github.com/MetaMask/metamask-onboarding/pull/47), [#48](https://github.com/MetaMask/metamask-onboarding/pull/48))
### Fixed
- Fix import of `bowser` package ([#57](https://github.com/MetaMask/metamask-onboarding/pull/57), [#60](https://github.com/MetaMask/metamask-onboarding/pull/60), [#61](https://github.com/MetaMask/metamask-onboarding/pull/61), [#63](https://github.com/MetaMask/metamask-onboarding/pull/63))
## [1.0.0] - 2020-07-02
### Changed
- **BREAKING**: Rename export to `MetaMaskOnboarding` (#32)
- Update example in README with validated HTML (#30)
- Rename export to `MetaMaskOnboarding` (#32, **breaking**)
- Update example in README with validated HTML (#30)
### Fixed
- Use Firefox URL without specified language (#38)
[Unreleased]:https://github.com/MetaMask/metamask-onboarding/compare/v1.0.0...HEAD
[1.0.0]:https://github.com/MetaMask/metamask-onboarding/tree/v1.0.0
[Unreleased]: https://github.com/MetaMask/metamask-onboarding/compare/v1.0.1...HEAD
[1.0.1]: https://github.com/MetaMask/metamask-onboarding/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/MetaMask/metamask-onboarding/releases/tag/v1.0.0

@@ -10,3 +10,3 @@ export default class Onboarding {

private state;
constructor({ forwarderOrigin, forwarderMode }?: {
constructor({ forwarderOrigin, forwarderMode, }?: {
forwarderOrigin?: string | undefined;

@@ -16,2 +16,3 @@ forwarderMode?: "INJECT" | undefined;

_onMessage(event: MessageEvent): Promise<void> | undefined;
_onMessageUnknownStateError(state: never): never;
_onMessageFromForwarder(event: MessageEvent): Promise<void>;

@@ -18,0 +19,0 @@ /**

'use strict';
var Bowser = require('bowser');
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var Bowser = _interopDefault(require('bowser'));
/*! *****************************************************************************

@@ -79,5 +81,5 @@ Copyright (c) Microsoft Corporation.

this.forwarderMode = forwarderMode;
this.state = Onboarding.isMetaMaskInstalled() ?
ONBOARDING_STATE.INSTALLED :
ONBOARDING_STATE.NOT_INSTALLED;
this.state = Onboarding.isMetaMaskInstalled()
? ONBOARDING_STATE.INSTALLED
: ONBOARDING_STATE.NOT_INSTALLED;
var browser = Onboarding._detectBrowser();

@@ -97,3 +99,4 @@ if (browser) {

window.addEventListener('message', this._onMessage);
if (forwarderMode === Onboarding.FORWARDER_MODE.INJECT && sessionStorage.getItem(REGISTRATION_IN_PROGRESS) === 'true') {
if (forwarderMode === Onboarding.FORWARDER_MODE.INJECT &&
sessionStorage.getItem(REGISTRATION_IN_PROGRESS) === 'true') {
Onboarding._injectForwarder(this.forwarderOrigin);

@@ -113,41 +116,48 @@ }

};
Onboarding.prototype._onMessageUnknownStateError = function (state) {
throw new Error("Unknown state: '" + state + "'");
};
Onboarding.prototype._onMessageFromForwarder = function (event) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!(this.state === ONBOARDING_STATE.RELOADING)) return [3 /*break*/, 1];
_a = this.state;
switch (_a) {
case ONBOARDING_STATE.RELOADING: return [3 /*break*/, 1];
case ONBOARDING_STATE.NOT_INSTALLED: return [3 /*break*/, 2];
case ONBOARDING_STATE.INSTALLED: return [3 /*break*/, 3];
case ONBOARDING_STATE.REGISTERING: return [3 /*break*/, 5];
case ONBOARDING_STATE.REGISTERED: return [3 /*break*/, 6];
}
return [3 /*break*/, 7];
case 1:
console.debug('Ignoring message while reloading');
return [3 /*break*/, 5];
case 1:
if (!(this.state === ONBOARDING_STATE.NOT_INSTALLED)) return [3 /*break*/, 2];
return [3 /*break*/, 8];
case 2:
console.debug('Reloading now to register with MetaMask');
this.state = ONBOARDING_STATE.RELOADING;
return [2 /*return*/, location.reload()];
case 2:
if (!(this.state === ONBOARDING_STATE.INSTALLED)) return [3 /*break*/, 4];
location.reload();
return [3 /*break*/, 8];
case 3:
console.debug('Registering with MetaMask');
this.state = ONBOARDING_STATE.REGISTERING;
return [4 /*yield*/, Onboarding._register()];
case 3:
case 4:
_b.sent();
this.state = ONBOARDING_STATE.REGISTERED;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
(_a = event.source) === null || _a === void 0 ? void 0 : _a.postMessage({ type: 'metamask:registrationCompleted' }, event.origin);
event.source.postMessage({ type: 'metamask:registrationCompleted' }, event.origin);
this.stopOnboarding();
return [3 /*break*/, 5];
case 4:
if (this.state === ONBOARDING_STATE.REGISTERING) {
console.debug('Already registering - ignoring reload message');
}
else if (this.state === ONBOARDING_STATE.REGISTERED) {
console.debug('Already registered - ignoring reload message');
}
else {
throw new Error("Unknown state: '" + this.state + "'");
}
_b.label = 5;
case 5: return [2 /*return*/, undefined];
return [3 /*break*/, 8];
case 5:
console.debug('Already registering - ignoring reload message');
return [3 /*break*/, 8];
case 6:
console.debug('Already registered - ignoring reload message');
return [3 /*break*/, 8];
case 7:
this._onMessageUnknownStateError(this.state);
_b.label = 8;
case 8: return [2 /*return*/];
}

@@ -154,0 +164,0 @@ });

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

import { parse } from 'bowser';
import Bowser from 'bowser';

@@ -77,5 +77,5 @@ /*! *****************************************************************************

this.forwarderMode = forwarderMode;
this.state = Onboarding.isMetaMaskInstalled() ?
ONBOARDING_STATE.INSTALLED :
ONBOARDING_STATE.NOT_INSTALLED;
this.state = Onboarding.isMetaMaskInstalled()
? ONBOARDING_STATE.INSTALLED
: ONBOARDING_STATE.NOT_INSTALLED;
var browser = Onboarding._detectBrowser();

@@ -95,3 +95,4 @@ if (browser) {

window.addEventListener('message', this._onMessage);
if (forwarderMode === Onboarding.FORWARDER_MODE.INJECT && sessionStorage.getItem(REGISTRATION_IN_PROGRESS) === 'true') {
if (forwarderMode === Onboarding.FORWARDER_MODE.INJECT &&
sessionStorage.getItem(REGISTRATION_IN_PROGRESS) === 'true') {
Onboarding._injectForwarder(this.forwarderOrigin);

@@ -111,41 +112,48 @@ }

};
Onboarding.prototype._onMessageUnknownStateError = function (state) {
throw new Error("Unknown state: '" + state + "'");
};
Onboarding.prototype._onMessageFromForwarder = function (event) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!(this.state === ONBOARDING_STATE.RELOADING)) return [3 /*break*/, 1];
_a = this.state;
switch (_a) {
case ONBOARDING_STATE.RELOADING: return [3 /*break*/, 1];
case ONBOARDING_STATE.NOT_INSTALLED: return [3 /*break*/, 2];
case ONBOARDING_STATE.INSTALLED: return [3 /*break*/, 3];
case ONBOARDING_STATE.REGISTERING: return [3 /*break*/, 5];
case ONBOARDING_STATE.REGISTERED: return [3 /*break*/, 6];
}
return [3 /*break*/, 7];
case 1:
console.debug('Ignoring message while reloading');
return [3 /*break*/, 5];
case 1:
if (!(this.state === ONBOARDING_STATE.NOT_INSTALLED)) return [3 /*break*/, 2];
return [3 /*break*/, 8];
case 2:
console.debug('Reloading now to register with MetaMask');
this.state = ONBOARDING_STATE.RELOADING;
return [2 /*return*/, location.reload()];
case 2:
if (!(this.state === ONBOARDING_STATE.INSTALLED)) return [3 /*break*/, 4];
location.reload();
return [3 /*break*/, 8];
case 3:
console.debug('Registering with MetaMask');
this.state = ONBOARDING_STATE.REGISTERING;
return [4 /*yield*/, Onboarding._register()];
case 3:
case 4:
_b.sent();
this.state = ONBOARDING_STATE.REGISTERED;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
(_a = event.source) === null || _a === void 0 ? void 0 : _a.postMessage({ type: 'metamask:registrationCompleted' }, event.origin);
event.source.postMessage({ type: 'metamask:registrationCompleted' }, event.origin);
this.stopOnboarding();
return [3 /*break*/, 5];
case 4:
if (this.state === ONBOARDING_STATE.REGISTERING) {
console.debug('Already registering - ignoring reload message');
}
else if (this.state === ONBOARDING_STATE.REGISTERED) {
console.debug('Already registered - ignoring reload message');
}
else {
throw new Error("Unknown state: '" + this.state + "'");
}
_b.label = 5;
case 5: return [2 /*return*/, undefined];
return [3 /*break*/, 8];
case 5:
console.debug('Already registering - ignoring reload message');
return [3 /*break*/, 8];
case 6:
console.debug('Already registered - ignoring reload message');
return [3 /*break*/, 8];
case 7:
this._onMessageUnknownStateError(this.state);
_b.label = 8;
case 8: return [2 /*return*/];
}

@@ -215,3 +223,3 @@ });

Onboarding._detectBrowser = function () {
var browserInfo = parse(window.navigator.userAgent);
var browserInfo = Bowser.parse(window.navigator.userAgent);
if (browserInfo.browser.name === 'Firefox') {

@@ -218,0 +226,0 @@ return 'FIREFOX';

{
"name": "@metamask/onboarding",
"version": "1.0.0",
"version": "1.0.1",
"description": "Assists with onboarding new MetaMask users",

@@ -14,3 +14,3 @@ "main": "dist/metamask-onboarding.cjs.js",

"type": "git",
"url": "git+ssh://git@github.com/MetaMask/metamask-onboarding.git"
"url": "https://github.com/MetaMask/metamask-onboarding.git"
},

@@ -27,23 +27,37 @@ "publishConfig": {

"scripts": {
"prepublishOnly": "npm run build",
"lint": "eslint --ext .ts,.js .",
"setup": "yarn install && yarn allow-scripts",
"prepublishOnly": "yarn build",
"lint:eslint": "eslint . --cache --ext js,ts",
"lint:misc": "prettier '**/*.json' '**/*.md' '!CHANGELOG.md' '**/*.yml' --ignore-path .gitignore",
"lint": "yarn lint:eslint && yarn lint:misc --check",
"lint:fix": "yarn lint:eslint --fix && yarn lint:misc --write",
"build": "rollup --config"
},
"dependencies": {
"bowser": "^2.9.0",
"tslib": "^1.11.0"
"bowser": "^2.9.0"
},
"devDependencies": {
"@metamask/eslint-config": "^2.0.0",
"@rollup/plugin-commonjs": "^11.0.2",
"@lavamoat/allow-scripts": "^1.0.6",
"@metamask/auto-changelog": "^2.3.0",
"@metamask/eslint-config": "^6.0.0",
"@metamask/eslint-config-nodejs": "^6.0.0",
"@metamask/eslint-config-typescript": "^6.0.0",
"@rollup/plugin-node-resolve": "^7.1.1",
"@typescript-eslint/eslint-plugin": "^2.20.0",
"@typescript-eslint/parser": "^2.20.0",
"eslint": "^6.8.0",
"eslint-plugin-import": "^2.20.1",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.4.0",
"prettier": "^2.3.0",
"rollup": "^2.18.0",
"rollup-plugin-typescript2": "^0.27.1",
"static-server": "^2.2.1",
"typescript": "^3.9.5"
"rollup-plugin-typescript2": "^0.30.0",
"typescript": "^4.3.2"
},
"lavamoat": {
"allowScripts": {
"@lavamoat/preinstall-always-fail": false
}
}
}

@@ -11,5 +11,5 @@ # MetaMask Onboarding

* ES6 module: `import MetaMaskOnboarding from '@metamask/onboarding'`
* ES5 module: `const MetaMaskOnboarding = require('@metamask/onboarding')`
* ES5 bundle: `dist/metamask-onboarding.bundle.js` (this can be included directly in a page)
- ES6 module: `import MetaMaskOnboarding from '@metamask/onboarding'`
- ES5 module: `const MetaMaskOnboarding = require('@metamask/onboarding')`
- ES5 bundle: `dist/metamask-onboarding.bundle.js` (this can be included directly in a page)

@@ -36,5 +36,5 @@ ## Usage

| Constant | Description |
| :-- | :-- |
| `INJECT` | Inject a `iframe` to that will refresh until MetaMask has installed |
| Constant | Description |
| :--------- | :------------------------------------------------------------------------------------------------------------------------------------- |
| `INJECT` | Inject a `iframe` to that will refresh until MetaMask has installed |
| `OPEN_TAB` | Open a tab to a new page that will refresh until MetaMask has installed—this is only useful if the client app has disallowed `iframes` |

@@ -48,6 +48,6 @@

| Option | Description |
| :-- | :-- |
| `forwarderOrigin` | Override the forwarder URL, useful for testing. **Optional**, defaults to `'https://fwd.metamask.io'`. |
| `forwarderMode` | One of the available forwarder modes. **Optional**, defaults to `MetaMaskOnboarding.FORWARDER_MODE.INJECT`. |
| Option | Description |
| :---------------- | :---------------------------------------------------------------------------------------------------------- |
| `forwarderOrigin` | Override the forwarder URL, useful for testing. **Optional**, defaults to `'https://fwd.metamask.io'`. |
| `forwarderMode` | One of the available forwarder modes. **Optional**, defaults to `MetaMaskOnboarding.FORWARDER_MODE.INJECT`. |

@@ -64,12 +64,26 @@ ### Instance methods

## Release & Publishing
## Contributing
### Setup
- Install [Node.js](https://nodejs.org) version 12
- If you are using [nvm](https://github.com/creationix/nvm#installation) (recommended) running `nvm use` will automatically choose the right node version for you.
- Install [Yarn v1](https://yarnpkg.com/en/docs/install)
- Run `yarn setup` to install dependencies and run any requried post-install scripts
- **Warning:** Do not use the `yarn` / `yarn install` command directly. Use `yarn setup` instead. The normal install command will skip required post-install scripts, leaving your development environment in an invalid state.
### Linting
Run `yarn lint` to run the linter.
### Release & Publishing
The project follows the same release process as the other libraries in the MetaMask organization:
1. Create a release branch
- For a typical release, this would be based on `master`
- To update an older maintained major version, base the release branch on the major version branch (e.g. `1.x`)
- For a typical release, this would be based on `main`
- To update an older maintained major version, base the release branch on the major version branch (e.g. `1.x`)
2. Update the changelog
3. Update version in package.json file (e.g. `yarn version --minor --no-git-tag-version`)
4. Create a pull request targeting the base branch (e.g. master or 1.x)
4. Create a pull request targeting the base branch (e.g. `main` or `1.x`)
5. Code review and QA

@@ -76,0 +90,0 @@ 6. Once approved, the PR is squashed & merged

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

import * as Bowser from 'bowser';
import Bowser from 'bowser';

@@ -12,3 +12,4 @@ const ONBOARDING_STATE = {

const EXTENSION_DOWNLOAD_URL = {
CHROME: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn',
CHROME:
'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn',
FIREFOX: 'https://addons.mozilla.org/firefox/addon/ether-metamask/',

@@ -38,8 +39,11 @@ DEFAULT: 'https://metamask.io',

constructor ({ forwarderOrigin = 'https://fwd.metamask.io', forwarderMode = Onboarding.FORWARDER_MODE.INJECT } = {}) {
constructor({
forwarderOrigin = 'https://fwd.metamask.io',
forwarderMode = Onboarding.FORWARDER_MODE.INJECT,
} = {}) {
this.forwarderOrigin = forwarderOrigin;
this.forwarderMode = forwarderMode;
this.state = Onboarding.isMetaMaskInstalled() ?
ONBOARDING_STATE.INSTALLED :
ONBOARDING_STATE.NOT_INSTALLED;
this.state = Onboarding.isMetaMaskInstalled()
? ONBOARDING_STATE.INSTALLED
: ONBOARDING_STATE.NOT_INSTALLED;

@@ -62,3 +66,6 @@ const browser = Onboarding._detectBrowser();

if (forwarderMode === Onboarding.FORWARDER_MODE.INJECT && sessionStorage.getItem(REGISTRATION_IN_PROGRESS) === 'true') {
if (
forwarderMode === Onboarding.FORWARDER_MODE.INJECT &&
sessionStorage.getItem(REGISTRATION_IN_PROGRESS) === 'true'
) {
Onboarding._injectForwarder(this.forwarderOrigin);

@@ -68,3 +75,3 @@ }

_onMessage (event: MessageEvent) {
_onMessage(event: MessageEvent) {
if (event.origin !== this.forwarderOrigin) {

@@ -79,30 +86,45 @@ // Ignoring non-forwarder message

console.debug(`Unknown message from '${event.origin}' with data ${JSON.stringify(event.data)}`);
console.debug(
`Unknown message from '${event.origin}' with data ${JSON.stringify(
event.data,
)}`,
);
return undefined;
}
async _onMessageFromForwarder (event: MessageEvent) {
if (this.state === ONBOARDING_STATE.RELOADING) {
console.debug('Ignoring message while reloading');
} else if (this.state === ONBOARDING_STATE.NOT_INSTALLED) {
console.debug('Reloading now to register with MetaMask');
this.state = ONBOARDING_STATE.RELOADING;
return location.reload();
} else if (this.state === ONBOARDING_STATE.INSTALLED) {
console.debug('Registering with MetaMask');
this.state = ONBOARDING_STATE.REGISTERING;
await Onboarding._register();
this.state = ONBOARDING_STATE.REGISTERED;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
event.source?.postMessage({ type: 'metamask:registrationCompleted' }, event.origin);
this.stopOnboarding();
} else if (this.state === ONBOARDING_STATE.REGISTERING) {
console.debug('Already registering - ignoring reload message');
} else if (this.state === ONBOARDING_STATE.REGISTERED) {
console.debug('Already registered - ignoring reload message');
} else {
throw new Error(`Unknown state: '${this.state}'`);
_onMessageUnknownStateError(state: never): never {
throw new Error(`Unknown state: '${state}'`);
}
async _onMessageFromForwarder(event: MessageEvent) {
switch (this.state) {
case ONBOARDING_STATE.RELOADING:
console.debug('Ignoring message while reloading');
break;
case ONBOARDING_STATE.NOT_INSTALLED:
console.debug('Reloading now to register with MetaMask');
this.state = ONBOARDING_STATE.RELOADING;
location.reload();
break;
case ONBOARDING_STATE.INSTALLED:
console.debug('Registering with MetaMask');
this.state = ONBOARDING_STATE.REGISTERING;
await Onboarding._register();
this.state = ONBOARDING_STATE.REGISTERED;
(event.source as Window).postMessage(
{ type: 'metamask:registrationCompleted' },
event.origin,
);
this.stopOnboarding();
break;
case ONBOARDING_STATE.REGISTERING:
console.debug('Already registering - ignoring reload message');
break;
case ONBOARDING_STATE.REGISTERED:
console.debug('Already registered - ignoring reload message');
break;
default:
this._onMessageUnknownStateError(this.state);
}
return undefined;
}

@@ -113,3 +135,3 @@

*/
startOnboarding () {
startOnboarding() {
sessionStorage.setItem(REGISTRATION_IN_PROGRESS, 'true');

@@ -126,3 +148,3 @@ this._openDownloadPage();

*/
stopOnboarding () {
stopOnboarding() {
if (sessionStorage.getItem(REGISTRATION_IN_PROGRESS) === 'true') {

@@ -137,3 +159,3 @@ if (this.forwarderMode === Onboarding.FORWARDER_MODE.INJECT) {

_openForwarder () {
_openForwarder() {
if (this.forwarderMode === Onboarding.FORWARDER_MODE.OPEN_TAB) {

@@ -146,3 +168,3 @@ window.open(this.forwarderOrigin, '_blank');

_openDownloadPage () {
_openDownloadPage() {
window.open(this.downloadUrl, '_blank');

@@ -154,7 +176,9 @@ }

*/
static isMetaMaskInstalled () {
return Boolean((window as any).ethereum && (window as any).ethereum.isMetaMask);
static isMetaMaskInstalled() {
return Boolean(
(window as any).ethereum && (window as any).ethereum.isMetaMask,
);
}
static _register () {
static _register() {
return (window as any).ethereum.request({

@@ -165,3 +189,3 @@ method: 'wallet_registerOnboarding',

static _injectForwarder (forwarderOrigin: string) {
static _injectForwarder(forwarderOrigin: string) {
const container = document.body;

@@ -177,11 +201,13 @@ const iframe = document.createElement('iframe');

static _removeForwarder () {
static _removeForwarder() {
document.getElementById(FORWARDER_ID)?.remove();
}
static _detectBrowser () {
static _detectBrowser() {
const browserInfo = Bowser.parse(window.navigator.userAgent);
if (browserInfo.browser.name === 'Firefox') {
return 'FIREFOX';
} else if (['Chrome', 'Chromium'].includes(browserInfo.browser.name || '')) {
} else if (
['Chrome', 'Chromium'].includes(browserInfo.browser.name || '')
) {
return 'CHROME';

@@ -188,0 +214,0 @@ }

Sorry, the diff of this file is too big to display

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