diff --git a/CHANGELOG.md b/CHANGELOG.md index 5048ba4a..240e5bea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +3.0.3 / 2023-02-12 +------------------ +* agentが指定されている(もしくはagentが空のオブジェクトの)場合はプライベートIPのリクエストを許可 + 3.0.2 / 2023-02-12 ------------------ * Fastifyのルーティングを'/'から'*'に diff --git a/built/utils/got.js b/built/utils/got.js index f2f73bc5..da41680c 100644 --- a/built/utils/got.js +++ b/built/utils/got.js @@ -28,8 +28,8 @@ export async function scpaping(url, opts) { }, typeFilter: /^(text\/html|application\/xhtml\+xml)/, }); - // テスト用 - const allowPrivateIp = process.env.SUMMALY_ALLOW_PRIVATE_IP === 'true'; + // SUMMALY_ALLOW_PRIVATE_IPはテスト用 + const allowPrivateIp = process.env.SUMMALY_ALLOW_PRIVATE_IP === 'true' || Object.keys(agent).length > 0; if (!allowPrivateIp && response.ip && PrivateIp(response.ip)) { throw new StatusError(`Private IP rejected ${response.ip}`, 400, 'Private IP Rejected'); } diff --git a/built/utils/status-error.d.ts b/built/utils/status-error.d.ts index fe061081..13890647 100644 --- a/built/utils/status-error.d.ts +++ b/built/utils/status-error.d.ts @@ -1,4 +1,5 @@ export declare class StatusError extends Error { + name: string; statusCode: number; statusMessage?: string; isPermanentError: boolean; diff --git a/package.json b/package.json index 5a278bc5..0abeb86c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "summaly", - "version": "3.0.1", + "version": "3.0.3", "description": "Get web page's summary", "author": "syuilo ", "license": "MIT", diff --git a/src/utils/got.ts b/src/utils/got.ts index e3465c33..22fc0524 100644 --- a/src/utils/got.ts +++ b/src/utils/got.ts @@ -42,8 +42,8 @@ export async function scpaping(url: string, opts?: { lang?: string; }) { typeFilter: /^(text\/html|application\/xhtml\+xml)/, }); - // テスト用 - const allowPrivateIp = process.env.SUMMALY_ALLOW_PRIVATE_IP === 'true'; + // SUMMALY_ALLOW_PRIVATE_IPはテスト用 + const allowPrivateIp = process.env.SUMMALY_ALLOW_PRIVATE_IP === 'true' || Object.keys(agent).length > 0; if (!allowPrivateIp && response.ip && PrivateIp(response.ip)) { throw new StatusError(`Private IP rejected ${response.ip}`, 400, 'Private IP Rejected'); diff --git a/src/utils/status-error.ts b/src/utils/status-error.ts index 42c87460..4545acfe 100644 --- a/src/utils/status-error.ts +++ b/src/utils/status-error.ts @@ -1,4 +1,5 @@ export class StatusError extends Error { + public name: string; public statusCode: number; public statusMessage?: string; public isPermanentError: boolean; diff --git a/test/index.ts b/test/index.ts index 9553527e..0f2506fb 100644 --- a/test/index.ts +++ b/test/index.ts @@ -13,6 +13,9 @@ import { summaly } from '../src/index.js'; import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import {expect, jest, test, describe, beforeEach, afterEach} from '@jest/globals'; +import { Agent as httpAgent } from 'node:http'; +import { Agent as httpsAgent } from 'node:https'; +import { StatusError } from '../src/utils/status-error.js'; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); @@ -31,10 +34,14 @@ const host = `http://localhost:${port}`; // Display detail of unhandled promise rejection process.on('unhandledRejection', console.dir); -let app: ReturnType; +let app: ReturnType | null = null; +let n = 0; -afterEach(() => { - if (app) return app.close(); +afterEach(async () => { + if (app) { + await app.close(); + app = null; + } }); /* tests below */ @@ -66,7 +73,7 @@ test('faviconがHTML上で指定されていなくて、ルートにも存在し test('titleがcleanupされる', async () => { app = fastify(); app.get('/', (request, reply) => { - return reply.send(fs.createReadStream(_dirname + '/htmls/ditry-title.html')); + return reply.send(fs.createReadStream(_dirname + '/htmls/dirty-title.html')); }); await app.listen({ port }); @@ -77,15 +84,39 @@ test('titleがcleanupされる', async () => { describe('Private IP blocking', () => { beforeEach(() => { process.env.SUMMALY_ALLOW_PRIVATE_IP = 'false'; + app = fastify(); + app.get('*', (request, reply) => { + return reply.send(fs.createReadStream(_dirname + '/htmls/og-title.html')); + }); + return app.listen({ port }); }); test('private ipなサーバーの情報を取得できない', async () => { - app = fastify(); - app.get('/', (request, reply) => { - return reply.send(fs.createReadStream(_dirname + '/htmls/og-title.html')); + const summary = await summaly(host).catch((e: StatusError) => e); + if (summary instanceof StatusError) { + expect(summary.name).toBe('StatusError'); + } else { + expect(summary).toBeInstanceOf(StatusError); + } + }); + + test('agentが指定されている場合はprivate ipを許可', async () => { + const summary = await summaly(host, { + agent: { + http: new httpAgent({ keepAlive: true }), + https: new httpsAgent({ keepAlive: true }), + } }); - await app.listen({ port }); - expect(() => summaly(host)).rejects.toMatch('Private IP rejected 127.0.0.1'); + expect(summary.title).toBe('Strawberry Pasta'); + }); + + test('agentが空のオブジェクトの場合はprivate ipを許可しない', async () => { + const summary = await summaly(host, { agent: {} }).catch((e: StatusError) => e); + if (summary instanceof StatusError) { + expect(summary.name).toBe('StatusError'); + } else { + expect(summary).toBeInstanceOf(StatusError); + } }); afterEach(() => { @@ -96,7 +127,7 @@ describe('Private IP blocking', () => { describe('OGP', () => { test('title', async () => { app = fastify(); - app.get('/', (request, reply) => { + app.get('*', (request, reply) => { return reply.send(fs.createReadStream(_dirname + '/htmls/og-title.html')); }); await app.listen({ port });