Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
gruve-p committed Nov 11, 2024
2 parents 30be6f9 + 41f8a2f commit f00499a
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 34 deletions.
6 changes: 6 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,9 @@ BTCEXP_NO_RATES=false

# CDN base url; if S3 details are given, this will probably be a CloudFront path for assets that are uploaded at launch
#BTCEXP_CDN_BASE_URL=xxx

# Rate limiting
# Window size, in minutes, set to -1 to disable rate limiting
#BTCEXP_RATE_LIMIT_WINDOW_MINUTES=xx
# Window max requests allowed
#BTCEXP_RATE_LIMIT_WINDOW_MAX_REQUESTS=xxx
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
FROM node:16 as builder
FROM node:20 as builder
WORKDIR /workspace
COPY . .
RUN npm install

FROM node:16-alpine
FROM node:20-alpine
WORKDIR /workspace
COPY --from=builder /workspace .
RUN apk --update add git
Expand Down
59 changes: 33 additions & 26 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,35 +240,42 @@ expressApp.use(config.baseUrl, express.static(path.join(__dirname, 'public'), {


// https://www.npmjs.com/package/express-rate-limit
const rateLimitWindowMinutes = 15;
const rateLimitWindowMaxRequests = 200;
const rateLimiter = rateLimit({
windowMs: rateLimitWindowMinutes * 60 * 1000, // 15 minutes
limit: rateLimitWindowMaxRequests, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header
legacyHeaders: false, // Disable the `X-RateLimit-*` headers.
skip: function (req, res) {
if (req.originalUrl.includes("/snippet/")) {
return true;
}

if (req.originalUrl.includes("/api/")) {
return true;
}
const rateLimitWindowMinutes = config.rateLimiting.windowMinutes;
const rateLimitWindowMaxRequests = config.rateLimiting.windowMaxRequests;

if (rateLimitWindowMinutes == -1) {
debugLog("Disabling rate limiting");

} else {
debugLog(`Enabling rate limiting: ${rateLimitWindowMaxRequests} requests per ${rateLimitWindowMinutes}min`);

const rateLimiter = rateLimit({
windowMs: rateLimitWindowMinutes * 60 * 1000, // 15 minutes
limit: rateLimitWindowMaxRequests, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header
legacyHeaders: false, // Disable the `X-RateLimit-*` headers.
skip: function (req, res) {
if (req.originalUrl.includes("/snippet/")) {
return true;
}

return false;
},
handler: function (req, res, next) {
debugErrorLog(`Rate-limiting request: ip=${req.ip}, req=${req.originalUrl}`)
res.status(429).json({
message: "Too many requests, please try again later.",
});
}
});
if (req.originalUrl.includes("/api/")) {
return true;
}

// Apply the rate limiting middleware to all requests.
expressApp.use(rateLimiter);
return false;
},
handler: function (req, res, next) {
debugErrorLog(`Rate-limiting request: ip=${req.ip}, req=${req.originalUrl}`)
res.status(429).json({
message: "Too many requests, please try again later.",
});
}
});

// Apply the rate limiting middleware to all requests.
expressApp.use(rateLimiter);
}


if (config.baseUrl != '/') {
Expand Down
5 changes: 5 additions & 0 deletions app/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ module.exports = {
baseUrl: cdnBaseUrl
},

rateLimiting: {
windowMinutes: process.env.BTCEXP_RATE_LIMIT_WINDOW_MINUTES || 15,
windowMaxRequests: process.env.BTCEXP_RATE_LIMIT_WINDOW_MAX_REQUESTS || 200
},

rpcBlacklist:
process.env.BTCEXP_RPC_ALLOWALL.toLowerCase() == "true" ? []
: process.env.BTCEXP_RPC_BLACKLIST ? process.env.BTCEXP_RPC_BLACKLIST.split(',').filter(Boolean)
Expand Down
4 changes: 3 additions & 1 deletion app/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ const crawlerBotUserAgentStrings = {
"moz": new RegExp("dotbot", "i"),
"semrush": new RegExp("SemrushBot", "i"),
"majestic": new RegExp("MJ12bot", "i"),
"python-requests": new RegExp("python-requests", "i")
"python-requests": new RegExp("python-requests", "i"),
"openai": new RegExp("OAI-SearchBot", "i"),
"unidentifiedCrawler": new RegExp("Test Certificate Info", "i"),
};

const ipMemoryCache = {};
Expand Down
2 changes: 0 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: "3.7"

networks:
default:
driver: bridge
Expand Down
44 changes: 42 additions & 2 deletions routes/apiRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@ router.get("/blocks/tip", asyncHandler(async (req, res, next) => {
next();
}));

// undocumented, old url
router.get("/blocks/tip/height", asyncHandler(async (req, res, next) => {
try {
const getblockchaininfo = await coreApi.getBlockchainInfo();

res.send(String(getblockchaininfo.blocks));

} catch (e) {
utils.logError("234508ehede", e);

res.json({success: false});
}

next();
}));

router.get("/block/:hashOrHeight", asyncHandler(async (req, res, next) => {
const hashOrHeight = req.params.hashOrHeight;
let hash = (hashOrHeight.length == 64 ? hashOrHeight : null);
Expand Down Expand Up @@ -322,8 +338,32 @@ router.get("/blockchain/next-halving", asyncHandler(async (req, res, next) => {

/// ADDRESSES

// encountered huge volume of traffic requesting the balance for top address
// here, from many different ips, the below page leads me to believe the addresses
// are associated with malware and the public instance API is being abused to
// aid the malware - block the requests
// ref: https://pberba.github.io/crypto/2024/09/14/malicious-browser-extension-genesis-market/
const blacklistedAddresses = [
"bc1q4fkjqusxsgqzylcagra800cxljal82k6y3ejay",
"bc1qvmvz53hdauzxuhs7dkm775tlqtd9vpk8ux7mqj",
"bc1qtms60m4fxhp5v229kfxwd3xruu48c4a0tqwafu",
"bc1qvkvzfla6wrem2uf4ejkuja8yp3c6f3xf72kyc9",
"bc1qnxwt7sr3rqatd6efjyym3nsgxhslyzeqndhjpn"
];

router.get("/address/:address", asyncHandler(async (req, res, next) => {
try {
const address = utils.asAddress(req.params.address);

if (blacklistedAddresses.includes(address)) {
debugLog(`Blocking request: ip=${req.ip}, req=${req.originalUrl}`)
res.status(418).json({
message: "Teapot",
});

return;
}

const { perfId, perfResults } = utils.perfLogNewItem({action:"api.address"});
res.locals.perfId = perfId;

Expand All @@ -347,8 +387,6 @@ router.get("/address/:address", asyncHandler(async (req, res, next) => {
}


const address = utils.asAddress(req.params.address);

const transactions = [];
const addressApiSupport = addressApi.getCurrentAddressApiFeatureSupport();

Expand Down Expand Up @@ -465,6 +503,8 @@ router.get("/address/:address", asyncHandler(async (req, res, next) => {
next();

} catch (e) {
utils.logError("a39ehudsudese", e);

res.json({success:false});

next();
Expand Down
9 changes: 8 additions & 1 deletion routes/baseRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ router.get("/block-stats", asyncHandler(async (req, res, next) => {

router.get("/mining-template", asyncHandler(async (req, res, next) => {
// url changed
res.redirect("./next-block");
res.redirect(301, "./next-block");
}));

router.get("/next-block", asyncHandler(async (req, res, next) => {
Expand Down Expand Up @@ -1360,6 +1360,13 @@ router.get("/block-analysis", function(req, res, next) {
next();
});

/*
router.get("/tx/tx/:transactionId", asyncHandler(async (req, res, next) => {
res.redirect(301, `${config.baseUrl}tx/${req.params.transactionId}`);
return;
}));*/

router.get("/tx/:transactionId@:blockHeight", asyncHandler(async (req, res, next) => {
req.query.blockHeight = req.params.blockHeight;
req.url = "/tx/" + req.params.transactionId;
Expand Down

0 comments on commit f00499a

Please sign in to comment.