Compare commits
No commits in common. "dab22cd63151d95c238db731e64200d741f825cf" and "1b79c99459c018aaccf7ca6e79e3be5f3d15ce26" have entirely different histories.
dab22cd631
...
1b79c99459
37 changed files with 194 additions and 327 deletions
55
.pnp.cjs
generated
55
.pnp.cjs
generated
|
|
@ -7295,7 +7295,7 @@ const RAW_RUNTIME_STATE =
|
|||
["mfm-js", "npm:0.23.3"],\
|
||||
["mime-types", "npm:2.1.35"],\
|
||||
["mocha", "npm:10.2.0"],\
|
||||
["msgpackr", "npm:1.11.2"],\
|
||||
["msgpackr", "npm:1.9.5"],\
|
||||
["multer", "npm:1.4.4-lts.1"],\
|
||||
["nested-property", "npm:4.0.0"],\
|
||||
["node-fetch", "npm:3.3.2"],\
|
||||
|
|
@ -7317,7 +7317,7 @@ const RAW_RUNTIME_STATE =
|
|||
["qs", "npm:6.11.2"],\
|
||||
["random-seed", "npm:0.3.0"],\
|
||||
["ratelimiter", "npm:3.4.1"],\
|
||||
["re2", "npm:1.21.4"],\
|
||||
["re2", "npm:1.20.11"],\
|
||||
["redis-lock", "npm:0.1.4"],\
|
||||
["redis-semaphore", "virtual:aa59773ac87791c4813d53447077fcf8a847d6de5a301d34dc31286584b1dbb26d30d3adb5b4c41c1e8aea04371e926fda05c09c6253647c432e11d872a304ba#npm:5.3.1"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
|
|
@ -18152,10 +18152,10 @@ const RAW_RUNTIME_STATE =
|
|||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.11.2", {\
|
||||
"packageLocation": "./.yarn/cache/msgpackr-npm-1.11.2-a21c5db6f8-7602f1e91e.zip/node_modules/msgpackr/",\
|
||||
["npm:1.9.5", {\
|
||||
"packageLocation": "./.yarn/cache/msgpackr-npm-1.9.5-69f0e8f5b8-d95fbee39b.zip/node_modules/msgpackr/",\
|
||||
"packageDependencies": [\
|
||||
["msgpackr", "npm:1.11.2"],\
|
||||
["msgpackr", "npm:1.9.5"],\
|
||||
["msgpackr-extract", "npm:3.0.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
|
|
@ -18225,10 +18225,10 @@ const RAW_RUNTIME_STATE =
|
|||
}]\
|
||||
]],\
|
||||
["nan", [\
|
||||
["npm:2.22.0", {\
|
||||
"packageLocation": "./.yarn/unplugged/nan-npm-2.22.0-3750ad85d9/node_modules/nan/",\
|
||||
["npm:2.19.0", {\
|
||||
"packageLocation": "./.yarn/unplugged/nan-npm-2.19.0-2f5da4a528/node_modules/nan/",\
|
||||
"packageDependencies": [\
|
||||
["nan", "npm:2.22.0"],\
|
||||
["nan", "npm:2.19.0"],\
|
||||
["node-gyp", "npm:9.4.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
|
|
@ -18406,19 +18406,19 @@ const RAW_RUNTIME_STATE =
|
|||
}]\
|
||||
]],\
|
||||
["node-gyp", [\
|
||||
["npm:10.2.0", {\
|
||||
"packageLocation": "./.yarn/unplugged/node-gyp-npm-10.2.0-cad1109948/node_modules/node-gyp/",\
|
||||
["npm:10.0.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/node-gyp-npm-10.0.1-48708ce70b/node_modules/node-gyp/",\
|
||||
"packageDependencies": [\
|
||||
["node-gyp", "npm:10.2.0"],\
|
||||
["node-gyp", "npm:10.0.1"],\
|
||||
["env-paths", "npm:2.2.1"],\
|
||||
["exponential-backoff", "npm:3.1.1"],\
|
||||
["glob", "npm:10.3.10"],\
|
||||
["graceful-fs", "npm:4.2.11"],\
|
||||
["make-fetch-happen", "npm:13.0.0"],\
|
||||
["nopt", "npm:7.2.0"],\
|
||||
["proc-log", "npm:4.2.0"],\
|
||||
["proc-log", "npm:3.0.0"],\
|
||||
["semver", "npm:7.5.4"],\
|
||||
["tar", "npm:6.2.1"],\
|
||||
["tar", "npm:6.1.15"],\
|
||||
["which", "npm:4.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
|
|
@ -20445,10 +20445,10 @@ const RAW_RUNTIME_STATE =
|
|||
}]\
|
||||
]],\
|
||||
["proc-log", [\
|
||||
["npm:4.2.0", {\
|
||||
"packageLocation": "./.yarn/cache/proc-log-npm-4.2.0-4d65296a9d-4e1394491b.zip/node_modules/proc-log/",\
|
||||
["npm:3.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/proc-log-npm-3.0.0-a8c21c2f0f-02b64e1b39.zip/node_modules/proc-log/",\
|
||||
"packageDependencies": [\
|
||||
["proc-log", "npm:4.2.0"]\
|
||||
["proc-log", "npm:3.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
|
|
@ -20975,13 +20975,13 @@ const RAW_RUNTIME_STATE =
|
|||
}]\
|
||||
]],\
|
||||
["re2", [\
|
||||
["npm:1.21.4", {\
|
||||
"packageLocation": "./.yarn/unplugged/re2-npm-1.21.4-315af4327e/node_modules/re2/",\
|
||||
["npm:1.20.11", {\
|
||||
"packageLocation": "./.yarn/unplugged/re2-npm-1.20.11-ab65de125e/node_modules/re2/",\
|
||||
"packageDependencies": [\
|
||||
["re2", "npm:1.21.4"],\
|
||||
["re2", "npm:1.20.11"],\
|
||||
["install-artifact-from-github", "npm:1.3.5"],\
|
||||
["nan", "npm:2.22.0"],\
|
||||
["node-gyp", "npm:10.2.0"]\
|
||||
["nan", "npm:2.19.0"],\
|
||||
["node-gyp", "npm:10.0.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
|
|
@ -23165,19 +23165,6 @@ const RAW_RUNTIME_STATE =
|
|||
["yallist", "npm:4.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:6.2.1", {\
|
||||
"packageLocation": "./.yarn/cache/tar-npm-6.2.1-237800bb20-bfbfbb2861.zip/node_modules/tar/",\
|
||||
"packageDependencies": [\
|
||||
["tar", "npm:6.2.1"],\
|
||||
["chownr", "npm:2.0.0"],\
|
||||
["fs-minipass", "npm:2.1.0"],\
|
||||
["minipass", "npm:5.0.0"],\
|
||||
["minizlib", "npm:2.1.2"],\
|
||||
["mkdirp", "npm:1.0.4"],\
|
||||
["yallist", "npm:4.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["tar-stream", [\
|
||||
|
|
|
|||
BIN
.yarn/cache/msgpackr-npm-1.11.2-a21c5db6f8-7602f1e91e.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/msgpackr-npm-1.11.2-a21c5db6f8-7602f1e91e.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/msgpackr-npm-1.9.5-69f0e8f5b8-d95fbee39b.zip
(Stored with Git LFS)
vendored
Normal file
BIN
.yarn/cache/msgpackr-npm-1.9.5-69f0e8f5b8-d95fbee39b.zip
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/nan-npm-2.19.0-2f5da4a528-b97f680753.zip
(Stored with Git LFS)
vendored
Normal file
BIN
.yarn/cache/nan-npm-2.19.0-2f5da4a528-b97f680753.zip
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/nan-npm-2.22.0-3750ad85d9-ab165ba910.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/nan-npm-2.22.0-3750ad85d9-ab165ba910.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/node-gyp-npm-10.0.1-48708ce70b-578cf0c821.zip
(Stored with Git LFS)
vendored
Normal file
BIN
.yarn/cache/node-gyp-npm-10.0.1-48708ce70b-578cf0c821.zip
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/node-gyp-npm-10.2.0-cad1109948-41773093b1.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/node-gyp-npm-10.2.0-cad1109948-41773093b1.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/proc-log-npm-3.0.0-a8c21c2f0f-02b64e1b39.zip
(Stored with Git LFS)
vendored
Normal file
BIN
.yarn/cache/proc-log-npm-3.0.0-a8c21c2f0f-02b64e1b39.zip
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/proc-log-npm-4.2.0-4d65296a9d-4e1394491b.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/proc-log-npm-4.2.0-4d65296a9d-4e1394491b.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/re2-npm-1.20.11-ab65de125e-a8665c861c.zip
(Stored with Git LFS)
vendored
Normal file
BIN
.yarn/cache/re2-npm-1.20.11-ab65de125e-a8665c861c.zip
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/re2-npm-1.21.4-315af4327e-926871cc84.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/re2-npm-1.21.4-315af4327e-926871cc84.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/tar-npm-6.2.1-237800bb20-bfbfbb2861.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/tar-npm-6.2.1-237800bb20-bfbfbb2861.zip
(Stored with Git LFS)
vendored
Binary file not shown.
20
CHANGELOG.md
20
CHANGELOG.md
|
|
@ -1,23 +1,3 @@
|
|||
## v2023.12.11
|
||||
This release contains several critical security patches, as well as minor fixes and improvements. Upgrading is strongly recommended for all server operators.
|
||||
|
||||
### Highlights
|
||||
- Several DoS, impersonation, data leakage & click jacking vulnerabilities have been patched
|
||||
|
||||
### Backend
|
||||
- Various issues related to AP object validation have been resolved
|
||||
- The ap/get API endpoint is now only available to administrators
|
||||
- Blocks are now enforced in NoteRepository.isVisibleForMe
|
||||
- Audience parsing no longer bypasses the AP recursion limit
|
||||
- Edits of local-only notes are no longer federated out
|
||||
- AP object URIs now get canonicalized before comparing them for consistency
|
||||
- SSRF prevention now applies to all code paths
|
||||
|
||||
### Attribution
|
||||
This release was made possible by project contributors: Kopper & Laura Hausmann
|
||||
|
||||
Furthermore, I want to give special thanks to Hazel Koehler for the vulnerability disclosure.
|
||||
|
||||
## v2023.12.10
|
||||
This release contains a critical security patch, as well as minor fixes and improvements. Upgrading is strongly recommended for all server operators.
|
||||
|
||||
|
|
|
|||
|
|
@ -1086,7 +1086,7 @@ _registry:
|
|||
domain: "Domain"
|
||||
createKey: "Schlüssel erstellen"
|
||||
_aboutIceshrimp:
|
||||
about: "Iceshrimp ist ein Fork von Firefish, der seit 2022 von zotan
|
||||
about: "Iceshrimp ist ein Fork von Iceshrimp, der seit 2022 von ThatOneCalculator
|
||||
entwickelt wird."
|
||||
contributors: "Hauptmitwirkende"
|
||||
allContributors: "Alle Mitwirkenden"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "iceshrimp",
|
||||
"version": "2023.12.11",
|
||||
"version": "2023.12.10",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://iceshrimp.dev/iceshrimp/iceshrimp.git"
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@
|
|||
"koa-views": "7.0.2",
|
||||
"mfm-js": "0.23.3",
|
||||
"mime-types": "2.1.35",
|
||||
"msgpackr": "1.11.2",
|
||||
"msgpackr": "1.9.5",
|
||||
"multer": "1.4.4-lts.1",
|
||||
"nested-property": "4.0.0",
|
||||
"node-fetch": "3.3.2",
|
||||
|
|
@ -111,7 +111,7 @@
|
|||
"qs": "6.11.2",
|
||||
"random-seed": "0.3.0",
|
||||
"ratelimiter": "3.4.1",
|
||||
"re2": "^1.21.4",
|
||||
"re2": "^1.20.11",
|
||||
"redis-lock": "0.1.4",
|
||||
"redis-semaphore": "5.3.1",
|
||||
"reflect-metadata": "0.1.13",
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
import * as http from "node:http";
|
||||
import * as https from "node:https";
|
||||
import net from "node:net";
|
||||
import { HttpProxyAgent, HttpsProxyAgent } from "hpagent";
|
||||
import config from "@/config/index.js";
|
||||
import IPCIDR from "ip-cidr";
|
||||
import PrivateIp from "private-ip";
|
||||
|
||||
declare module 'node:http' {
|
||||
interface Agent {
|
||||
createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket;
|
||||
}
|
||||
}
|
||||
|
||||
function isPrivateIp(ip: string): boolean {
|
||||
for (const net of config.allowedPrivateNetworks || []) {
|
||||
const cidr = new IPCIDR(net);
|
||||
if (cidr.contains(ip)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return PrivateIp(ip);
|
||||
}
|
||||
|
||||
function checkConnection(socket: net.Socket) {
|
||||
const address = socket.remoteAddress;
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
if (address && IPCIDR.isValidAddress(address) && isPrivateIp(address)) {
|
||||
socket.destroy(new Error(`Blocked address: ${address}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class CheckedHttpAgent extends http.Agent {
|
||||
createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
|
||||
const socket = super.createConnection(options, callback).on('connect', () => { checkConnection(socket) });
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
|
||||
export class CheckedHttpsAgent extends https.Agent {
|
||||
createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
|
||||
const socket = super.createConnection(options, callback).on('connect', () => { checkConnection(socket) });
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
export class CheckedHttpProxyAgent extends HttpProxyAgent {
|
||||
createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
|
||||
const socket = super.createConnection(options, callback).on('connect', () => { checkConnection(socket) });
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
|
||||
export class CheckedHttpsProxyAgent extends HttpsProxyAgent {
|
||||
createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
|
||||
const socket = super.createConnection(options, callback).on('connect', () => { checkConnection(socket) });
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@ import { httpAgent, httpsAgent, StatusError } from "./fetch.js";
|
|||
import config from "@/config/index.js";
|
||||
import chalk from "chalk";
|
||||
import Logger from "@/services/logger.js";
|
||||
import IPCIDR from "ip-cidr";
|
||||
import PrivateIp from "private-ip";
|
||||
|
||||
const pipeline = util.promisify(stream.pipeline);
|
||||
|
||||
|
|
@ -43,6 +45,18 @@ export async function downloadUrl(url: string, path: string): Promise<void> {
|
|||
},
|
||||
})
|
||||
.on("response", (res: Got.Response) => {
|
||||
if (
|
||||
(process.env.NODE_ENV === "production" ||
|
||||
process.env.NODE_ENV === "test") &&
|
||||
!config.proxy &&
|
||||
res.ip
|
||||
) {
|
||||
if (isPrivateIp(res.ip)) {
|
||||
logger.warn(`Blocked address: ${res.ip}`);
|
||||
req.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
const contentLength = res.headers["content-length"];
|
||||
if (contentLength != null) {
|
||||
const size = Number(contentLength);
|
||||
|
|
@ -78,3 +92,13 @@ export async function downloadUrl(url: string, path: string): Promise<void> {
|
|||
logger.succ(`Download finished: ${chalk.cyan(url)}`);
|
||||
}
|
||||
|
||||
function isPrivateIp(ip: string): boolean {
|
||||
for (const net of config.allowedPrivateNetworks || []) {
|
||||
const cidr = new IPCIDR(net);
|
||||
if (cidr.contains(ip)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return PrivateIp(ip);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@ import * as https from "node:https";
|
|||
import type { URL } from "node:url";
|
||||
import CacheableLookup from "cacheable-lookup";
|
||||
import fetch from "node-fetch";
|
||||
import { HttpProxyAgent, HttpsProxyAgent } from "hpagent";
|
||||
import config from "@/config/index.js";
|
||||
import net from "node:net";
|
||||
import {CheckedHttpAgent, CheckedHttpProxyAgent, CheckedHttpsAgent, CheckedHttpsProxyAgent} from "@/misc/checked-fetch.js";
|
||||
|
||||
export async function getJson(
|
||||
url: string,
|
||||
|
|
@ -133,7 +132,7 @@ const cache = new CacheableLookup({
|
|||
/**
|
||||
* Get http non-proxy agent
|
||||
*/
|
||||
const _http = new CheckedHttpAgent({
|
||||
const _http = new http.Agent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 30 * 1000,
|
||||
lookup: cache.lookup,
|
||||
|
|
@ -142,7 +141,7 @@ const _http = new CheckedHttpAgent({
|
|||
/**
|
||||
* Get https non-proxy agent
|
||||
*/
|
||||
const _https = new CheckedHttpsAgent({
|
||||
const _https = new https.Agent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 30 * 1000,
|
||||
lookup: cache.lookup,
|
||||
|
|
@ -154,7 +153,7 @@ const maxSockets = Math.max(256, config.deliverJobConcurrency || 128);
|
|||
* Get http proxy or non-proxy agent
|
||||
*/
|
||||
export const httpAgent = config.proxy
|
||||
? new CheckedHttpProxyAgent({
|
||||
? new HttpProxyAgent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 30 * 1000,
|
||||
maxSockets,
|
||||
|
|
@ -168,7 +167,7 @@ export const httpAgent = config.proxy
|
|||
* Get https proxy or non-proxy agent
|
||||
*/
|
||||
export const httpsAgent = config.proxy
|
||||
? new CheckedHttpsProxyAgent({
|
||||
? new HttpsProxyAgent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 30 * 1000,
|
||||
maxSockets,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
Followings,
|
||||
Polls,
|
||||
Channels,
|
||||
Notes, UserProfiles, Blockings,
|
||||
Notes, UserProfiles,
|
||||
} from "../index.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { nyaize } from "@/misc/nyaize.js";
|
||||
|
|
@ -113,20 +113,6 @@ async function populateIsRenoted(
|
|||
|
||||
export const NoteRepository = db.getRepository(Note).extend({
|
||||
async isVisibleForMe(note: Note, meId: User["id"] | null): Promise<boolean> {
|
||||
if (meId != null && meId !== note.userId) {
|
||||
const blocked = await Blockings.count({
|
||||
where: {
|
||||
blockeeId: meId,
|
||||
blockerId: note.userId
|
||||
},
|
||||
take: 1
|
||||
});
|
||||
|
||||
if (blocked !== 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// This code must always be synchronized with the checks in generateVisibilityQuery.
|
||||
// visibility が specified かつ自分が指定されていなかったら非表示
|
||||
if (note.visibility === "specified") {
|
||||
|
|
|
|||
|
|
@ -178,14 +178,12 @@ async function process(job: Job<InboxJobData>): Promise<string> {
|
|||
}
|
||||
|
||||
// activity.idがあればホストが署名者のホストであることを確認する
|
||||
if (typeof activity.id !== "string") {
|
||||
return 'skip: activity.id is not a string';
|
||||
}
|
||||
|
||||
const signerHost = extractDbHost(authUser.user.uri!);
|
||||
const activityIdHost = extractDbHost(activity.id);
|
||||
if (signerHost !== activityIdHost) {
|
||||
return `skip: signerHost(${signerHost}) !== activity.id host(${activityIdHost}`;
|
||||
if (typeof activity.id === "string") {
|
||||
const signerHost = extractDbHost(authUser.user.uri!);
|
||||
const activityIdHost = extractDbHost(activity.id);
|
||||
if (signerHost !== activityIdHost) {
|
||||
return `skip: signerHost(${signerHost}) !== activity.id host(${activityIdHost}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Update stats
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { ApObject } from "./type.js";
|
||||
import { getApIds } from "./type.js";
|
||||
import Resolver from "./resolver.js";
|
||||
import type Resolver from "./resolver.js";
|
||||
import { resolvePerson } from "./models/person.js";
|
||||
import { unique, concat } from "@/prelude/array.js";
|
||||
import promiseLimit from "promise-limit";
|
||||
|
|
@ -31,7 +31,6 @@ export async function parseAudience(
|
|||
|
||||
const others = unique(concat([toGroups.other, ccGroups.other]));
|
||||
|
||||
resolver ??= new Resolver();
|
||||
const limit = promiseLimit<CacheableUser | null>(2);
|
||||
const mentionedUsers = (
|
||||
await Promise.all(
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export async function checkFetch(req: IncomingMessage): Promise<number> {
|
|||
let signature;
|
||||
|
||||
try {
|
||||
signature = httpSignature.parseRequest(req, { headers: ["(request-target)", "host", "date"], authorizationHeaderName: 'signature' });
|
||||
signature = httpSignature.parseRequest(req, { headers: ["(request-target)", "host", "date"] });
|
||||
} catch (e) {
|
||||
return 401;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import type { IObject } from "./type.js";
|
|||
import { getApId } from "./type.js";
|
||||
import { resolvePerson, updatePerson } from "./models/person.js";
|
||||
import {redisClient, subscriber} from "@/db/redis.js";
|
||||
import { extractDbHost, toPuny } from "@/misc/convert-host.js";
|
||||
|
||||
const publicKeyCache = new Cache<UserPublickey | null>("publicKey", 60 * 30);
|
||||
const publicKeyByUserIdCache = new Cache<UserPublickey | null>(
|
||||
|
|
@ -47,15 +46,15 @@ export type UriParseResult =
|
|||
|
||||
export function parseUri(value: string | IObject): UriParseResult {
|
||||
const uri = getApId(value);
|
||||
const parsed = new URL(uri);
|
||||
|
||||
if (toPuny(parsed.host) === toPuny(config.host)) {
|
||||
const localRegex = new RegExp(`^.*?/(\\w+)/(\\w+)(?:/(.+))?`);
|
||||
const matchLocal = uri.match(localRegex);
|
||||
if (matchLocal == null) {
|
||||
throw new Error(`Failed to parse local URI: ${uri}`);
|
||||
}
|
||||
// the host part of a URL is case insensitive, so use the 'i' flag.
|
||||
const localRegex = new RegExp(
|
||||
`^${escapeRegexp(config.url)}/(\\w+)/(\\w+)(?:/(.+))?`,
|
||||
"i",
|
||||
);
|
||||
const matchLocal = uri.match(localRegex);
|
||||
|
||||
if (matchLocal) {
|
||||
return {
|
||||
local: true,
|
||||
type: matchLocal[1],
|
||||
|
|
|
|||
|
|
@ -29,9 +29,6 @@ export default async function (
|
|||
return "skip: host in actor.uri !== note.id";
|
||||
}
|
||||
}
|
||||
else {
|
||||
return "skip: note.id is not a string";
|
||||
}
|
||||
}
|
||||
|
||||
const unlock = await getApLock(uri);
|
||||
|
|
|
|||
|
|
@ -46,8 +46,19 @@ export async function performActivity(
|
|||
activity: IObject,
|
||||
) {
|
||||
if (isCollectionOrOrderedCollection(activity)) {
|
||||
apLogger.debug('Refusing to ingest collection as activity');
|
||||
return;
|
||||
const resolver = new Resolver();
|
||||
for (const item of toArray(
|
||||
isCollection(activity) ? activity.items : activity.orderedItems,
|
||||
)) {
|
||||
const act = await resolver.resolve(item);
|
||||
try {
|
||||
await performOneActivity(actor, act);
|
||||
} catch (err) {
|
||||
if (err instanceof Error || typeof err === "string") {
|
||||
apLogger.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await performOneActivity(actor, activity);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { CacheableRemoteUser } from "@/models/entities/user.js";
|
||||
import { getApId, IUpdate } from "../../type.js";
|
||||
import type { IUpdate } from "../../type.js";
|
||||
import { getApType, isActor } from "../../type.js";
|
||||
import { apLogger } from "../../logger.js";
|
||||
import { updateNote } from "../../models/note.js";
|
||||
|
|
@ -13,7 +13,7 @@ export default async (
|
|||
actor: CacheableRemoteUser,
|
||||
activity: IUpdate,
|
||||
): Promise<string> => {
|
||||
if (actor.uri == null || actor.uri !== getApId(activity.actor)) {
|
||||
if ("actor" in activity && actor.uri !== activity.actor) {
|
||||
return "skip: invalid actor";
|
||||
}
|
||||
|
||||
|
|
@ -27,10 +27,6 @@ export default async (
|
|||
});
|
||||
|
||||
if (isActor(object)) {
|
||||
if (actor.uri !== object.id) {
|
||||
return "skip: actor id mismatch";
|
||||
}
|
||||
|
||||
await updatePerson(actor.uri!, resolver, object);
|
||||
return "ok: Person updated";
|
||||
}
|
||||
|
|
@ -43,7 +39,7 @@ export default async (
|
|||
case "Document":
|
||||
case "Page":
|
||||
let failed = false;
|
||||
await updateNote(object, actor, resolver).catch((e: Error) => {
|
||||
await updateNote(object, resolver).catch((e: Error) => {
|
||||
failed = true;
|
||||
});
|
||||
return failed ? "skip: Note update failed" : "ok: Note updated";
|
||||
|
|
|
|||
|
|
@ -131,20 +131,13 @@ export async function createNote(
|
|||
|
||||
const note: IPost = object;
|
||||
|
||||
if (note.id == null) {
|
||||
throw new Error('Note must have an id');
|
||||
}
|
||||
|
||||
const idUrl = new URL(note.id);
|
||||
|
||||
if (idUrl.protocol != 'https:') {
|
||||
if (note.id && !note.id.startsWith("https://")) {
|
||||
throw new Error(`unexpected schema of note.id: ${note.id}`);
|
||||
}
|
||||
|
||||
let url = getOneApHrefNullable(note.url);
|
||||
const urlUrl = url != null ? new URL(url) : null;
|
||||
const url = getOneApHrefNullable(note.url);
|
||||
|
||||
if (urlUrl != null && urlUrl.protocol != 'https:') {
|
||||
if (url && !url.startsWith("https://")) {
|
||||
throw new Error(`unexpected schema of note url: ${url}`);
|
||||
}
|
||||
|
||||
|
|
@ -176,22 +169,6 @@ export async function createNote(
|
|||
limiter
|
||||
)) as CacheableRemoteUser;
|
||||
|
||||
if (actor.uri == null) {
|
||||
logger.warn('Note actor uri is null, discarding');
|
||||
return null;
|
||||
}
|
||||
|
||||
const actorUri = new URL(actor.uri);
|
||||
if (idUrl.host != actorUri.host) {
|
||||
logger.warn("Note id host doesn't match actor host, discarding");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (urlUrl != null && urlUrl.host != actorUri.host) {
|
||||
logger.debug("Note url host doesn't match actor host, clearing variable");
|
||||
url = undefined;
|
||||
}
|
||||
|
||||
// Skip if author is suspended.
|
||||
if (actor.isSuspended) {
|
||||
logger.debug(
|
||||
|
|
@ -455,7 +432,7 @@ export async function resolveNote(
|
|||
}
|
||||
//#endregion
|
||||
|
||||
if (extractDbHost(uri) === toPuny(config.host)) {
|
||||
if (uri.startsWith(config.url)) {
|
||||
throw new StatusError(
|
||||
"cannot resolve local note",
|
||||
400,
|
||||
|
|
@ -567,12 +544,12 @@ function notEmpty(partial: Partial<any>) {
|
|||
return Object.keys(partial).length > 0;
|
||||
}
|
||||
|
||||
export async function updateNote(value: string | IObject, actor: CacheableRemoteUser, resolver?: Resolver) {
|
||||
export async function updateNote(value: string | IObject, resolver?: Resolver) {
|
||||
const uri = typeof value === "string" ? value : value.id;
|
||||
if (!uri) throw new Error("Missing note uri");
|
||||
|
||||
// Skip if URI points to this server
|
||||
if (extractDbHost(uri) === toPuny(config.host)) throw new Error("uri points local");
|
||||
if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local");
|
||||
|
||||
// A new resolver is created if not specified
|
||||
if (resolver == null) resolver = new Resolver();
|
||||
|
|
@ -580,18 +557,16 @@ export async function updateNote(value: string | IObject, actor: CacheableRemote
|
|||
// Resolve the updated Note object
|
||||
const post = (await resolver.resolve(value)) as IPost;
|
||||
|
||||
if (getOneApId(post.attributedTo) !== actor.uri || actor.uri == null) {
|
||||
throw new Error('Refusing to ingest update for note with mismatching actor');
|
||||
}
|
||||
const actor = (await resolvePerson(
|
||||
getOneApId(post.attributedTo),
|
||||
resolver,
|
||||
)) as CacheableRemoteUser;
|
||||
|
||||
// Already registered with this server?
|
||||
const note = await Notes.findOneBy({ uri });
|
||||
if (note == null) {
|
||||
return await createNote(post, resolver);
|
||||
}
|
||||
if (note.userId !== actor.id) {
|
||||
throw new Error('Refusing to ingest update for note of different user');
|
||||
}
|
||||
|
||||
// Whether to tell clients the note has been updated and requires refresh.
|
||||
let updating = false;
|
||||
|
|
@ -724,10 +699,6 @@ export async function updateNote(value: string | IObject, actor: CacheableRemote
|
|||
|
||||
if (poll) {
|
||||
const dbPoll = await Polls.findOneBy({ noteId: note.id });
|
||||
if (poll?.votes != null && poll.votes.find(p => !Number.isInteger(p) || p < 0) !== undefined) {
|
||||
throw new Error('Refusing to ingest poll with non-integer or negative vote count');
|
||||
}
|
||||
|
||||
if (dbPoll == null) {
|
||||
await Polls.insert({
|
||||
noteId: note.id,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { genId } from "@/misc/gen-id.js";
|
|||
import { instanceChart, usersChart } from "@/services/chart/index.js";
|
||||
import { UserPublickey } from "@/models/entities/user-publickey.js";
|
||||
import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js";
|
||||
import { extractDbHost, toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { UserProfile } from "@/models/entities/user-profile.js";
|
||||
import { toArray } from "@/prelude/array.js";
|
||||
import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js";
|
||||
|
|
@ -69,7 +69,7 @@ const summaryLength = 2048;
|
|||
* @param uri Fetch target URI
|
||||
*/
|
||||
function validateActor(x: IObject, uri: string): IActor {
|
||||
const expectHost = extractDbHost(uri);
|
||||
const expectHost = toPuny(new URL(uri).hostname);
|
||||
|
||||
if (x == null) {
|
||||
throw new Error("invalid Actor: object is null");
|
||||
|
|
@ -83,36 +83,10 @@ function validateActor(x: IObject, uri: string): IActor {
|
|||
throw new Error("invalid Actor: wrong id");
|
||||
}
|
||||
|
||||
if (!(typeof x.inbox === "string" && x.inbox.length > 0 && extractDbHost(x.inbox) === expectHost)) {
|
||||
if (!(typeof x.inbox === "string" && x.inbox.length > 0)) {
|
||||
throw new Error("invalid Actor: wrong inbox");
|
||||
}
|
||||
|
||||
if (!(typeof x.outbox === "string" && x.outbox.length > 0 && extractDbHost(getApId(x.outbox)) === expectHost)) {
|
||||
throw new Error("invalid Actor: wrong outbox");
|
||||
}
|
||||
|
||||
const sharedInboxObject = x.sharedInbox ?? (x.endpoints ? x.endpoints.sharedInbox : undefined);
|
||||
if (sharedInboxObject != null) {
|
||||
const sharedInbox = getApId(sharedInboxObject);
|
||||
if (!(typeof sharedInbox === "string" && sharedInbox.length > 0 && extractDbHost(sharedInbox) === expectHost)) {
|
||||
throw new Error("invalid Actor: wrong shared inbox");
|
||||
}
|
||||
}
|
||||
|
||||
if (x.followers != null) {
|
||||
x.followers = getApId(x.followers);
|
||||
if (!(typeof x.followers === "string" && x.followers.length > 0 && extractDbHost(x.followers) === expectHost)) {
|
||||
throw new Error("invalid Actor: wrong followers");
|
||||
}
|
||||
}
|
||||
|
||||
if (x.following != null) {
|
||||
x.following = getApId(x.following);
|
||||
if (!(typeof x.following === "string" && x.following.length > 0 && extractDbHost(x.following) === expectHost)) {
|
||||
throw new Error("invalid Actor: wrong following");
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!(
|
||||
typeof x.preferredUsername === "string" &&
|
||||
|
|
@ -140,7 +114,7 @@ function validateActor(x: IObject, uri: string): IActor {
|
|||
x.summary = truncate(x.summary, summaryLength);
|
||||
}
|
||||
|
||||
const idHost = toPuny(new URL(x.id!).host);
|
||||
const idHost = toPuny(new URL(x.id!).hostname);
|
||||
if (idHost !== expectHost) {
|
||||
throw new Error("invalid Actor: id has different host");
|
||||
}
|
||||
|
|
@ -150,7 +124,7 @@ function validateActor(x: IObject, uri: string): IActor {
|
|||
throw new Error("invalid Actor: publicKey.id is not a string");
|
||||
}
|
||||
|
||||
const publicKeyIdHost = toPuny(new URL(x.publicKey.id).host);
|
||||
const publicKeyIdHost = toPuny(new URL(x.publicKey.id).hostname);
|
||||
if (publicKeyIdHost !== expectHost) {
|
||||
throw new Error("invalid Actor: publicKey.id has different host");
|
||||
}
|
||||
|
|
@ -174,7 +148,7 @@ export async function fetchPerson(
|
|||
if (cached) return cached;
|
||||
|
||||
// Fetch from the database if the URI points to this server
|
||||
if (extractDbHost(uri) === toPuny(config.host)) {
|
||||
if (uri.startsWith(`${config.url}/`)) {
|
||||
const id = uri.split("/").pop();
|
||||
const u = await Users.findOneBy({ id });
|
||||
if (u) await uriPersonCache.set(uri, u);
|
||||
|
|
@ -204,7 +178,7 @@ export async function createPerson(
|
|||
): Promise<User> {
|
||||
if (typeof uri !== "string") throw new Error("uri is not string");
|
||||
|
||||
if (extractDbHost(uri) === toPuny(config.host)) {
|
||||
if (uri.startsWith(config.url)) {
|
||||
throw new StatusError(
|
||||
"cannot resolve local user",
|
||||
400,
|
||||
|
|
@ -221,10 +195,10 @@ export async function createPerson(
|
|||
person = validateActor(object, uri);
|
||||
}
|
||||
catch (e: any) {
|
||||
// Work around GoToSocial issue #1186 (ref: https://github.com/superseriousbusiness/gotosocial/issues/1186)
|
||||
if (typeof object.publicKey?.owner !== 'string' || object.inbox != null)
|
||||
if (typeof object.publicKey?.owner !== 'string')
|
||||
throw e;
|
||||
|
||||
// Work around GoToSocial issue #1186 (ref: https://github.com/superseriousbusiness/gotosocial/issues/1186)
|
||||
logger.info(`Received stub actor, re-resolving with key owner uri: ${object.publicKey.owner}`);
|
||||
object = (await resolver.resolve(object.publicKey.owner)) as any;
|
||||
person = validateActor(object, uri);
|
||||
|
|
@ -287,19 +261,12 @@ export async function createPerson(
|
|||
|
||||
const bday = person["vcard:bday"]?.match(/^\d{4}-\d{2}-\d{2}/);
|
||||
|
||||
let url = getOneApHrefNullable(person.url);
|
||||
const urlUrl = url != null ? new URL(url) : null;
|
||||
const uriUrl = new URL(uri);
|
||||
const url = getOneApHrefNullable(person.url);
|
||||
|
||||
if (urlUrl != null && urlUrl.protocol != 'https:') {
|
||||
if (url && !url.startsWith("https://")) {
|
||||
throw new Error(`unexpected schema of person url: ${url}`);
|
||||
}
|
||||
|
||||
if (urlUrl != null && urlUrl.host != uriUrl.host) {
|
||||
logger.debug("Person url host doesn't match person uri host, clearing variable");
|
||||
url = undefined;
|
||||
}
|
||||
|
||||
let followersCount: number | undefined;
|
||||
|
||||
if (typeof person.followers === "string") {
|
||||
|
|
@ -507,7 +474,7 @@ export async function updatePerson(
|
|||
if (typeof uri !== "string") throw new Error("uri is not string");
|
||||
|
||||
// Skip if the URI points to this server
|
||||
if (extractDbHost(uri) === toPuny(config.host)) {
|
||||
if (uri.startsWith(`${config.url}/`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { getApId, isQuestion } from "../type.js";
|
|||
import { apLogger } from "../logger.js";
|
||||
import { Notes, Polls } from "@/models/index.js";
|
||||
import type { IPoll } from "@/models/entities/poll.js";
|
||||
import { extractDbHost, toPuny } from "@/misc/convert-host.js";
|
||||
|
||||
export async function extractPollFromQuestion(
|
||||
source: string | IObject,
|
||||
|
|
@ -56,7 +55,7 @@ export async function updateQuestion(
|
|||
const uri = typeof value === "string" ? value : getApId(value);
|
||||
|
||||
// Skip if URI points to this server
|
||||
if (extractDbHost(uri) === toPuny(config.host)) throw new Error("uri points local");
|
||||
if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local");
|
||||
|
||||
//#region Already registered with this server?
|
||||
const note = await Notes.findOneBy({ uri });
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ function inbox(ctx: Router.RouterContext) {
|
|||
let signature;
|
||||
|
||||
try {
|
||||
signature = httpSignature.parseRequest(ctx.req, { headers: ['(request-target)', 'digest', 'host', 'date'], authorizationHeaderName: 'signature' });
|
||||
signature = httpSignature.parseRequest(ctx.req, { headers: ['(request-target)', 'digest', 'host', 'date'] });
|
||||
} catch (e) {
|
||||
ctx.status = 401;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ export const meta = {
|
|||
tags: ["federation"],
|
||||
|
||||
requireCredential: true,
|
||||
requireAdmin: true,
|
||||
|
||||
limit: {
|
||||
duration: HOUR,
|
||||
|
|
|
|||
|
|
@ -51,6 +51,40 @@ export async function proxyMedia(ctx: Koa.Context) {
|
|||
|
||||
if (ctx.status == 429) return;
|
||||
|
||||
const { hostname } = new URL(url);
|
||||
let resolvedIps;
|
||||
try {
|
||||
resolvedIps = await promises.resolve(hostname);
|
||||
} catch (error) {
|
||||
ctx.status = 400;
|
||||
ctx.body = { message: "Invalid URL" };
|
||||
return;
|
||||
}
|
||||
|
||||
const isSSRF = resolvedIps.some((ip) => {
|
||||
if (net.isIPv4(ip)) {
|
||||
const parts = ip.split(".").map(Number);
|
||||
return (
|
||||
parts[0] === 10 ||
|
||||
(parts[0] === 172 && parts[1] >= 16 && parts[1] < 32) ||
|
||||
(parts[0] === 192 && parts[1] === 168) ||
|
||||
parts[0] === 127 ||
|
||||
parts[0] === 0
|
||||
);
|
||||
} else if (net.isIPv6(ip)) {
|
||||
return (
|
||||
ip.startsWith("::") || ip.startsWith("fc00:") || ip.startsWith("fe80:")
|
||||
);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (isSSRF) {
|
||||
ctx.status = 400;
|
||||
ctx.body = { message: "Access to this URL is not allowed" };
|
||||
return;
|
||||
}
|
||||
|
||||
// Create temp file
|
||||
const [path, cleanup] = await createTemp();
|
||||
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@
|
|||
{{ i18n.ts.updateRemoteUser }}</FormButton
|
||||
>
|
||||
|
||||
<FormFolder class="_formBlock" v-if="iAmAdmin">
|
||||
<FormFolder class="_formBlock">
|
||||
<template #label>Raw</template>
|
||||
|
||||
<MkObjectView v-if="ap" tall :value="ap">
|
||||
|
|
@ -577,15 +577,13 @@ watch(
|
|||
},
|
||||
);
|
||||
|
||||
if (iAmAdmin) {
|
||||
watch($$(user), () => {
|
||||
os.api("ap/get", {
|
||||
uri: user.uri ?? `${url}/users/${user.id}`,
|
||||
}).then((res) => {
|
||||
ap = res;
|
||||
});
|
||||
watch($$(user), () => {
|
||||
os.api("ap/get", {
|
||||
uri: user.uri ?? `${url}/users/${user.id}`,
|
||||
}).then((res) => {
|
||||
ap = res;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
/>
|
||||
<MkRemoteCaution
|
||||
v-if="user.host != null"
|
||||
:href="user.url ?? user.uri"
|
||||
:href="user.url"
|
||||
class="warn"
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ export function getUserMenu(user, router: Router = mainRouter) {
|
|||
type: "a",
|
||||
icon: "ph-arrow-square-out ph-bold ph-lg",
|
||||
text: i18n.ts.showOnRemote,
|
||||
href: user.url ?? user.uri,
|
||||
href: user.url,
|
||||
target: "_blank",
|
||||
}
|
||||
: undefined,
|
||||
|
|
|
|||
66
yarn.lock
66
yarn.lock
|
|
@ -5593,7 +5593,7 @@ __metadata:
|
|||
mfm-js: "npm:0.23.3"
|
||||
mime-types: "npm:2.1.35"
|
||||
mocha: "npm:10.2.0"
|
||||
msgpackr: "npm:1.11.2"
|
||||
msgpackr: "npm:1.9.5"
|
||||
multer: "npm:1.4.4-lts.1"
|
||||
nested-property: "npm:4.0.0"
|
||||
node-fetch: "npm:3.3.2"
|
||||
|
|
@ -5615,7 +5615,7 @@ __metadata:
|
|||
qs: "npm:6.11.2"
|
||||
random-seed: "npm:0.3.0"
|
||||
ratelimiter: "npm:3.4.1"
|
||||
re2: "npm:^1.21.4"
|
||||
re2: "npm:^1.20.11"
|
||||
redis-lock: "npm:0.1.4"
|
||||
redis-semaphore: "npm:5.3.1"
|
||||
reflect-metadata: "npm:0.1.13"
|
||||
|
|
@ -15035,15 +15035,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"msgpackr@npm:1.11.2":
|
||||
version: 1.11.2
|
||||
resolution: "msgpackr@npm:1.11.2"
|
||||
"msgpackr@npm:1.9.5":
|
||||
version: 1.9.5
|
||||
resolution: "msgpackr@npm:1.9.5"
|
||||
dependencies:
|
||||
msgpackr-extract: "npm:^3.0.2"
|
||||
dependenciesMeta:
|
||||
msgpackr-extract:
|
||||
optional: true
|
||||
checksum: 10/7602f1e91e5ba13f4289ec9cab0d3f3db87d4ed323bebcb40a0c43ba2f6153192bffb63a5bb4755faacb6e0985f307c35084f40eaba1c325b7035da91381f01a
|
||||
checksum: 10/d95fbee39b6046bdee06c59af43efda7068c6d1b0406d82b345b2ffd31f917b58829f925ceb56bbd686374ae52c952d3106747c41097021a8218c023715c948a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
@ -15099,12 +15099,12 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nan@npm:^2.20.0":
|
||||
version: 2.22.0
|
||||
resolution: "nan@npm:2.22.0"
|
||||
"nan@npm:^2.19.0":
|
||||
version: 2.19.0
|
||||
resolution: "nan@npm:2.19.0"
|
||||
dependencies:
|
||||
node-gyp: "npm:latest"
|
||||
checksum: 10/ab165ba910e549fcc21fd561a33f534d86e81ae36c97b1019dcfe506b09692ff867c97794a54b49c9a83b8b485f529f0f58d24966c3a11863c97dc70814f4d50
|
||||
checksum: 10/b97f680753113bcd803cb174e40baa01e04aa4cb95ee62b48841336d9c48b278a2eeff71a4a0d7315b8f639fb1e38049925d3be1c6e266c158dc8f7d95d67eaa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
@ -15277,9 +15277,9 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-gyp@npm:^10.2.0":
|
||||
version: 10.2.0
|
||||
resolution: "node-gyp@npm:10.2.0"
|
||||
"node-gyp@npm:^10.0.1":
|
||||
version: 10.0.1
|
||||
resolution: "node-gyp@npm:10.0.1"
|
||||
dependencies:
|
||||
env-paths: "npm:^2.2.0"
|
||||
exponential-backoff: "npm:^3.1.1"
|
||||
|
|
@ -15287,13 +15287,13 @@ __metadata:
|
|||
graceful-fs: "npm:^4.2.6"
|
||||
make-fetch-happen: "npm:^13.0.0"
|
||||
nopt: "npm:^7.0.0"
|
||||
proc-log: "npm:^4.1.0"
|
||||
proc-log: "npm:^3.0.0"
|
||||
semver: "npm:^7.3.5"
|
||||
tar: "npm:^6.2.1"
|
||||
tar: "npm:^6.1.2"
|
||||
which: "npm:^4.0.0"
|
||||
bin:
|
||||
node-gyp: bin/node-gyp.js
|
||||
checksum: 10/41773093b1275751dec942b985982fd4e7a69b88cae719b868babcef3880ee6168aaec8dcaa8cd0b9fa7c84873e36cc549c6cac6a124ee65ba4ce1f1cc108cfe
|
||||
checksum: 10/578cf0c821f258ce4b6ebce4461eca4c991a4df2dee163c0624f2fe09c7d6d37240be4942285a0048d307230248ee0b18382d6623b9a0136ce9533486deddfa8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
@ -17073,10 +17073,10 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"proc-log@npm:^4.1.0":
|
||||
version: 4.2.0
|
||||
resolution: "proc-log@npm:4.2.0"
|
||||
checksum: 10/4e1394491b717f6c1ade15c570ecd4c2b681698474d3ae2d303c1e4b6ab9455bd5a81566211e82890d5a5ae9859718cc6954d5150bb18b09b72ecb297beae90a
|
||||
"proc-log@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "proc-log@npm:3.0.0"
|
||||
checksum: 10/02b64e1b3919e63df06f836b98d3af002b5cd92655cab18b5746e37374bfb73e03b84fe305454614b34c25b485cc687a9eebdccf0242cda8fda2475dd2c97e02
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
@ -17541,14 +17541,14 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"re2@npm:^1.21.4":
|
||||
version: 1.21.4
|
||||
resolution: "re2@npm:1.21.4"
|
||||
"re2@npm:^1.20.11":
|
||||
version: 1.20.11
|
||||
resolution: "re2@npm:1.20.11"
|
||||
dependencies:
|
||||
install-artifact-from-github: "npm:^1.3.5"
|
||||
nan: "npm:^2.20.0"
|
||||
node-gyp: "npm:^10.2.0"
|
||||
checksum: 10/926871cc84dab656afc035118c79d121211f21f4154084d7f6c05a05f746b5355f04e80a773db9ca817718dde03c561421b0a962300698c9f2eeafa4f70fd364
|
||||
nan: "npm:^2.19.0"
|
||||
node-gyp: "npm:^10.0.1"
|
||||
checksum: 10/a8665c861c632c67db448832a5a6a0092a1a29b8b6b731d6ce10f0017ba2871620780a745a8b2cbdd77e57ecf9e7bc8983c7ec5e10e6da6c06079a98146db443
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
@ -19655,20 +19655,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tar@npm:^6.2.1":
|
||||
version: 6.2.1
|
||||
resolution: "tar@npm:6.2.1"
|
||||
dependencies:
|
||||
chownr: "npm:^2.0.0"
|
||||
fs-minipass: "npm:^2.0.0"
|
||||
minipass: "npm:^5.0.0"
|
||||
minizlib: "npm:^2.1.1"
|
||||
mkdirp: "npm:^1.0.3"
|
||||
yallist: "npm:^4.0.0"
|
||||
checksum: 10/bfbfbb2861888077fc1130b84029cdc2721efb93d1d1fb80f22a7ac3a98ec6f8972f29e564103bbebf5e97be67ebc356d37fa48dbc4960600a1eb7230fbd1ea0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tdigest@npm:^0.1.1":
|
||||
version: 0.1.2
|
||||
resolution: "tdigest@npm:0.1.2"
|
||||
|
|
|
|||
Loading…
Reference in a new issue