Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] adds blockaid scan site service and route #99

Merged
merged 7 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env-EXAMPLE
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ MODE=not-set
USE_MERCURY=not-set
MERCURY_INTEGRITY_CHECK_ACCOUNT_EMAIL=not-set
MERCURY_INTEGRITY_CHECK_ACCOUNT_PASS=not-set
SENTRY_KEY=not-set
SENTRY_KEY=not-set
BLOCKAID_KEY=not-set
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"node": ">=18.12.0"
},
"dependencies": {
"@blockaid/client": "^0.11.0",
"@fastify/cors": "^8.5.0",
"@fastify/helmet": "^11.1.1",
"@fastify/rate-limit": "^8.0.3",
Expand Down
2 changes: 2 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const ENV_KEYS = [
"USE_MERCURY",
"MERCURY_INTEGRITY_CHECK_ACCOUNT_EMAIL",
"MERCURY_INTEGRITY_CHECK_ACCOUNT_PASS",
"BLOCKAID_KEY",
];

export function buildConfig(config: Record<string, string | undefined>) {
Expand All @@ -30,6 +31,7 @@ export function buildConfig(config: Record<string, string | undefined>) {
}

return {
blockAidKey: config.BLOCKAID_KEY || process.env.BLOCKAID_KEY!,
hostname: config.HOSTNAME || process.env.HOSTNAME!,
mercuryBackendTestnet: "https://api.mercurydata.app",
mercuryGraphQLTestnet: "https://api.mercurydata.app/graphql",
Expand Down
1 change: 1 addition & 0 deletions src/helper/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export const ERROR = {
CONTRACT_CODE: "contract code entry not found",
},
INVALID_RUN_MODE: "invalid run mode",
UNABLE_TO_SCAN_SITE: "unable to scan site using blockaid",
};
10 changes: 10 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import {
dataIntegrityCheckFail,
dataIntegrityCheckPass,
} from "./helper/metrics";
import Blockaid from "@blockaid/client";
import { fetchWithTimeout } from "./helper/fetch";
import { BlockAidService } from "./service/blockaid";

interface CliArgs {
env: string;
Expand Down Expand Up @@ -119,6 +122,12 @@ async function main() {
await redis.set(REDIS_USE_MERCURY_KEY, String(conf.useMercury));
}

const blockAidClient = new Blockaid({
apiKey: conf.blockAidKey,
fetch: fetchWithTimeout,
});
const blockAidService = new BlockAidService(blockAidClient, logger);

const mercuryClient = new MercuryClient(
mercurySession,
logger,
Expand All @@ -132,6 +141,7 @@ async function main() {
);
const server = await initApiServer(
mercuryClient,
blockAidService,
logger,
conf.useMercury,
conf.useSorobanPublic,
Expand Down
30 changes: 30 additions & 0 deletions src/route/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Networks } from "stellar-sdk-next";
import * as StellarSdk from "stellar-sdk";

import { MercuryClient } from "../service/mercury";
import { BlockAidService } from "../service/blockaid";
import { ajv } from "./validators";
import {
isContractId,
Expand All @@ -36,6 +37,7 @@ const API_VERSION = "v1";

export async function initApiServer(
mercuryClient: MercuryClient,
blockAidService: BlockAidService,
logger: Logger,
useMercuryConf: boolean,
useSorobanPublic: boolean,
Expand Down Expand Up @@ -504,6 +506,34 @@ export async function initApiServer(
},
});

instance.route({
method: "GET",
url: "/scan-dapp",
schema: {
querystring: {
["url"]: {
type: "string",
},
},
},
handler: async (
request: FastifyRequest<{
Querystring: {
["url"]: string;
};
}>,
reply
) => {
const { url } = request.query;
try {
const { data, error } = await blockAidService.scanDapp(url);
return reply.code(error ? 400 : 200).send({ data, error });
} catch (error) {
return reply.code(500).send(ERROR.SERVER_ERROR);
}
},
});

instance.route({
method: "POST",
url: "/subscription/token",
Expand Down
32 changes: 32 additions & 0 deletions src/service/blockaid/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Blockaid from "@blockaid/client";
import { Logger } from "pino";
import { ERROR } from "../../helper/error";

export class BlockAidService {
blockAidClient: Blockaid;
logger: Logger;
constructor(blockAidClient: Blockaid, logger: Logger) {
this.blockAidClient = blockAidClient;
this.logger = logger;
}

scanDapp = async (
url: string
): Promise<{
data: Blockaid.Site.SiteScanResponse | null;
error: string | null;
}> => {
try {
const data = await this.blockAidClient.site.scan({ url });

if (data.status === "miss") {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't add an explicit loop count to exit this because our fetch client will abort the request after 5 seconds. I was also thinking we may want to handle the misses out of the request lifecycle by making Freighter client poll another route which will check misses separately instead of keeping the request open like this does, thoughts?

return await this.scanDapp(url);
}

return { data, error: null };
} catch (error) {
this.logger.error(error);
return { data: null, error: ERROR.UNABLE_TO_SCAN_SITE };
}
};
}
103 changes: 102 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,20 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==

"@blockaid/client@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@blockaid/client/-/client-0.11.0.tgz#1fbc894d605eae0a8c8d7192ade4f344dd34946f"
integrity sha512-Lvg+lrQTDTBr03yKdrMOerjYovxEmWM5gUToO3Bbd5Qiybq4rBxoZBFvtBrg/vu5ENIA1f+jIo+1EI8TOktI4w==
dependencies:
"@types/node" "^18.11.18"
"@types/node-fetch" "^2.6.4"
abort-controller "^3.0.0"
agentkeepalive "^4.2.1"
form-data-encoder "1.7.2"
formdata-node "^4.3.2"
node-fetch "^2.6.7"
web-streams-polyfill "^3.2.1"

"@discoveryjs/json-ext@^0.5.0":
version "0.5.7"
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
Expand Down Expand Up @@ -1273,13 +1287,28 @@
dependencies:
"@types/node" "*"

"@types/node-fetch@^2.6.4":
version "2.6.11"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24"
integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==
dependencies:
"@types/node" "*"
form-data "^4.0.0"

"@types/node@*", "@types/node@^20.8.2":
version "20.8.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.7.tgz#ad23827850843de973096edfc5abc9e922492a25"
integrity sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==
dependencies:
undici-types "~5.25.1"

"@types/node@^18.11.18":
version "18.19.39"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.39.tgz#c316340a5b4adca3aee9dcbf05de385978590593"
integrity sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==
dependencies:
undici-types "~5.26.4"

"@types/pg-pool@2.0.4":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/pg-pool/-/pg-pool-2.0.4.tgz#b5c60f678094ff3acf3442628a7f708928fcf263"
Expand Down Expand Up @@ -1535,6 +1564,13 @@ acorn@^8.7.1, acorn@^8.8.2:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==

agentkeepalive@^4.2.1:
version "4.5.0"
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923"
integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==
dependencies:
humanize-ms "^1.2.1"

ajv-formats@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
Expand Down Expand Up @@ -2413,6 +2449,11 @@ follow-redirects@^1.15.6:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==

form-data-encoder@1.7.2:
version "1.7.2"
resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040"
integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==

form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
Expand All @@ -2422,6 +2463,14 @@ form-data@^4.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"

formdata-node@^4.3.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2"
integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==
dependencies:
node-domexception "1.0.0"
web-streams-polyfill "4.0.0-beta.3"

forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
Expand Down Expand Up @@ -2557,6 +2606,13 @@ human-signals@^5.0.0:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28"
integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==

humanize-ms@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==
dependencies:
ms "^2.0.0"

husky@^8.0.3:
version "8.0.3"
resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184"
Expand Down Expand Up @@ -3379,7 +3435,7 @@ ms@2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==

ms@^2.1.3:
ms@^2.0.0, ms@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
Expand All @@ -3405,6 +3461,18 @@ neo-async@^2.6.2:
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==

node-domexception@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==

node-fetch@^2.6.7:
version "2.7.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
dependencies:
whatwg-url "^5.0.0"

node-gyp-build@^4.8.0:
version "4.8.0"
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd"
Expand Down Expand Up @@ -4308,6 +4376,11 @@ toml@^3.0.0:
resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee"
integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==

tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==

ts-jest@^29.1.1:
version "29.1.1"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b"
Expand Down Expand Up @@ -4363,6 +4436,11 @@ undici-types@~5.25.1:
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3"
integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==

undici-types@~5.26.4:
version "5.26.5"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==

update-browserslist-db@^1.0.13:
version "1.0.13"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
Expand Down Expand Up @@ -4412,6 +4490,21 @@ watchpack@^2.4.0:
glob-to-regexp "^0.4.1"
graceful-fs "^4.1.2"

web-streams-polyfill@4.0.0-beta.3:
version "4.0.0-beta.3"
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38"
integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==

web-streams-polyfill@^3.2.1:
version "3.3.3"
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b"
integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==

webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==

webpack-cli@^5.1.4:
version "5.1.4"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b"
Expand Down Expand Up @@ -4480,6 +4573,14 @@ webpack@^5.88.2:
watchpack "^2.4.0"
webpack-sources "^3.2.3"

whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"

which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
Expand Down
Loading