This commit is contained in:
tamaina
2023-02-12 14:37:37 +00:00
parent f4a180907c
commit 709ca51b6c
7 changed files with 52 additions and 15 deletions

View File

@ -1,3 +1,7 @@
3.0.3 / 2023-02-12
------------------
* agentが指定されているもしくはagentが空のオブジェクトの場合はプライベートIPのリクエストを許可
3.0.2 / 2023-02-12 3.0.2 / 2023-02-12
------------------ ------------------
* Fastifyのルーティングを'/'から'*'に * Fastifyのルーティングを'/'から'*'に

View File

@ -28,8 +28,8 @@ export async function scpaping(url, opts) {
}, },
typeFilter: /^(text\/html|application\/xhtml\+xml)/, typeFilter: /^(text\/html|application\/xhtml\+xml)/,
}); });
// テスト用 // SUMMALY_ALLOW_PRIVATE_IPはテスト用
const allowPrivateIp = process.env.SUMMALY_ALLOW_PRIVATE_IP === 'true'; const allowPrivateIp = process.env.SUMMALY_ALLOW_PRIVATE_IP === 'true' || Object.keys(agent).length > 0;
if (!allowPrivateIp && response.ip && PrivateIp(response.ip)) { if (!allowPrivateIp && response.ip && PrivateIp(response.ip)) {
throw new StatusError(`Private IP rejected ${response.ip}`, 400, 'Private IP Rejected'); throw new StatusError(`Private IP rejected ${response.ip}`, 400, 'Private IP Rejected');
} }

View File

@ -1,4 +1,5 @@
export declare class StatusError extends Error { export declare class StatusError extends Error {
name: string;
statusCode: number; statusCode: number;
statusMessage?: string; statusMessage?: string;
isPermanentError: boolean; isPermanentError: boolean;

View File

@ -1,6 +1,6 @@
{ {
"name": "summaly", "name": "summaly",
"version": "3.0.1", "version": "3.0.3",
"description": "Get web page's summary", "description": "Get web page's summary",
"author": "syuilo <syuilotan@yahoo.co.jp>", "author": "syuilo <syuilotan@yahoo.co.jp>",
"license": "MIT", "license": "MIT",

View File

@ -42,8 +42,8 @@ export async function scpaping(url: string, opts?: { lang?: string; }) {
typeFilter: /^(text\/html|application\/xhtml\+xml)/, typeFilter: /^(text\/html|application\/xhtml\+xml)/,
}); });
// テスト用 // SUMMALY_ALLOW_PRIVATE_IPはテスト用
const allowPrivateIp = process.env.SUMMALY_ALLOW_PRIVATE_IP === 'true'; const allowPrivateIp = process.env.SUMMALY_ALLOW_PRIVATE_IP === 'true' || Object.keys(agent).length > 0;
if (!allowPrivateIp && response.ip && PrivateIp(response.ip)) { if (!allowPrivateIp && response.ip && PrivateIp(response.ip)) {
throw new StatusError(`Private IP rejected ${response.ip}`, 400, 'Private IP Rejected'); throw new StatusError(`Private IP rejected ${response.ip}`, 400, 'Private IP Rejected');

View File

@ -1,4 +1,5 @@
export class StatusError extends Error { export class StatusError extends Error {
public name: string;
public statusCode: number; public statusCode: number;
public statusMessage?: string; public statusMessage?: string;
public isPermanentError: boolean; public isPermanentError: boolean;

View File

@ -13,6 +13,9 @@ import { summaly } from '../src/index.js';
import { dirname } from 'node:path'; import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import {expect, jest, test, describe, beforeEach, afterEach} from '@jest/globals'; 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 _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename); const _dirname = dirname(_filename);
@ -31,10 +34,14 @@ const host = `http://localhost:${port}`;
// Display detail of unhandled promise rejection // Display detail of unhandled promise rejection
process.on('unhandledRejection', console.dir); process.on('unhandledRejection', console.dir);
let app: ReturnType<typeof fastify>; let app: ReturnType<typeof fastify> | null = null;
let n = 0;
afterEach(() => { afterEach(async () => {
if (app) return app.close(); if (app) {
await app.close();
app = null;
}
}); });
/* tests below */ /* tests below */
@ -66,7 +73,7 @@ test('faviconがHTML上で指定されていなくて、ルートにも存在し
test('titleがcleanupされる', async () => { test('titleがcleanupされる', async () => {
app = fastify(); app = fastify();
app.get('/', (request, reply) => { 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 }); await app.listen({ port });
@ -77,15 +84,39 @@ test('titleがcleanupされる', async () => {
describe('Private IP blocking', () => { describe('Private IP blocking', () => {
beforeEach(() => { beforeEach(() => {
process.env.SUMMALY_ALLOW_PRIVATE_IP = 'false'; 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 () => { test('private ipなサーバーの情報を取得できない', async () => {
app = fastify(); const summary = await summaly(host).catch((e: StatusError) => e);
app.get('/', (request, reply) => { if (summary instanceof StatusError) {
return reply.send(fs.createReadStream(_dirname + '/htmls/og-title.html')); 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(summary.title).toBe('Strawberry Pasta');
expect(() => summaly(host)).rejects.toMatch('Private IP rejected 127.0.0.1'); });
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(() => { afterEach(() => {
@ -96,7 +127,7 @@ describe('Private IP blocking', () => {
describe('OGP', () => { describe('OGP', () => {
test('title', async () => { test('title', async () => {
app = fastify(); app = fastify();
app.get('/', (request, reply) => { app.get('*', (request, reply) => {
return reply.send(fs.createReadStream(_dirname + '/htmls/og-title.html')); return reply.send(fs.createReadStream(_dirname + '/htmls/og-title.html'));
}); });
await app.listen({ port }); await app.listen({ port });