mirror of
https://github.com/jason5ng32/MyIP.git
synced 2026-11-04 08:55:47 +00:00
Improvements
This commit is contained in:
1 parent
2b20d9d41e
commit
af7f5e1d64
6 files changed
+46
-4
No files matched your search
+2
-1
@@ -22,7 +22,8 @@ function domainHasWhoisText(result) {
|
||||
|
||||
export default async (req, res) => {
|
||||
const query = req.query.q;
|
||||
if (!query) {
|
||||
// typeof check also rejects the array form (?q=a&q=b) express produces.
|
||||
if (!query || typeof query !== 'string') {
|
||||
return res.status(400).json({ error: 'No address provided' });
|
||||
}
|
||||
if (!isValidIP(query) && !isValidDomain(query)) {
|
||||
|
||||
+12
-2
@@ -13,6 +13,7 @@ import logger from '../common/logger.js';
|
||||
// the DSN the SDK was configured with. Returns a URL or null. Exported for
|
||||
// tests.
|
||||
export const parseEnvelopeDsn = (rawBody) => {
|
||||
if (!Buffer.isBuffer(rawBody)) return null;
|
||||
try {
|
||||
const text = rawBody.toString('utf8');
|
||||
const newline = text.indexOf('\n');
|
||||
@@ -43,6 +44,7 @@ const USER_ITEM_TYPES = new Set(['event', 'transaction', 'replay_event', 'feedba
|
||||
// parse trouble returns the body unchanged: losing an IP is acceptable,
|
||||
// losing the event is not. Exported for tests.
|
||||
export const injectUserIp = (rawBody, ip) => {
|
||||
if (!Buffer.isBuffer(rawBody)) return rawBody;
|
||||
const NL = 0x0a;
|
||||
try {
|
||||
const headerEnd = rawBody.indexOf(NL);
|
||||
@@ -103,7 +105,15 @@ export default async (req, res) => {
|
||||
return res.status(404).json({ error: 'Tunnel not configured' });
|
||||
}
|
||||
|
||||
const dsn = parseEnvelopeDsn(req.body);
|
||||
// express.raw always yields a Buffer here, but guard anyway so a
|
||||
// misconfigured parser (string / array body) can't reach the byte-level
|
||||
// envelope walk below.
|
||||
const rawBody = req.body;
|
||||
if (!Buffer.isBuffer(rawBody)) {
|
||||
return res.status(400).json({ error: 'Invalid envelope' });
|
||||
}
|
||||
|
||||
const dsn = parseEnvelopeDsn(rawBody);
|
||||
if (!dsn) {
|
||||
return res.status(400).json({ error: 'Invalid envelope' });
|
||||
}
|
||||
@@ -113,7 +123,7 @@ export default async (req, res) => {
|
||||
|
||||
const visitorIp = visitorIpFrom(req.headers);
|
||||
|
||||
const body = visitorIp ? injectUserIp(req.body, visitorIp) : req.body;
|
||||
const body = visitorIp ? injectUserIp(rawBody, visitorIp) : rawBody;
|
||||
|
||||
try {
|
||||
const projectId = dsn.pathname.replace(/^\//, '');
|
||||
|
||||
@@ -80,6 +80,7 @@ export async function rdapDomain(domain, { timeoutMs = 5000 } = {}) {
|
||||
// Numeric value of an IP for prefix math. Returns null on junk — callers
|
||||
// validate first, but bootstrap CIDR bases also pass through here.
|
||||
const ipToBigInt = (ip) => {
|
||||
if (typeof ip !== 'string') return null;
|
||||
if (!ip.includes(':')) {
|
||||
const parts = ip.split('.');
|
||||
if (parts.length !== 4) return null;
|
||||
|
||||
@@ -115,6 +115,13 @@ watch(() => store.allHasLoaded, (newVal) => {
|
||||
if (newVal) getUserInfo();
|
||||
});
|
||||
|
||||
// The unknown-auth-hint boot resolves sign-in AFTER allHasLoaded (background
|
||||
// probe in main.js), so the watcher above already ran and skipped; retry when
|
||||
// the signed-in state lands. getUserInfo self-guards against double fetches.
|
||||
watch(isSignedIn, (signed) => {
|
||||
if (signed && store.allHasLoaded) getUserInfo();
|
||||
});
|
||||
|
||||
watch(() => triggerUserBenefits.value, (newVal) => {
|
||||
if (newVal) openUserBenefits();
|
||||
});
|
||||
|
||||
@@ -22,7 +22,12 @@ const loadFirebaseAuth = () => {
|
||||
]).then(([{ initializeApp }, authModule]) => ({
|
||||
...authModule,
|
||||
auth: authModule.getAuth(initializeApp(firebaseConfig)),
|
||||
}));
|
||||
})).catch((error) => {
|
||||
// Don't memoize a transient chunk-load failure — the next auth
|
||||
// action should retry the import instead of replaying the rejection.
|
||||
authModulePromise = null;
|
||||
throw error;
|
||||
});
|
||||
return authModulePromise;
|
||||
};
|
||||
|
||||
|
||||
@@ -37,6 +37,18 @@ test('parseEnvelopeDsn returns null for garbage input', () => {
|
||||
assert.strictEqual(parseEnvelopeDsn(Buffer.from('{"no_dsn":1}\n{}')), null);
|
||||
});
|
||||
|
||||
test('parseEnvelopeDsn returns null for non-Buffer input', () => {
|
||||
assert.strictEqual(parseEnvelopeDsn(`{"dsn":"${OUR_DSN}"}\n{}`), null);
|
||||
assert.strictEqual(parseEnvelopeDsn(undefined), null);
|
||||
});
|
||||
|
||||
test('returns 400 when the body is not a Buffer', async () => {
|
||||
process.env.VITE_SENTRY_DSN_FRONTEND = OUR_DSN;
|
||||
const res = makeRes();
|
||||
await tunnelHandler({ method: 'POST', body: `{"dsn":"${OUR_DSN}"}\n{}` }, res);
|
||||
assert.strictEqual(res.statusCode, 400);
|
||||
});
|
||||
|
||||
test('rejects non-POST methods with 405', async () => {
|
||||
const res = makeRes();
|
||||
await tunnelHandler({ method: 'GET' }, res);
|
||||
@@ -146,6 +158,12 @@ test('injectUserIp leaves non-event items byte-identical', () => {
|
||||
assert.deepStrictEqual(JSON.parse(items[1][1]).user, { ip_address: IP });
|
||||
});
|
||||
|
||||
test('injectUserIp returns non-Buffer bodies unchanged', () => {
|
||||
const str = '{"dsn":"x"}\n{"type":"event"}\n{}';
|
||||
assert.strictEqual(injectUserIp(str, IP), str);
|
||||
assert.strictEqual(injectUserIp(undefined, IP), undefined);
|
||||
});
|
||||
|
||||
test('injectUserIp returns malformed bodies unchanged', () => {
|
||||
const headerOnly = Buffer.from('{"dsn":"x"}');
|
||||
assert.strictEqual(injectUserIp(headerOnly, IP), headerOnly);
|
||||
|
||||
Reference in new issue
Block a user