@prosopo/cli 3.1.5 → 3.4.6

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.
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const provider = require("@prosopo/provider");
4
+ const typesDatabase = require("@prosopo/types-database");
5
+ const ipAddress = require("ip-address");
6
+ const mongodb = require("mongodb");
7
+ const MAX_IPV4_NUMERIC = 4294967295;
8
+ const BATCH_SIZE = 1e5;
9
+ const migrateIpField = async (db, collectionsToUpgrade, logger) => {
10
+ for (const collection of collectionsToUpgrade) {
11
+ await migrateV4Records(db, collection, logger);
12
+ await migrateV6Records(db, collection, logger);
13
+ }
14
+ };
15
+ const migrateV4Records = async (db, collection, logger) => {
16
+ const searchArgs = {
17
+ ipAddress: {
18
+ $type: "number",
19
+ $lte: Number(MAX_IPV4_NUMERIC)
20
+ }
21
+ };
22
+ let totalModified = 0;
23
+ let processed = 0;
24
+ const count = await db.collection(collection).countDocuments(searchArgs);
25
+ while (true) {
26
+ const docs = await db.collection(collection).find(searchArgs, { projection: { ipAddress: 1 } }).limit(BATCH_SIZE).toArray();
27
+ if (docs.length === 0) break;
28
+ const operations = docs.map((doc) => ({
29
+ updateOne: {
30
+ filter: { _id: doc._id },
31
+ update: {
32
+ $set: {
33
+ ipAddress: {
34
+ lower: doc.ipAddress,
35
+ type: typesDatabase.IpAddressType.v4
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }));
41
+ const bulkResult = await db.collection(collection).bulkWrite(operations, { ordered: false });
42
+ totalModified += bulkResult?.modifiedCount || 0;
43
+ processed += docs.length;
44
+ logger.info(() => ({
45
+ msg: `Migrated v4 batch (${docs.length}) [${processed}/${count}] in "${collection}"`
46
+ }));
47
+ }
48
+ logger.info(() => ({
49
+ msg: `Migrated ${count} v4 records (${totalModified} modified) in "${collection}" collection`
50
+ }));
51
+ };
52
+ const migrateV6Records = async (db, collection, logger) => {
53
+ const searchArgs = {
54
+ ipAddress: {
55
+ $type: "number",
56
+ $gt: Number(MAX_IPV4_NUMERIC)
57
+ }
58
+ };
59
+ let totalModified = 0;
60
+ let processed = 0;
61
+ const count = await db.collection(collection).countDocuments(searchArgs);
62
+ while (true) {
63
+ const docs = await db.collection(collection).find(searchArgs, { projection: { ipAddress: 1 } }).limit(BATCH_SIZE).toArray();
64
+ if (docs.length === 0) break;
65
+ const operations = docs.map((doc) => {
66
+ const ipAddress$1 = ipAddress.Address6.fromBigInt(BigInt(doc.ipAddress));
67
+ const compositeIpAddress = provider.getCompositeIpAddress(ipAddress$1);
68
+ return {
69
+ updateOne: {
70
+ filter: { _id: doc._id },
71
+ update: {
72
+ $set: {
73
+ ipAddress: {
74
+ lower: mongodb.Decimal128.fromString(
75
+ compositeIpAddress.lower.toString()
76
+ ),
77
+ upper: mongodb.Decimal128.fromString(
78
+ (compositeIpAddress.upper || 0n).toString()
79
+ ),
80
+ type: typesDatabase.IpAddressType.v6
81
+ }
82
+ }
83
+ }
84
+ }
85
+ };
86
+ });
87
+ const bulkResult = await db.collection(collection).bulkWrite(operations, { ordered: false });
88
+ totalModified += bulkResult?.modifiedCount || 0;
89
+ processed += docs.length;
90
+ logger.info(() => ({
91
+ msg: `Migrated v6 batch (${docs.length}) [${processed}/${count}] in "${collection}"`
92
+ }));
93
+ }
94
+ logger.info(() => ({
95
+ msg: `Migrated ${count} v6 records (${totalModified} modified) in "${collection}"`
96
+ }));
97
+ };
98
+ exports.migrateIpField = migrateIpField;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const common = require("@prosopo/common");
4
+ const z = require("zod");
5
+ const getDb = require("./getDb.cjs");
6
+ const migrateIpField = require("./migrateIpField.cjs");
7
+ function _interopNamespaceDefault(e) {
8
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
9
+ if (e) {
10
+ for (const k in e) {
11
+ if (k !== "default") {
12
+ const d = Object.getOwnPropertyDescriptor(e, k);
13
+ Object.defineProperty(n, k, d.get ? d : {
14
+ enumerable: true,
15
+ get: () => e[k]
16
+ });
17
+ }
18
+ }
19
+ }
20
+ n.default = e;
21
+ return Object.freeze(n);
22
+ }
23
+ const z__namespace = /* @__PURE__ */ _interopNamespaceDefault(z);
24
+ const collectionsToUpgrade = [
25
+ "powcaptchas",
26
+ "usercommitments",
27
+ "frictionlesstokens",
28
+ "pendings"
29
+ ];
30
+ const migrateIpInCaptchaRecordsCommand = (pair, config, logger) => {
31
+ logger = logger || common.getLogger(common.LogLevel.enum.info, "cli.migrate_ip_in_captcha_records");
32
+ return {
33
+ command: "migrateIpInCaptchaRecords",
34
+ describe: "Migrate IP addresses in captcha records",
35
+ builder: (yargs) => yargs.option("uri", {
36
+ type: "string",
37
+ desc: "DB Uri. When skipped, used the default connection based on the current environment"
38
+ }),
39
+ handler: async (argv) => {
40
+ const uri = z__namespace.string().parse(argv.uri || "");
41
+ try {
42
+ const db = await getDb.getDb(pair, config, uri, logger);
43
+ await migrateIpField.migrateIpField(db, collectionsToUpgrade, logger);
44
+ logger.info(() => ({
45
+ msg: "migration completed"
46
+ }));
47
+ } catch (err) {
48
+ logger.error(() => ({
49
+ err,
50
+ msg: "Error migrating captcha records"
51
+ }));
52
+ }
53
+ }
54
+ };
55
+ };
56
+ exports.migrateIpInCaptchaRecordsCommand = migrateIpInCaptchaRecordsCommand;
@@ -3,6 +3,7 @@ const common = require("@prosopo/common");
3
3
  const types = require("@prosopo/types");
4
4
  const RateLimiter = require("./RateLimiter.cjs");
5
5
  const process_env = require("./process.env.cjs");
6
+ var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
6
7
  function getMongoURI() {
7
8
  const protocol = process.env.PROSOPO_DATABASE_PROTOCOL || "mongodb";
8
9
  const mongoSrv = protocol === "mongodb+srv";
@@ -24,9 +25,14 @@ const getLRules = () => {
24
25
  return {};
25
26
  }
26
27
  };
28
+ const getHost = () => {
29
+ const importMeta = { url: typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("prosopo.config.cjs", document.baseURI).href };
30
+ return process.env.CADDY_DOMAIN || importMeta.env?.VITE_CADDY_DOMAIN;
31
+ };
27
32
  function getConfig(captchaSolutionsConfig, captchaServeConfig, who = "PROVIDER", admin = "ADMIN") {
28
33
  return types.ProsopoConfigSchema.parse({
29
34
  logLevel: common.parseLogLevel(process.env.PROSOPO_LOG_LEVEL, "info"),
35
+ host: getHost(),
30
36
  defaultEnvironment: process.env.PROSOPO_DEFAULT_ENVIRONMENT ? types.EnvironmentTypesSchema.parse(process.env.PROSOPO_DEFAULT_ENVIRONMENT) : types.EnvironmentTypesSchema.enum.development,
31
37
  account: {
32
38
  address: process_env.getAddress(who),
@@ -61,7 +67,8 @@ function getConfig(captchaSolutionsConfig, captchaServeConfig, who = "PROVIDER",
61
67
  captchas: captchaServeConfig,
62
68
  penalties: types.FrictionlessPenalties.parse({
63
69
  PENALTY_OLD_TIMESTAMP: process.env.PENALTY_OLD_TIMESTAMP,
64
- PENALTY_ACCESS_RULE: process.env.PENALTY_ACCESS_RULE
70
+ PENALTY_ACCESS_RULE: process.env.PENALTY_ACCESS_RULE,
71
+ PENALTY_UNVERIFIED_HOST: process.env.PENALTY_UNVERIFIED_HOST
65
72
  }),
66
73
  mongoEventsUri: process.env.PROSOPO_MONGO_EVENTS_URI || "",
67
74
  mongoCaptchaUri: process.env.PROSOPO_MONGO_CAPTCHA_URI || "",
@@ -85,6 +92,10 @@ function getConfig(captchaSolutionsConfig, captchaServeConfig, who = "PROVIDER",
85
92
  address: process_env.getAddress(admin),
86
93
  password: process_env.getPassword(admin),
87
94
  secret: process_env.getSecret(admin)
95
+ },
96
+ ipApi: {
97
+ apiKey: process.env.PROSOPO_IPAPI_KEY,
98
+ baseUrl: process.env.PROSOPO_IPAPI_URL
88
99
  }
89
100
  });
90
101
  }
@@ -22,7 +22,6 @@ class ReloadingAPI {
22
22
  }
23
23
  async start(reloadEnv = false) {
24
24
  log.info(() => ({ msg: "Starting API" }));
25
- this._envWatcher = await this._watchEnv();
26
25
  dotenv.loadEnv();
27
26
  if (!this._env || reloadEnv) {
28
27
  this._env = new env.ProviderEnvironment(
@@ -33,6 +32,9 @@ class ReloadingAPI {
33
32
  }
34
33
  await this.env.isReady();
35
34
  this.api = await start.start(this.env, !!this._processedArgs.adminApi);
35
+ if (process.env.NODE_ENV === "development") {
36
+ this._envWatcher = await this._watchEnv();
37
+ }
36
38
  }
37
39
  async stop() {
38
40
  log.info(() => ({ msg: "Stopping API" }));
@@ -43,7 +45,7 @@ class ReloadingAPI {
43
45
  });
44
46
  }
45
47
  async _watchEnv() {
46
- return fs.watchFile(this._envPath, async () => {
48
+ return fs.watch(this._envPath, async () => {
47
49
  log.info(() => ({
48
50
  data: { restarting: this._restarting },
49
51
  msg: "env file change detected. Restarting"
@@ -23,7 +23,7 @@ const getClientApiPathsExcludingVerify = () => {
23
23
  async function startApi(env2, admin = false, port) {
24
24
  env2.logger.info(() => ({ msg: "Starting Prosopo API" }));
25
25
  const apiApp = express();
26
- const apiPort = port || env2.config.server.port;
26
+ const apiPort = port || env2.config.server?.port;
27
27
  const apiEndpointAdapter = apiExpressRouter.createApiExpressDefaultEndpointAdapter(
28
28
  common.parseLogLevel(env2.config.logLevel)
29
29
  );
@@ -36,13 +36,10 @@ async function startApi(env2, admin = false, port) {
36
36
  msg: "Adding headerCheckMiddleware",
37
37
  paths: clientPathsExcludingVerify
38
38
  }));
39
- apiApp.set(
40
- "trust proxy",
41
- env2.config.proxyCount
42
- );
39
+ apiApp.set("trust proxy", 1);
43
40
  apiApp.use(cors());
44
41
  apiApp.use(express.json({ limit: "50mb" }));
45
- apiApp.use(provider.publicRouter());
42
+ apiApp.use(provider.publicRouter(env2));
46
43
  const i18Middleware = await locale.i18nMiddleware({});
47
44
  apiApp.use(provider.robotsMiddleware());
48
45
  apiApp.use(provider.ignoreMiddleware());
@@ -50,15 +47,15 @@ async function startApi(env2, admin = false, port) {
50
47
  apiApp.use(i18Middleware);
51
48
  apiApp.use(provider.ja4Middleware(env2));
52
49
  apiApp.use(provider.prosopoVerifyRouter(env2));
53
- apiApp.use(provider.blockMiddleware(env2));
54
50
  apiApp.use(clientPathsExcludingVerify, provider.headerCheckMiddleware(env2));
55
- apiApp.use("/v1/prosopo/provider/client/", provider.domainMiddleware(env2));
56
- apiApp.use(provider.prosopoRouter(env2));
57
51
  env2.logger.info(() => ({ msg: "Enabling admin auth middleware" }));
58
52
  apiApp.use(
59
53
  "/v1/prosopo/provider/admin",
60
54
  apiExpressRouter.authMiddleware(env2.pair, env2.authAccount)
61
55
  );
56
+ apiApp.use(provider.blockMiddleware(env2));
57
+ apiApp.use("/v1/prosopo/provider/client/", provider.domainMiddleware(env2));
58
+ apiApp.use(provider.prosopoRouter(env2));
62
59
  const userAccessRuleRoutes = apiRuleRoutesProvider.getRoutes();
63
60
  for (const userAccessRuleRoute of userAccessRuleRoutes) {
64
61
  apiApp.use(
@@ -105,10 +102,18 @@ async function start(env$1, admin, port) {
105
102
  unsolved: { count: 0 }
106
103
  });
107
104
  const pair = keyring.getPair(secret);
108
- const authAccount = keyring.getPair(void 0, config.authAccount.address);
105
+ let authAccount;
106
+ if (config.authAccount) {
107
+ authAccount = keyring.getPair(void 0, config.authAccount.address);
108
+ }
109
109
  env$1 = new env.ProviderEnvironment(config, pair, authAccount);
110
110
  } else {
111
- env$1.logger.debug(() => ({ msg: "Env already defined" }));
111
+ env$1.logger.debug(() => ({
112
+ msg: "Env already defined",
113
+ data: {
114
+ config: env$1?.config
115
+ }
116
+ }));
112
117
  }
113
118
  await env$1.isReady();
114
119
  env$1.cleanup();
@@ -0,0 +1,29 @@
1
+ import { getLogger, LogLevel } from "@prosopo/common";
2
+ import { ProviderEnvironment } from "@prosopo/env";
3
+ import { Tasks } from "@prosopo/provider";
4
+ const commandEnsureExternalIndexes = (pair, config, cmdArgs) => {
5
+ const logger = cmdArgs?.logger || getLogger(LogLevel.enum.info, "cli.ensure_external_indexes");
6
+ return {
7
+ command: "ensure_external_indexes",
8
+ describe: "Ensure indexes for external database",
9
+ handler: async () => {
10
+ try {
11
+ const env = new ProviderEnvironment(config, pair);
12
+ await env.isReady();
13
+ const tasks = new Tasks(env);
14
+ if (!env.config.mongoCaptchaUri) {
15
+ throw new Error("mongoCaptchaUri not set in config");
16
+ }
17
+ await tasks.clientTaskManager.getCaptchaDB(env.config.mongoCaptchaUri).ensureIndexes().catch((err) => {
18
+ env.logger.error(() => ({ err }));
19
+ });
20
+ } catch (err) {
21
+ logger.error(() => ({ err }));
22
+ }
23
+ },
24
+ middlewares: []
25
+ };
26
+ };
27
+ export {
28
+ commandEnsureExternalIndexes as default
29
+ };
@@ -0,0 +1,27 @@
1
+ import { getLogger, LogLevel } from "@prosopo/common";
2
+ import { ProviderEnvironment } from "@prosopo/env";
3
+ import { Tasks } from "@prosopo/provider";
4
+ const commandEnsureIndexes = (pair, config, cmdArgs) => {
5
+ const logger = cmdArgs?.logger || getLogger(LogLevel.enum.info, "cli.ensure_indexes");
6
+ return {
7
+ command: "ensure_indexes",
8
+ describe: "Ensure indexes for internal database",
9
+ handler: async () => {
10
+ try {
11
+ const env = new ProviderEnvironment(config, pair);
12
+ await env.isReady();
13
+ const tasks = new Tasks(env);
14
+ if (!env.config.mongoCaptchaUri) {
15
+ throw new Error("mongoCaptchaUri not set in config");
16
+ }
17
+ await tasks.db.ensureIndexes();
18
+ } catch (err) {
19
+ logger.error(() => ({ err }));
20
+ }
21
+ },
22
+ middlewares: []
23
+ };
24
+ };
25
+ export {
26
+ commandEnsureIndexes as default
27
+ };
@@ -3,7 +3,11 @@ import { default as default3 } from "./storeCaptchasExternally.js";
3
3
  import { default as default4 } from "./version.js";
4
4
  import { default as default5 } from "./siteKeyRegister.js";
5
5
  import { default as default6 } from "./siteKeyRegisterApi.js";
6
+ import { default as default7 } from "./ensureExternalIndexes.js";
7
+ import { default as default8 } from "./ensureIndexes.js";
6
8
  export {
9
+ default7 as commandEnsureExternalIndexes,
10
+ default8 as commandEnsureIndexes,
7
11
  default2 as commandProviderSetDataset,
8
12
  default5 as commandSiteKeyRegister,
9
13
  default6 as commandSiteKeyRegisterApi,
@@ -0,0 +1,32 @@
1
+ import { ProviderEnvironment } from "@prosopo/env";
2
+ import mongoose from "mongoose";
3
+ const getDb = async (pair, config, uri, logger) => {
4
+ let db;
5
+ if (uri) {
6
+ logger.info(() => ({
7
+ msg: "Using DB connection from the URI"
8
+ }));
9
+ db = await getByUri(uri);
10
+ } else {
11
+ logger.info(() => ({
12
+ msg: "Using DB connection from the config"
13
+ }));
14
+ db = await getByConfig(pair, config);
15
+ }
16
+ if (db) {
17
+ return db;
18
+ }
19
+ throw new Error("Db connection cannot be established");
20
+ };
21
+ const getByUri = async (uri) => {
22
+ await mongoose.connect(uri);
23
+ return mongoose.connection.db;
24
+ };
25
+ const getByConfig = async (pair, config) => {
26
+ const env = new ProviderEnvironment(config, pair);
27
+ await env.isReady();
28
+ return env.db?.getConnection()?.db;
29
+ };
30
+ export {
31
+ getDb
32
+ };
@@ -0,0 +1,98 @@
1
+ import { getCompositeIpAddress } from "@prosopo/provider";
2
+ import { IpAddressType } from "@prosopo/types-database";
3
+ import { Address6 } from "ip-address";
4
+ import { Decimal128 } from "mongodb";
5
+ const MAX_IPV4_NUMERIC = 4294967295;
6
+ const BATCH_SIZE = 1e5;
7
+ const migrateIpField = async (db, collectionsToUpgrade, logger) => {
8
+ for (const collection of collectionsToUpgrade) {
9
+ await migrateV4Records(db, collection, logger);
10
+ await migrateV6Records(db, collection, logger);
11
+ }
12
+ };
13
+ const migrateV4Records = async (db, collection, logger) => {
14
+ const searchArgs = {
15
+ ipAddress: {
16
+ $type: "number",
17
+ $lte: Number(MAX_IPV4_NUMERIC)
18
+ }
19
+ };
20
+ let totalModified = 0;
21
+ let processed = 0;
22
+ const count = await db.collection(collection).countDocuments(searchArgs);
23
+ while (true) {
24
+ const docs = await db.collection(collection).find(searchArgs, { projection: { ipAddress: 1 } }).limit(BATCH_SIZE).toArray();
25
+ if (docs.length === 0) break;
26
+ const operations = docs.map((doc) => ({
27
+ updateOne: {
28
+ filter: { _id: doc._id },
29
+ update: {
30
+ $set: {
31
+ ipAddress: {
32
+ lower: doc.ipAddress,
33
+ type: IpAddressType.v4
34
+ }
35
+ }
36
+ }
37
+ }
38
+ }));
39
+ const bulkResult = await db.collection(collection).bulkWrite(operations, { ordered: false });
40
+ totalModified += bulkResult?.modifiedCount || 0;
41
+ processed += docs.length;
42
+ logger.info(() => ({
43
+ msg: `Migrated v4 batch (${docs.length}) [${processed}/${count}] in "${collection}"`
44
+ }));
45
+ }
46
+ logger.info(() => ({
47
+ msg: `Migrated ${count} v4 records (${totalModified} modified) in "${collection}" collection`
48
+ }));
49
+ };
50
+ const migrateV6Records = async (db, collection, logger) => {
51
+ const searchArgs = {
52
+ ipAddress: {
53
+ $type: "number",
54
+ $gt: Number(MAX_IPV4_NUMERIC)
55
+ }
56
+ };
57
+ let totalModified = 0;
58
+ let processed = 0;
59
+ const count = await db.collection(collection).countDocuments(searchArgs);
60
+ while (true) {
61
+ const docs = await db.collection(collection).find(searchArgs, { projection: { ipAddress: 1 } }).limit(BATCH_SIZE).toArray();
62
+ if (docs.length === 0) break;
63
+ const operations = docs.map((doc) => {
64
+ const ipAddress = Address6.fromBigInt(BigInt(doc.ipAddress));
65
+ const compositeIpAddress = getCompositeIpAddress(ipAddress);
66
+ return {
67
+ updateOne: {
68
+ filter: { _id: doc._id },
69
+ update: {
70
+ $set: {
71
+ ipAddress: {
72
+ lower: Decimal128.fromString(
73
+ compositeIpAddress.lower.toString()
74
+ ),
75
+ upper: Decimal128.fromString(
76
+ (compositeIpAddress.upper || 0n).toString()
77
+ ),
78
+ type: IpAddressType.v6
79
+ }
80
+ }
81
+ }
82
+ }
83
+ };
84
+ });
85
+ const bulkResult = await db.collection(collection).bulkWrite(operations, { ordered: false });
86
+ totalModified += bulkResult?.modifiedCount || 0;
87
+ processed += docs.length;
88
+ logger.info(() => ({
89
+ msg: `Migrated v6 batch (${docs.length}) [${processed}/${count}] in "${collection}"`
90
+ }));
91
+ }
92
+ logger.info(() => ({
93
+ msg: `Migrated ${count} v6 records (${totalModified} modified) in "${collection}"`
94
+ }));
95
+ };
96
+ export {
97
+ migrateIpField
98
+ };
@@ -0,0 +1,39 @@
1
+ import { getLogger, LogLevel } from "@prosopo/common";
2
+ import * as z from "zod";
3
+ import { getDb } from "./getDb.js";
4
+ import { migrateIpField } from "./migrateIpField.js";
5
+ const collectionsToUpgrade = [
6
+ "powcaptchas",
7
+ "usercommitments",
8
+ "frictionlesstokens",
9
+ "pendings"
10
+ ];
11
+ const migrateIpInCaptchaRecordsCommand = (pair, config, logger) => {
12
+ logger = logger || getLogger(LogLevel.enum.info, "cli.migrate_ip_in_captcha_records");
13
+ return {
14
+ command: "migrateIpInCaptchaRecords",
15
+ describe: "Migrate IP addresses in captcha records",
16
+ builder: (yargs) => yargs.option("uri", {
17
+ type: "string",
18
+ desc: "DB Uri. When skipped, used the default connection based on the current environment"
19
+ }),
20
+ handler: async (argv) => {
21
+ const uri = z.string().parse(argv.uri || "");
22
+ try {
23
+ const db = await getDb(pair, config, uri, logger);
24
+ await migrateIpField(db, collectionsToUpgrade, logger);
25
+ logger.info(() => ({
26
+ msg: "migration completed"
27
+ }));
28
+ } catch (err) {
29
+ logger.error(() => ({
30
+ err,
31
+ msg: "Error migrating captcha records"
32
+ }));
33
+ }
34
+ }
35
+ };
36
+ };
37
+ export {
38
+ migrateIpInCaptchaRecordsCommand
39
+ };
@@ -23,9 +23,14 @@ const getLRules = () => {
23
23
  return {};
24
24
  }
25
25
  };
26
+ const getHost = () => {
27
+ const importMeta = import.meta;
28
+ return process.env.CADDY_DOMAIN || importMeta.env?.VITE_CADDY_DOMAIN;
29
+ };
26
30
  function getConfig(captchaSolutionsConfig, captchaServeConfig, who = "PROVIDER", admin = "ADMIN") {
27
31
  return ProsopoConfigSchema.parse({
28
32
  logLevel: parseLogLevel(process.env.PROSOPO_LOG_LEVEL, "info"),
33
+ host: getHost(),
29
34
  defaultEnvironment: process.env.PROSOPO_DEFAULT_ENVIRONMENT ? EnvironmentTypesSchema.parse(process.env.PROSOPO_DEFAULT_ENVIRONMENT) : EnvironmentTypesSchema.enum.development,
30
35
  account: {
31
36
  address: getAddress(who),
@@ -60,7 +65,8 @@ function getConfig(captchaSolutionsConfig, captchaServeConfig, who = "PROVIDER",
60
65
  captchas: captchaServeConfig,
61
66
  penalties: FrictionlessPenalties.parse({
62
67
  PENALTY_OLD_TIMESTAMP: process.env.PENALTY_OLD_TIMESTAMP,
63
- PENALTY_ACCESS_RULE: process.env.PENALTY_ACCESS_RULE
68
+ PENALTY_ACCESS_RULE: process.env.PENALTY_ACCESS_RULE,
69
+ PENALTY_UNVERIFIED_HOST: process.env.PENALTY_UNVERIFIED_HOST
64
70
  }),
65
71
  mongoEventsUri: process.env.PROSOPO_MONGO_EVENTS_URI || "",
66
72
  mongoCaptchaUri: process.env.PROSOPO_MONGO_CAPTCHA_URI || "",
@@ -84,6 +90,10 @@ function getConfig(captchaSolutionsConfig, captchaServeConfig, who = "PROVIDER",
84
90
  address: getAddress(admin),
85
91
  password: getPassword(admin),
86
92
  secret: getSecret(admin)
93
+ },
94
+ ipApi: {
95
+ apiKey: process.env.PROSOPO_IPAPI_KEY,
96
+ baseUrl: process.env.PROSOPO_IPAPI_URL
87
97
  }
88
98
  });
89
99
  }
package/dist/reloader.js CHANGED
@@ -21,7 +21,6 @@ class ReloadingAPI {
21
21
  }
22
22
  async start(reloadEnv = false) {
23
23
  log.info(() => ({ msg: "Starting API" }));
24
- this._envWatcher = await this._watchEnv();
25
24
  loadEnv();
26
25
  if (!this._env || reloadEnv) {
27
26
  this._env = new ProviderEnvironment(
@@ -32,6 +31,9 @@ class ReloadingAPI {
32
31
  }
33
32
  await this.env.isReady();
34
33
  this.api = await start(this.env, !!this._processedArgs.adminApi);
34
+ if (process.env.NODE_ENV === "development") {
35
+ this._envWatcher = await this._watchEnv();
36
+ }
35
37
  }
36
38
  async stop() {
37
39
  log.info(() => ({ msg: "Stopping API" }));
@@ -42,7 +44,7 @@ class ReloadingAPI {
42
44
  });
43
45
  }
44
46
  async _watchEnv() {
45
- return fs.watchFile(this._envPath, async () => {
47
+ return fs.watch(this._envPath, async () => {
46
48
  log.info(() => ({
47
49
  data: { restarting: this._restarting },
48
50
  msg: "env file change detected. Restarting"
package/dist/start.js CHANGED
@@ -4,7 +4,7 @@ import { loadEnv } from "@prosopo/dotenv";
4
4
  import { ProviderEnvironment } from "@prosopo/env";
5
5
  import { getPair } from "@prosopo/keyring";
6
6
  import { i18nMiddleware } from "@prosopo/locale";
7
- import { createApiAdminRoutesProvider, publicRouter, robotsMiddleware, ignoreMiddleware, ja4Middleware, prosopoVerifyRouter, blockMiddleware, headerCheckMiddleware, domainMiddleware, prosopoRouter, storeCaptchasExternally, getClientList } from "@prosopo/provider";
7
+ import { createApiAdminRoutesProvider, publicRouter, robotsMiddleware, ignoreMiddleware, ja4Middleware, prosopoVerifyRouter, headerCheckMiddleware, blockMiddleware, domainMiddleware, prosopoRouter, storeCaptchasExternally, getClientList } from "@prosopo/provider";
8
8
  import { ClientApiPaths } from "@prosopo/types";
9
9
  import { createApiRuleRoutesProvider, getExpressApiRuleRateLimits } from "@prosopo/user-access-policy";
10
10
  import cors from "cors";
@@ -21,7 +21,7 @@ const getClientApiPathsExcludingVerify = () => {
21
21
  async function startApi(env, admin = false, port) {
22
22
  env.logger.info(() => ({ msg: "Starting Prosopo API" }));
23
23
  const apiApp = express();
24
- const apiPort = port || env.config.server.port;
24
+ const apiPort = port || env.config.server?.port;
25
25
  const apiEndpointAdapter = createApiExpressDefaultEndpointAdapter(
26
26
  parseLogLevel(env.config.logLevel)
27
27
  );
@@ -34,13 +34,10 @@ async function startApi(env, admin = false, port) {
34
34
  msg: "Adding headerCheckMiddleware",
35
35
  paths: clientPathsExcludingVerify
36
36
  }));
37
- apiApp.set(
38
- "trust proxy",
39
- env.config.proxyCount
40
- );
37
+ apiApp.set("trust proxy", 1);
41
38
  apiApp.use(cors());
42
39
  apiApp.use(express.json({ limit: "50mb" }));
43
- apiApp.use(publicRouter());
40
+ apiApp.use(publicRouter(env));
44
41
  const i18Middleware = await i18nMiddleware({});
45
42
  apiApp.use(robotsMiddleware());
46
43
  apiApp.use(ignoreMiddleware());
@@ -48,15 +45,15 @@ async function startApi(env, admin = false, port) {
48
45
  apiApp.use(i18Middleware);
49
46
  apiApp.use(ja4Middleware(env));
50
47
  apiApp.use(prosopoVerifyRouter(env));
51
- apiApp.use(blockMiddleware(env));
52
48
  apiApp.use(clientPathsExcludingVerify, headerCheckMiddleware(env));
53
- apiApp.use("/v1/prosopo/provider/client/", domainMiddleware(env));
54
- apiApp.use(prosopoRouter(env));
55
49
  env.logger.info(() => ({ msg: "Enabling admin auth middleware" }));
56
50
  apiApp.use(
57
51
  "/v1/prosopo/provider/admin",
58
52
  authMiddleware(env.pair, env.authAccount)
59
53
  );
54
+ apiApp.use(blockMiddleware(env));
55
+ apiApp.use("/v1/prosopo/provider/client/", domainMiddleware(env));
56
+ apiApp.use(prosopoRouter(env));
60
57
  const userAccessRuleRoutes = apiRuleRoutesProvider.getRoutes();
61
58
  for (const userAccessRuleRoute of userAccessRuleRoutes) {
62
59
  apiApp.use(
@@ -103,10 +100,18 @@ async function start(env, admin, port) {
103
100
  unsolved: { count: 0 }
104
101
  });
105
102
  const pair = getPair(secret);
106
- const authAccount = getPair(void 0, config.authAccount.address);
103
+ let authAccount;
104
+ if (config.authAccount) {
105
+ authAccount = getPair(void 0, config.authAccount.address);
106
+ }
107
107
  env = new ProviderEnvironment(config, pair, authAccount);
108
108
  } else {
109
- env.logger.debug(() => ({ msg: "Env already defined" }));
109
+ env.logger.debug(() => ({
110
+ msg: "Env already defined",
111
+ data: {
112
+ config: env?.config
113
+ }
114
+ }));
110
115
  }
111
116
  await env.isReady();
112
117
  env.cleanup();