From 7138d55a6322d3b5d38dc965f44f903107827e58 Mon Sep 17 00:00:00 2001 From: fortuna Date: Wed, 17 Oct 2018 12:19:51 -0400 Subject: [PATCH 1/2] Remove ss-libev --- src/shadowbox/docker/Dockerfile | 4 - .../infrastructure/ip_location.spec.ts | 45 ---- src/shadowbox/infrastructure/ip_location.ts | 55 ---- src/shadowbox/package.json | 2 - src/shadowbox/scripts/install_shadowsocks.sh | 71 ------ .../server/libev_shadowsocks_server.ts | 234 ------------------ src/shadowbox/server/main.ts | 23 +- yarn.lock | 37 +-- 8 files changed, 25 insertions(+), 446 deletions(-) delete mode 100644 src/shadowbox/infrastructure/ip_location.spec.ts delete mode 100644 src/shadowbox/infrastructure/ip_location.ts delete mode 100755 src/shadowbox/scripts/install_shadowsocks.sh delete mode 100644 src/shadowbox/server/libev_shadowsocks_server.ts diff --git a/src/shadowbox/docker/Dockerfile b/src/shadowbox/docker/Dockerfile index d4c802bd..52246a14 100644 --- a/src/shadowbox/docker/Dockerfile +++ b/src/shadowbox/docker/Dockerfile @@ -19,9 +19,6 @@ RUN go get github.com/Jigsaw-Code/outline-ss-server # See versions at https://hub.docker.com/_/node/ FROM node:8.11.3-alpine -# Versions can be found at https://github.com/shadowsocks/shadowsocks-libev/releases -ARG SS_VERSION=3.2.0 - # Save metadata on the software versions we are using. LABEL shadowbox.node_version=8.11.3 LABEL shadowbox.shadowsocks_version="${SS_VERSION}" @@ -37,7 +34,6 @@ COPY src/shadowbox/scripts/update_mmdb.sh /etc/periodic/weekly/update_mmdb # TODO: remove the ACL file, used to prevent access to localhost and LAN, when migrating to shadowsocks-go. COPY src/shadowbox/shadowbox.acl /root/shadowbox/shadowsocks.acl -RUN sh ./scripts/install_shadowsocks.sh $SS_VERSION RUN /etc/periodic/weekly/update_mmdb WORKDIR /root/shadowbox diff --git a/src/shadowbox/infrastructure/ip_location.spec.ts b/src/shadowbox/infrastructure/ip_location.spec.ts deleted file mode 100644 index 073c47d0..00000000 --- a/src/shadowbox/infrastructure/ip_location.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 The Outline Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as ip_location from './ip_location'; - -function testIpLocationService(name: string, service: ip_location.IpLocationService) { - describe(name, () => { - it('returns ZZ on unknown country', (done) => { - service.countryForIp('127.0.0.1') - .then((countryCode) => { - expect(countryCode).toEqual('ZZ'); - done(); - }) - .catch((e) => { - done.fail(e); - }); - }); - it('returns AU for 1.0.0.1', (done) => { - service.countryForIp('1.0.0.1') - .then((countryCode) => { - expect(countryCode).toEqual('AU'); - done(); - }) - .catch((e) => { - done.fail(e); - }); - }); - }); -} - -testIpLocationService( - 'MmdbLocationService', - new ip_location.MmdbLocationService( - 'third_party/maxmind/GeoLite2-Country_20180327/GeoLite2-Country.mmdb')); diff --git a/src/shadowbox/infrastructure/ip_location.ts b/src/shadowbox/infrastructure/ip_location.ts deleted file mode 100644 index 7fb52a03..00000000 --- a/src/shadowbox/infrastructure/ip_location.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2018 The Outline Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as maxmind from 'maxmind'; - -export interface IpLocationService { - // Returns the 2-digit country code for the IP address. - countryForIp(ipAddress: string): Promise; -} - -// An IpLocationService that uses the node-maxmind package. -// The database is downloaded by scripts/update_mmdb.sh. -// The Dockerfile runs this script on boot and configures the system to run it weekly. -export class MmdbLocationService implements IpLocationService { - private readonly db: Promise; - - constructor(filename: string) { - this.db = new Promise((fulfill, reject) => { - // TODO: Change type to maxmind.Options once the type definition is updated - // with these fields. - const options: {} = {watchForUpdates: true, watchForUpdatesNonPersistent: true}; - maxmind.open(filename, options, (err, reader) => { - if (err) { - reject(err); - } else { - fulfill(reader); - } - }); - }); - } - - countryForIp(ipAddress) { - return this.db.then((reader) => { - if (!reader) { - throw new Error('MMDB reader is not valid'); - } - if (!maxmind.validate(ipAddress)) { - throw new Error('Invalid IP address'); - } - const result = reader.get(ipAddress); - return (result && result.country && result.country.iso_code) || 'ZZ'; - }); - } -} diff --git a/src/shadowbox/package.json b/src/shadowbox/package.json index 4f460745..714f4603 100644 --- a/src/shadowbox/package.json +++ b/src/shadowbox/package.json @@ -13,7 +13,6 @@ "ShadowsocksConfig": "Jigsaw-Code/outline-shadowsocksconfig#^v0.0.8", "ipaddr.js": "^1.4.0", "js-yaml": "^3.12.0", - "maxmind": "^2.7.0", "prom-client": "^11.1.3", "randomstring": "^1.1.5", "request-lite": "^2.40.1", @@ -22,7 +21,6 @@ }, "devDependencies": { "@types/js-yaml": "^3.11.2", - "@types/maxmind": "^2", "@types/node": "^8", "@types/randomstring": "^1.1.6", "@types/restify": "^2.0.41" diff --git a/src/shadowbox/scripts/install_shadowsocks.sh b/src/shadowbox/scripts/install_shadowsocks.sh deleted file mode 100755 index 3c127827..00000000 --- a/src/shadowbox/scripts/install_shadowsocks.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash -eu -# -# Copyright 2018 The Outline Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# TODO(fortuna): Delete once outline-ss-server rolls out - -VERSION=$1 -DOWNLOAD_URL=https://github.com/shadowsocks/shadowsocks-libev/releases/download/v${VERSION}/shadowsocks-libev-${VERSION}.tar.gz -BUILD_DIR=/src/shadowsocks-libev - -set -ex - -# Install runtime dependencies -apk add --no-cache libev c-ares libsodium mbedtls pcre - -# Install build dependencies -apk add --no-cache --virtual BUILD_DEPS \ - autoconf automake build-base gettext-dev libev-dev libsodium-dev libtool \ - linux-headers mbedtls-dev openssl-dev pcre-dev tar c-ares-dev - -# Build. -mkdir -p $BUILD_DIR -cd $BUILD_DIR -curl -sSL $DOWNLOAD_URL | tar xz --strip 1 - -./configure --disable-documentation -make install - -# Other licenses and/or source. -# Alpine does not always include LICENSE files and has no equivalent of -# Debian's "apt source" command. So, we have to manually roll something. -# We'll place licenses in the root folder of the image, named LICENSE.xxx, -# and sources under /src. - -# libev (BSD or GPL2): -# http://software.schmorp.de/pkg/libev.html -curl -sS http://cvs.schmorp.de/libev/LICENSE > /LICENSE.libev - -# c-ares (MIT): -# https://c-ares.haxx.se/ -curl -sS https://c-ares.haxx.se/license.html > /LICENSE.c-ares.html - -# libsodium (ISC): -# https://libsodium.org/ -curl -sS https://raw.githubusercontent.com/jedisct1/libsodium/master/LICENSE > /LICENSE.libsodium - -# mbedtls (Apache): -# https://tls.mbed.org/ -curl -sS https://raw.githubusercontent.com/ARMmbed/mbedtls/development/apache-2.0.txt > /LICENSE.mbedtls - -# pcre (BSD): -# http://www.pcre.org/ -curl -sS http://www.pcre.org/licence.txt > /LICENSE.pcre - -# Clean shadowsocks-libev's folder, leaving the source in the image. -make clean - -# Remove build dependencies. -apk del BUILD_DEPS diff --git a/src/shadowbox/server/libev_shadowsocks_server.ts b/src/shadowbox/server/libev_shadowsocks_server.ts deleted file mode 100644 index a54ddd3c..00000000 --- a/src/shadowbox/server/libev_shadowsocks_server.ts +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2018 The Outline Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as child_process from 'child_process'; -import * as dgram from 'dgram'; -import * as dns from 'dns'; -import {makeConfig, SIP002_URI} from 'ShadowsocksConfig/shadowsocks_config'; - -import {IpLocationService} from '../infrastructure/ip_location'; -import * as logging from '../infrastructure/logging'; -import {AccessKey, ShadowsocksServer} from '../model/shadowsocks_server'; - -import {UsageMetricsWriter} from './shared_metrics'; - -const SHADOWSOCKS_ACL_PATH = '/root/shadowbox/shadowsocks.acl'; - -export async function createLibevShadowsocksServer( - publicAddress: string, metricsSocketPort: number, ipLocation: IpLocationService, - usageWriter: UsageMetricsWriter, verbose: boolean) { - const metricsSocket = await createBoundUdpSocket(metricsSocketPort); - return new LibevShadowsocksServer(publicAddress, metricsSocket, ipLocation, usageWriter, verbose); -} - -// Runs shadowsocks-libev server instances. -// TODO(fortuna): Delete once outline-ss-server rolls out -export class LibevShadowsocksServer implements ShadowsocksServer { - private portId = new Map(); - private portInboundBytes = new Map(); - private portIps = new Map(); - private keyProcess = new Map(); - private keys = new Map(); - - constructor( - private readonly publicAddress: string, private readonly metricsSocket: dgram.Socket, - ipLocation: IpLocationService, usageWriter: UsageMetricsWriter, - private readonly verbose: boolean) { - metricsSocket.on('message', (buf: Buffer) => { - let metricsMessage; - try { - metricsMessage = parseMetricsMessage(buf); - } catch (err) { - logging.error(`Error parsing metrics message ${buf}: ${err.stack}`); - return; - } - let previousTotalInboundBytes = this.portInboundBytes[metricsMessage.portNumber] || 0; - if (previousTotalInboundBytes > metricsMessage.totalInboundBytes) { - // totalInboundBytes is a counter that monotonically increases. A drop means - // ss-server got restarted, so we set the previous value to zero. - previousTotalInboundBytes = 0; - } - const dataDelta = metricsMessage.totalInboundBytes - previousTotalInboundBytes; - if (dataDelta === 0) { - return; - } - this.portInboundBytes[metricsMessage.portNumber] = metricsMessage.totalInboundBytes; - getConnectedClientIPAddresses(metricsMessage.portNumber) - .catch((e) => { - logging.error( - `Unable to get client IP for port ${metricsMessage.portNumber}: ${e.stack}`); - return []; - }) - .then((ipAddresses: string[]) => { - // We keep using the same IP addresses if we don't see any IP for a port. - // This may happen if getConnectedClientIPAddresses runs when there's no TCP - // connection open at that moment. - if (ipAddresses && ipAddresses.length > 0) { - this.portIps.set(metricsMessage.portNumber, ipAddresses); - } else { - ipAddresses = this.portIps.get(metricsMessage.portNumber) || []; - } - return Promise.all(ipAddresses.map((ipAddress) => { - return ipLocation.countryForIp(ipAddress).catch((e) => { - logging.error(`failed to get country for IP: ${e.stack}`); - return 'ZZ'; - }); - })); - }) - .then((countries: string[]) => { - const dedupedCountries = [...new Set(countries)].sort(); - usageWriter.writeBytesTransferred( - this.portId[metricsMessage.portNumber] || '', dataDelta, dedupedCountries); - }) - .catch((err: Error) => { - logging.error(`Unable to write bytes transferred: ${err.stack}`); - }); - }); - } - - // Update spawns the ss-libev subprocess and returns, likely before the instances - // are ready and serving. - update(newKeys: AccessKey[]): Promise { - return new Promise((resolve, reject) => { - const oldKeys = this.keys; - this.keys = new Map(); - // Start keys that were added - for (const key of newKeys) { - this.keys[key.id] = key; - const oldKey = oldKeys.get(key.id); - if (oldKey) { - continue; - } - this.startInstance(key); - } - // Stop keys that were removed. - for (const oldKey of oldKeys.values()) { - if (!this.keys.has(oldKey.id)) { - this.stopInstance(oldKey.id); - } - } - resolve(); - }); - } - - private startInstance(key: AccessKey): child_process.ChildProcess { - logging.info(`Starting server on port ${key.port}`); - this.portId[key.port] = key.id; - - const metricsAddress = this.metricsSocket.address(); - const commandArguments = [ - '-m', key.cipher, // Encryption method - '-u', // Allow UDP - '--fast-open', // Allow TCP fast open - '-p', key.port.toString(), '-k', key.secret, '--manager-address', - `${metricsAddress.address}:${metricsAddress.port}`, '--acl', SHADOWSOCKS_ACL_PATH - ]; - logging.info('starting ss-server with args: ' + commandArguments.join(' ')); - // Add the system DNS servers. - // TODO(fortuna): Add dns.getServers to @types/node. - for (const dnsServer of dns.getServers()) { - commandArguments.push('-d'); - commandArguments.push(dnsServer); - } - if (this.verbose) { - // Make the Shadowsocks output verbose in debug mode. - commandArguments.push('-v'); - } - const childProcess = child_process.spawn('ss-server', commandArguments); - this.keyProcess[key.id] = childProcess; - - childProcess.on('error', (error) => { - logging.error(`Error spawning server on port ${key.port}: ${error}`); - }); - // TODO(fortuna): Add restart logic. - childProcess.on('exit', (code, signal) => { - logging.info(`Server on port ${key.port} has exited. Code: ${code}, Signal: ${signal}`); - }); - // This exposes the ss-server output on the docker logs. - // TODO(fortuna): Consider saving the output and expose it through the manager service. - childProcess.stdout.pipe(process.stdout); - childProcess.stderr.pipe(process.stderr); - - // Generate a SIP002 access url. - const accessUrl = SIP002_URI.stringify(makeConfig({ - host: this.publicAddress, - port: key.port, - method: key.cipher, - password: key.secret, - outline: 1, - })); - - return childProcess; - } - - private stopInstance(keyId: string) { - this.keyProcess.get(keyId).kill(); - this.keyProcess.delete(keyId); - } -} - -function getConnectedClientIPAddresses(portNumber: number): Promise { - const lsofCommand = `lsof -i tcp:${portNumber} -n -P -Fn ` + - ' | grep \'\\->\'' + // only look at connection lines (e.g. skips "p8855" and "f60") - ' | sed \'s/:\\d*$//g\'' + // remove p - ' | sed \'s/n\\S*->//g\'' + // remove first part of address - ' | sed \'s/\\[//g\'' + // remove [] (used by ipv6) - ' | sed \'s/\\]//g\'' + // remove ] (used by ipv6) - ' | sort | uniq'; // remove duplicates - return execCmd(lsofCommand).then((output: string) => { - return output.trim().split('\n').map((e) => e.trim()).filter(Boolean); - }); -} - -function execCmd(cmd: string): Promise { - return new Promise((fulfill, reject) => { - child_process.exec(cmd, (error: child_process.ExecError, stdout: string, stderr: string) => { - if (error) { - reject(error); - } else { - fulfill(stdout.trim()); - } - }); - }); -} - -interface MetricsMessage { - portNumber: number; - totalInboundBytes: number; -} - -function parseMetricsMessage(buf): MetricsMessage { - const jsonString = buf.toString() - .substr('stat: '.length) // remove leading "stat: " - .replace(/\0/g, ''); // remove trailing null terminator - // statObj is in the form {"port#": totalInboundBytes}, where - // there is always only 1 port# per JSON object. If there are multiple - // ss-servers communicating to the same manager, we will get multiple - // message events. - const statObj = JSON.parse(jsonString); - // Object.keys is used here because node doesn't support Object.values. - const portNumber = parseInt(Object.keys(statObj)[0], 10); - const totalInboundBytes = statObj[portNumber]; - return {portNumber, totalInboundBytes}; -} - -// Creates a bound UDP socket on a random unused port. -function createBoundUdpSocket(portNumber: number): Promise { - const socket = dgram.createSocket('udp4'); - return new Promise((fulfill, reject) => { - socket.bind(portNumber, 'localhost', () => { - return fulfill(socket); - }); - }); -} diff --git a/src/shadowbox/server/main.ts b/src/shadowbox/server/main.ts index f62ad997..b551bfb8 100644 --- a/src/shadowbox/server/main.ts +++ b/src/shadowbox/server/main.ts @@ -21,21 +21,18 @@ import * as restify from 'restify'; import {RealClock} from '../infrastructure/clock'; import {PortProvider} from '../infrastructure/get_port'; -import * as ip_location from '../infrastructure/ip_location'; import * as json_config from '../infrastructure/json_config'; import * as logging from '../infrastructure/logging'; import {PrometheusClient, runPrometheusScraper} from '../infrastructure/prometheus_scraper'; import {RolloutTracker} from '../infrastructure/rollout'; import {AccessKeyId} from '../model/access_key'; -import {ShadowsocksServer} from '../model/shadowsocks_server'; -import {createLibevShadowsocksServer} from './libev_shadowsocks_server'; import {LegacyManagerMetrics, LegacyManagerMetricsJson, PrometheusManagerMetrics} from './manager_metrics'; import {bindService, ShadowsocksManagerService} from './manager_service'; import {OutlineShadowsocksServer} from './outline_shadowsocks_server'; import {AccessKeyConfigJson, ServerAccessKeyRepository} from './server_access_key'; import * as server_config from './server_config'; -import {createPrometheusUsageMetricsWriter, OutlineSharedMetricsPublisher, PrometheusUsageMetrics, RestMetricsCollectorClient, SharedMetricsPublisher} from './shared_metrics'; +import {OutlineSharedMetricsPublisher, PrometheusUsageMetrics, RestMetricsCollectorClient, SharedMetricsPublisher} from './shared_metrics'; const DEFAULT_STATE_DIR = '/root/shadowbox/persisted-state'; const MAX_STATS_FILE_AGE_MS = 5000; @@ -81,6 +78,7 @@ function reserveAccessKeyPorts( } } +// TODO: Get rid of this after 30 days of everyone's migration to Prometheus. function createLegacyManagerMetrics(configFilename: string): LegacyManagerMetrics { const metricsConfig = readMetricsConfig(configFilename); return new LegacyManagerMetrics( @@ -174,19 +172,10 @@ async function main() { const managerMetrics = new PrometheusManagerMetrics(prometheusClient, legacyManagerMetrics); const metricsReader = new PrometheusUsageMetrics(prometheusClient); - const rollouts = createRolloutTracker(serverConfig); - let shadowsocksServer: ShadowsocksServer; - if (rollouts.isRolloutEnabled('outline-ss-server', 0)) { - shadowsocksServer = - new OutlineShadowsocksServer( - getPersistentFilename('outline-ss-server/config.yml'), verbose, ssMetricsLocation) - .enableCountryMetrics(MMDB_LOCATION); - } else { - const ipLocation = new ip_location.MmdbLocationService(MMDB_LOCATION); - const metricsWriter = createPrometheusUsageMetricsWriter(prometheus.register); - shadowsocksServer = await createLibevShadowsocksServer( - proxyHostname, await portProvider.reserveNewPort(), ipLocation, metricsWriter, verbose); - } + const shadowsocksServer = + new OutlineShadowsocksServer( + getPersistentFilename('outline-ss-server/config.yml'), verbose, ssMetricsLocation) + .enableCountryMetrics(MMDB_LOCATION); const accessKeyRepository = new ServerAccessKeyRepository( portProvider, proxyHostname, accessKeyConfig, shadowsocksServer); diff --git a/yarn.lock b/yarn.lock index caf6463f..ad0368b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -212,9 +212,9 @@ version "2.5.53" resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.5.53.tgz#4e0cefad09df5ec48c8dd40433512f84b1568d61" -"@types/maxmind@^2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/maxmind/-/maxmind-2.0.3.tgz#c8633e85e1440c145dfa87fe4782a5c840b7ad21" +"@types/js-yaml@^3.11.2": + version "3.11.2" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.11.2.tgz#699ad86054cc20043c30d66a6fcde30bbf5d3d5e" "@types/mime@*": version "2.0.0" @@ -612,14 +612,14 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -big-integer@^1.6.31: - version "1.6.31" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.31.tgz#6d7852486e67c642502dcc03f7225a245c9fc7fa" - bignumber.js@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-2.4.0.tgz#838a992da9f9d737e0f4b2db0be62bb09dd0c5e8" +bintrees@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" + block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -3056,13 +3056,6 @@ map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" -maxmind@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/maxmind/-/maxmind-2.7.0.tgz#b6695cf2b98da825b418a228c4307ac2d790714d" - dependencies: - big-integer "^1.6.31" - tiny-lru "^1.6.1" - md5.js@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" @@ -3714,6 +3707,12 @@ progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" +prom-client@^11.1.3: + version "11.1.3" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-11.1.3.tgz#bd9566ddcc6cb52e47732547191d777fbe35d12e" + dependencies: + tdigest "^0.1.1" + prompt@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prompt/-/prompt-1.0.0.tgz#8e57123c396ab988897fb327fd3aedc3e735e4fe" @@ -4686,6 +4685,12 @@ tar@^2.2.1: fstream "^1.0.2" inherits "2" +tdigest@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021" + dependencies: + bintrees "1.0.1" + temp-file@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/temp-file/-/temp-file-3.1.3.tgz#24c144994f033be1ccf6773280c8f7f1c91691a9" @@ -4737,10 +4742,6 @@ timers-browserify@^1.0.1: dependencies: process "~0.11.0" -tiny-lru@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-1.6.1.tgz#addb5c043311d1f07cd3a81d706ae739b8efebb1" - tinycolor2@^1.1.2: version "1.4.1" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" From d89b17b0875cab53e84a8f8e51d14b72e4715dc3 Mon Sep 17 00:00:00 2001 From: fortuna Date: Mon, 10 Dec 2018 11:11:41 -0500 Subject: [PATCH 2/2] Remove ipaddr.sj --- src/shadowbox/package.json | 1 - yarn.lock | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/shadowbox/package.json b/src/shadowbox/package.json index 714f4603..3e141007 100644 --- a/src/shadowbox/package.json +++ b/src/shadowbox/package.json @@ -11,7 +11,6 @@ ], "dependencies": { "ShadowsocksConfig": "Jigsaw-Code/outline-shadowsocksconfig#^v0.0.8", - "ipaddr.js": "^1.4.0", "js-yaml": "^3.12.0", "prom-client": "^11.1.3", "randomstring": "^1.1.5", diff --git a/yarn.lock b/yarn.lock index ad0368b4..cdc4581f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2588,7 +2588,7 @@ ipaddr.js@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0" -ipaddr.js@1.6.0, ipaddr.js@^1.4.0: +ipaddr.js@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" @@ -2865,6 +2865,10 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonic@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/jsonic/-/jsonic-0.3.1.tgz#da306185dc635b649ad934e3f6826188cad73bdb" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"