Socket
Socket
Sign inDemoInstall

mockttp

Package Overview
Dependencies
Maintainers
1
Versions
124
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mockttp - npm Package Compare versions

Comparing version 3.14.0 to 3.15.0

2

dist/main.d.ts

@@ -20,3 +20,3 @@ import { Mockttp, MockttpOptions, MockttpHttpsOptions, SubscribableEvent, PortRange } from "./mockttp";

export type { ProxyConfig, ProxySetting, ProxySettingSource, ProxySettingCallback, ProxySettingCallbackParams } from './rules/proxy-config';
export type { ForwardingOptions, PassThroughLookupOptions, PassThroughHandlerConnectionOptions } from './rules/passthrough-handling-definitions';
export type { CADefinition, ForwardingOptions, PassThroughLookupOptions, PassThroughHandlerConnectionOptions } from './rules/passthrough-handling-definitions';
export type { RequestRuleBuilder } from "./rules/requests/request-rule-builder";

@@ -23,0 +23,0 @@ export type { WebSocketRuleBuilder } from "./rules/websockets/websocket-rule-builder";

@@ -14,2 +14,3 @@ "use strict";

const proxy_config_1 = require("./proxy-config");
const passthrough_handling_1 = require("./passthrough-handling");
const KeepAliveAgents = util_1.isNode

@@ -53,3 +54,4 @@ ? {

url: proxySetting.proxyUrl,
ca: proxySetting.trustedCAs
trustedCAs: proxySetting.trustedCAs,
additionalTrustedCAs: proxySetting.additionalTrustedCAs
});

@@ -59,2 +61,6 @@ if (!proxyAgentCache.has(cacheKey)) {

const buildProxyAgent = ProxyAgentFactoryMap[protocol];
// If you specify trusted CAs, we override the CAs used for this connection, i.e. the trusted
// CA for the certificate of an HTTPS proxy. This is *not* the CAs trusted for upstream servers
// on the otherside of the proxy - see the corresponding passthrough options for that.
const trustedCerts = await (0, passthrough_handling_1.getTrustedCAs)(proxySetting.trustedCAs, proxySetting.additionalTrustedCAs);
proxyAgentCache.set(cacheKey, buildProxyAgent({

@@ -65,7 +71,4 @@ protocol,

port,
// If you specify trusted CAs, we override the CAs used for this connection, i.e. the trusted
// CA for the certificate of an HTTPS proxy. This is *not* the CAs trusted for upstream servers
// on the otherside of the proxy - see the `trustAdditionalCAs` passthrough option for that.
...(proxySetting.trustedCAs
? { ca: proxySetting.trustedCAs }
...(trustedCerts
? { ca: trustedCerts }
: {})

@@ -72,0 +75,0 @@ }));

@@ -28,2 +28,7 @@ /// <reference types="node" />

}
export declare type CADefinition = {
cert: string | Buffer;
} | {
certPath: string;
};
/**

@@ -61,8 +66,10 @@ * This defines the upstream connection parameters. These passthrough parameters

*/
trustAdditionalCAs?: Array<{
cert: string | Buffer;
} | {
certPath: string;
}>;
additionalTrustedCAs?: Array<CADefinition>;
/**
* Deprecated alias for `additionalTrustedCAs`
*
* @deprecated
*/
trustAdditionalCAs?: Array<CADefinition>;
/**
* A mapping of hosts to client certificates to use, in the form of

@@ -69,0 +76,0 @@ * `{ key, cert }` objects (none, by default)

@@ -7,4 +7,5 @@ /// <reference types="node" />

import { CallbackRequestResult, CallbackResponseMessageResult } from './requests/request-handler-definitions';
import { PassThroughLookupOptions } from './passthrough-handling-definitions';
import { CADefinition, PassThroughLookupOptions } from './passthrough-handling-definitions';
export declare const getUpstreamTlsOptions: (strictChecks: boolean) => tls.SecureContextOptions;
export declare function getTrustedCAs(trustedCAs: Array<string | CADefinition> | undefined, additionalTrustedCAs: Array<CADefinition> | undefined): Promise<Array<string> | undefined>;
/**

@@ -11,0 +12,0 @@ * Takes a callback result and some headers, and returns a ready to send body, using the headers

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getClientRelativeHostname = exports.getDnsLookupFunction = exports.shouldUseStrictHttps = exports.getContentLengthAfterModification = exports.getH2HeadersAfterModification = exports.OVERRIDABLE_REQUEST_PSEUDOHEADERS = exports.getHostAfterModification = exports.buildOverriddenBody = exports.getUpstreamTlsOptions = void 0;
exports.getClientRelativeHostname = exports.getDnsLookupFunction = exports.shouldUseStrictHttps = exports.getContentLengthAfterModification = exports.getH2HeadersAfterModification = exports.OVERRIDABLE_REQUEST_PSEUDOHEADERS = exports.getHostAfterModification = exports.buildOverriddenBody = exports.getTrustedCAs = exports.getUpstreamTlsOptions = void 0;
const _ = require("lodash");
const fs = require("fs/promises");
const tls = require("tls");

@@ -85,2 +86,23 @@ const url = require("url");

exports.getUpstreamTlsOptions = getUpstreamTlsOptions;
async function getTrustedCAs(trustedCAs, additionalTrustedCAs) {
if (trustedCAs && additionalTrustedCAs?.length) {
throw new Error(`trustedCAs and additionalTrustedCAs options are mutually exclusive`);
}
if (trustedCAs) {
return Promise.all(trustedCAs.map((caDefinition) => getCA(caDefinition)));
}
if (additionalTrustedCAs) {
const CAs = await Promise.all(additionalTrustedCAs.map((caDefinition) => getCA(caDefinition)));
return tls.rootCertificates.concat(CAs);
}
}
exports.getTrustedCAs = getTrustedCAs;
const getCA = async (caDefinition) => {
return typeof caDefinition === 'string'
? caDefinition
: 'certPath' in caDefinition
? await fs.readFile(caDefinition.certPath, 'utf8')
// 'cert' in caDefinition
: caDefinition.cert.toString('utf8');
};
// --- Various helpers for deriving parts of request/response data given partial overrides: ---

@@ -87,0 +109,0 @@ /**

import { MaybePromise } from '../util/type-utils';
import { RuleParameterReference } from './rule-parameters';
import { CADefinition } from './passthrough-handling-definitions';
/**

@@ -39,6 +40,19 @@ * A ProxySetting is a specific proxy setting to use, which is passed to a proxy agent

*
* Note that unlike passthrough rule's `trustAdditionalCAs` option, this sets the
* complete list of trusted CAs - not just additional ones.
* This sets the complete list of trusted CAs, and is mutually exclusive with the
* `additionalTrustedCAs` option, which adds additional CAs (but also trusts the
* Node default CAs too).
*
* This should be specified as either a { cert: string | Buffer } object or a
* { certPath: string } object (to read the cert from disk). The previous
* simple string format is supported but deprecated.
*/
trustedCAs?: string[];
trustedCAs?: Array<string | CADefinition>;
/**
* Extra CAs to trust for HTTPS connections to the proxy. Ignored if the connection
* to the proxy is not HTTPS.
*
* This appends to the list of trusted CAs, and is mutually exclusive with the
* `trustedCAs` option, which completely overrides the list of CAs.
*/
additionalTrustedCAs?: Array<CADefinition>;
}

@@ -45,0 +59,0 @@ /**

@@ -10,3 +10,3 @@ /// <reference types="node" />

import { ProxyConfig } from '../proxy-config';
import { ForwardingOptions, PassThroughHandlerConnectionOptions, PassThroughLookupOptions } from '../passthrough-handling-definitions';
import { CADefinition, ForwardingOptions, PassThroughHandlerConnectionOptions, PassThroughLookupOptions } from '../passthrough-handling-definitions';
export interface RequestHandlerDefinition extends Explainable, Serializable {

@@ -546,7 +546,3 @@ type: keyof typeof HandlerDefinitionLookup;

};
readonly extraCACertificates: Array<{
cert: string | Buffer;
} | {
certPath: string;
}>;
readonly extraCACertificates: Array<CADefinition>;
readonly transformRequest?: RequestTransform;

@@ -553,0 +549,0 @@ readonly transformResponse?: ResponseTransform;

@@ -192,3 +192,6 @@ "use strict";

this.simulateConnectionErrors = !!options.simulateConnectionErrors;
this.extraCACertificates = options.trustAdditionalCAs || [];
this.extraCACertificates =
options.additionalTrustedCAs ||
options.trustAdditionalCAs ||
[];
this.clientCertificateHostMap = options.clientCertificateHostMap || {};

@@ -195,0 +198,0 @@ if (options.beforeRequest && options.transformRequest && !_.isEmpty(options.transformRequest)) {

@@ -6,3 +6,2 @@ "use strict";

const url = require("url");
const tls = require("tls");
const http = require("http");

@@ -220,11 +219,3 @@ const https = require("https");

if (!this._trustedCACertificates) {
this._trustedCACertificates = Promise.all(tls.rootCertificates
.concat(this.extraCACertificates.map(certObject => {
if ('cert' in certObject) {
return certObject.cert.toString('utf8');
}
else {
return fs.readFile(certObject.certPath, 'utf8');
}
})));
this._trustedCACertificates = (0, passthrough_handling_1.getTrustedCAs)(undefined, this.extraCACertificates);
}

@@ -938,3 +929,3 @@ return this._trustedCACertificates;

ignoreHostHttpsErrors: data.ignoreHostCertificateErrors,
trustAdditionalCAs: data.extraCACertificates,
additionalTrustedCAs: data.extraCACertificates,
clientCertificateHostMap: _.mapValues(data.clientCertificateHostMap, ({ pfx, passphrase }) => ({ pfx: (0, serialization_1.deserializeBuffer)(pfx), passphrase })),

@@ -941,0 +932,0 @@ });

@@ -5,3 +5,3 @@ /// <reference types="node" />

import { ProxyConfig } from '../proxy-config';
import { PassThroughHandlerConnectionOptions, ForwardingOptions, PassThroughLookupOptions } from '../passthrough-handling-definitions';
import { PassThroughHandlerConnectionOptions, ForwardingOptions, PassThroughLookupOptions, CADefinition } from '../passthrough-handling-definitions';
import { CloseConnectionHandlerDefinition, ResetConnectionHandlerDefinition, TimeoutHandlerDefinition } from '../requests/request-handler-definitions';

@@ -45,7 +45,3 @@ export interface WebSocketHandlerDefinition extends Explainable, Serializable {

};
readonly extraCACertificates: Array<{
cert: string | Buffer;
} | {
certPath: string;
}>;
readonly extraCACertificates: Array<CADefinition>;
constructor(options?: PassThroughWebSocketHandlerOptions);

@@ -52,0 +48,0 @@ explain(): string;

@@ -37,3 +37,6 @@ "use strict";

this.proxyConfig = options.proxyConfig;
this.extraCACertificates = options.trustAdditionalCAs || [];
this.extraCACertificates =
options.additionalTrustedCAs ||
options.trustAdditionalCAs ||
[];
this.clientCertificateHostMap = options.clientCertificateHostMap || {};

@@ -40,0 +43,0 @@ }

@@ -5,3 +5,3 @@ /// <reference types="node" />

import { MaybePromise } from '../util/type-utils';
import { RuleParameterReference, RuleParameters } from '../rules/rule-parameters';
import { RuleParameters } from '../rules/rule-parameters';
import type { ProxySetting, ProxySettingSource, ProxyConfig } from '../rules/proxy-config';

@@ -61,3 +61,2 @@ export declare function serialize<T extends Serializable>(obj: T, stream: Duplex): SerializedValue<T>;

};
export declare function maybeSerializeParam<T, R>(value: T | RuleParameterReference<R>): T | SerializedRuleParameterReference<R>;
export declare function ensureParamsDeferenced<T>(value: T | SerializedRuleParameterReference<T>, ruleParams: RuleParameters): T;

@@ -64,0 +63,0 @@ export declare type SerializedProxyConfig = ProxySetting | string | undefined | SerializedRuleParameterReference<ProxySettingSource> | Array<SerializedProxyConfig>;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.deserializeProxyConfig = exports.serializeProxyConfig = exports.ensureParamsDeferenced = exports.maybeSerializeParam = exports.deserializeBuffer = exports.serializeBuffer = exports.ClientServerChannel = exports.Serializable = exports.deserialize = exports.serialize = void 0;
exports.deserializeProxyConfig = exports.serializeProxyConfig = exports.ensureParamsDeferenced = exports.deserializeBuffer = exports.serializeBuffer = exports.ClientServerChannel = exports.Serializable = exports.deserialize = exports.serialize = void 0;
const _ = require("lodash");

@@ -203,12 +203,6 @@ const stream_1 = require("stream");

const SERIALIZED_PARAM_REFERENCE = "__mockttp__param__reference__";
function maybeSerializeParam(value) {
if ((0, rule_parameters_1.isParamReference)(value)) {
// Swap the symbol for a string, since we can't serialize symbols in JSON:
return { [SERIALIZED_PARAM_REFERENCE]: value[rule_parameters_1.MOCKTTP_PARAM_REF] };
}
else {
return value;
}
function serializeParam(value) {
// Swap the symbol for a string, since we can't serialize symbols in JSON:
return { [SERIALIZED_PARAM_REFERENCE]: value[rule_parameters_1.MOCKTTP_PARAM_REF] };
}
exports.maybeSerializeParam = maybeSerializeParam;
function isSerializedRuleParam(value) {

@@ -238,5 +232,16 @@ return value && SERIALIZED_PARAM_REFERENCE in value;

}
else {
return maybeSerializeParam(proxyConfig);
else if ((0, rule_parameters_1.isParamReference)(proxyConfig)) {
return serializeParam(proxyConfig);
}
else if (proxyConfig) {
return {
...proxyConfig,
trustedCAs: proxyConfig.trustedCAs?.map((caDefinition) => typeof caDefinition !== 'string' && 'cert' in caDefinition
? { cert: caDefinition.cert.toString('utf8') } // Stringify in case of buffers
: caDefinition),
additionalTrustedCAs: proxyConfig.additionalTrustedCAs?.map((caDefinition) => 'cert' in caDefinition
? { cert: caDefinition.cert.toString('utf8') } // Stringify in case of buffers
: caDefinition)
};
}
}

@@ -243,0 +248,0 @@ exports.serializeProxyConfig = serializeProxyConfig;

{
"name": "mockttp",
"version": "3.14.0",
"version": "3.15.0",
"description": "Mock HTTP server for testing HTTP clients and stubbing webservices",

@@ -5,0 +5,0 @@ "exports": {

@@ -60,2 +60,3 @@ import { Mockttp, MockttpOptions, MockttpHttpsOptions, SubscribableEvent, PortRange } from "./mockttp";

export type {
CADefinition,
ForwardingOptions,

@@ -62,0 +63,0 @@ PassThroughLookupOptions,

@@ -15,2 +15,3 @@ import * as _ from 'lodash';

import { getProxySetting, matchesNoProxy, ProxySettingSource } from './proxy-config';
import { getTrustedCAs } from './passthrough-handling';

@@ -74,3 +75,4 @@ const KeepAliveAgents = isNode

url: proxySetting.proxyUrl,
ca: proxySetting.trustedCAs
trustedCAs: proxySetting.trustedCAs,
additionalTrustedCAs: proxySetting.additionalTrustedCAs
});

@@ -82,2 +84,10 @@

// If you specify trusted CAs, we override the CAs used for this connection, i.e. the trusted
// CA for the certificate of an HTTPS proxy. This is *not* the CAs trusted for upstream servers
// on the otherside of the proxy - see the corresponding passthrough options for that.
const trustedCerts = await getTrustedCAs(
proxySetting.trustedCAs,
proxySetting.additionalTrustedCAs
);
proxyAgentCache.set(cacheKey, buildProxyAgent({

@@ -89,7 +99,4 @@ protocol,

// If you specify trusted CAs, we override the CAs used for this connection, i.e. the trusted
// CA for the certificate of an HTTPS proxy. This is *not* the CAs trusted for upstream servers
// on the otherside of the proxy - see the `trustAdditionalCAs` passthrough option for that.
...(proxySetting.trustedCAs
? { ca: proxySetting.trustedCAs }
...(trustedCerts
? { ca: trustedCerts }
: {}

@@ -96,0 +103,0 @@ )

@@ -31,2 +31,6 @@ import { ProxyConfig } from "./proxy-config";

export type CADefinition =
| { cert: string | Buffer }
| { certPath: string };
/**

@@ -66,5 +70,12 @@ * This defines the upstream connection parameters. These passthrough parameters

*/
trustAdditionalCAs?: Array<{ cert: string | Buffer } | { certPath: string }>;
additionalTrustedCAs?: Array<CADefinition>;
/**
* Deprecated alias for `additionalTrustedCAs`
*
* @deprecated
*/
trustAdditionalCAs?: Array<CADefinition>;
/**
* A mapping of hosts to client certificates to use, in the form of

@@ -71,0 +82,0 @@ * `{ key, cert }` objects (none, by default)

import * as _ from 'lodash';
import * as fs from 'fs/promises';
import * as tls from 'tls';

@@ -20,2 +21,3 @@ import url = require('url');

import {
CADefinition,
PassThroughLookupOptions

@@ -101,2 +103,30 @@ } from './passthrough-handling-definitions';

export async function getTrustedCAs(
trustedCAs: Array<string | CADefinition> | undefined,
additionalTrustedCAs: Array<CADefinition> | undefined
): Promise<Array<string> | undefined> {
if (trustedCAs && additionalTrustedCAs?.length) {
throw new Error(`trustedCAs and additionalTrustedCAs options are mutually exclusive`);
}
if (trustedCAs) {
return Promise.all(trustedCAs.map((caDefinition) => getCA(caDefinition)));
}
if (additionalTrustedCAs) {
const CAs = await Promise.all(additionalTrustedCAs.map((caDefinition) => getCA(caDefinition)));
return tls.rootCertificates.concat(CAs);
}
}
const getCA = async (caDefinition: string | CADefinition) => {
return typeof caDefinition === 'string'
? caDefinition
: 'certPath' in caDefinition
? await fs.readFile(caDefinition.certPath, 'utf8')
// 'cert' in caDefinition
: caDefinition.cert.toString('utf8')
}
// --- Various helpers for deriving parts of request/response data given partial overrides: ---

@@ -103,0 +133,0 @@

@@ -5,2 +5,3 @@ import * as _ from 'lodash';

import { RuleParameterReference } from './rule-parameters';
import { CADefinition } from './passthrough-handling-definitions';

@@ -45,6 +46,23 @@ /**

*
* Note that unlike passthrough rule's `trustAdditionalCAs` option, this sets the
* complete list of trusted CAs - not just additional ones.
* This sets the complete list of trusted CAs, and is mutually exclusive with the
* `additionalTrustedCAs` option, which adds additional CAs (but also trusts the
* Node default CAs too).
*
* This should be specified as either a { cert: string | Buffer } object or a
* { certPath: string } object (to read the cert from disk). The previous
* simple string format is supported but deprecated.
*/
trustedCAs?: string[];
trustedCAs?: Array<
| string // Deprecated
| CADefinition
>;
/**
* Extra CAs to trust for HTTPS connections to the proxy. Ignored if the connection
* to the proxy is not HTTPS.
*
* This appends to the list of trusted CAs, and is mutually exclusive with the
* `trustedCAs` option, which completely overrides the list of CAs.
*/
additionalTrustedCAs?: Array<CADefinition>;
}

@@ -51,0 +69,0 @@

@@ -37,2 +37,3 @@ import _ = require('lodash');

import {
CADefinition,
ForwardingOptions,

@@ -775,3 +776,3 @@ PassThroughHandlerConnectionOptions,

public readonly extraCACertificates: Array<{ cert: string | Buffer } | { certPath: string }> = [];
public readonly extraCACertificates: Array<CADefinition> = [];

@@ -825,3 +826,7 @@ public readonly transformRequest?: RequestTransform;

this.extraCACertificates = options.trustAdditionalCAs || [];
this.extraCACertificates =
options.additionalTrustedCAs ||
options.trustAdditionalCAs ||
[];
this.clientCertificateHostMap = options.clientCertificateHostMap || {};

@@ -828,0 +833,0 @@

@@ -81,3 +81,4 @@ import _ = require('lodash');

getClientRelativeHostname,
getDnsLookupFunction
getDnsLookupFunction,
getTrustedCAs
} from '../passthrough-handling';

@@ -392,12 +393,3 @@

if (!this._trustedCACertificates) {
this._trustedCACertificates = Promise.all(
(tls.rootCertificates as Array<string | Promise<string>>)
.concat(this.extraCACertificates.map(certObject => {
if ('cert' in certObject) {
return certObject.cert.toString('utf8');
} else {
return fs.readFile(certObject.certPath, 'utf8');
}
}))
);
this._trustedCACertificates = getTrustedCAs(undefined, this.extraCACertificates);
}

@@ -1284,3 +1276,3 @@

ignoreHostHttpsErrors: data.ignoreHostCertificateErrors,
trustAdditionalCAs: data.extraCACertificates,
additionalTrustedCAs: data.extraCACertificates,
clientCertificateHostMap: _.mapValues(data.clientCertificateHostMap,

@@ -1287,0 +1279,0 @@ ({ pfx, passphrase }) => ({ pfx: deserializeBuffer(pfx), passphrase })

@@ -19,3 +19,4 @@ import * as _ from 'lodash';

ForwardingOptions,
PassThroughLookupOptions
PassThroughLookupOptions,
CADefinition
} from '../passthrough-handling-definitions';

@@ -73,3 +74,3 @@ import {

public readonly extraCACertificates: Array<{ cert: string | Buffer } | { certPath: string }> = [];
public readonly extraCACertificates: Array<CADefinition> = [];

@@ -103,3 +104,6 @@ constructor(options: PassThroughWebSocketHandlerOptions = {}) {

this.extraCACertificates = options.trustAdditionalCAs || [];
this.extraCACertificates =
options.additionalTrustedCAs ||
options.trustAdditionalCAs ||
[];
this.clientCertificateHostMap = options.clientCertificateHostMap || {};

@@ -106,0 +110,0 @@ }

@@ -289,9 +289,5 @@ import * as _ from 'lodash';

export function maybeSerializeParam<T, R>(value: T | RuleParameterReference<R>): T | SerializedRuleParameterReference<R> {
if (isParamReference(value)) {
// Swap the symbol for a string, since we can't serialize symbols in JSON:
return { [SERIALIZED_PARAM_REFERENCE]: value[MOCKTTP_PARAM_REF] };
} else {
return value;
}
function serializeParam<R>(value: RuleParameterReference<R>): SerializedRuleParameterReference<R> {
// Swap the symbol for a string, since we can't serialize symbols in JSON:
return { [SERIALIZED_PARAM_REFERENCE]: value[MOCKTTP_PARAM_REF] };
}

@@ -339,4 +335,18 @@

return proxyConfig.map((config) => serializeProxyConfig(config, channel));
} else {
return maybeSerializeParam(proxyConfig);
} else if (isParamReference(proxyConfig)) {
return serializeParam(proxyConfig);
} else if (proxyConfig) {
return {
...proxyConfig,
trustedCAs: proxyConfig.trustedCAs?.map((caDefinition) =>
typeof caDefinition !== 'string' && 'cert' in caDefinition
? { cert: caDefinition.cert.toString('utf8') } // Stringify in case of buffers
: caDefinition
),
additionalTrustedCAs: proxyConfig.additionalTrustedCAs?.map((caDefinition) =>
'cert' in caDefinition
? { cert: caDefinition.cert.toString('utf8') } // Stringify in case of buffers
: caDefinition
)
};
}

@@ -343,0 +353,0 @@ }

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

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

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

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

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

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