mirror of
https://github.com/OutlineFoundation/outline-server.git
synced 2026-08-30 13:23:00 +00:00
Migrate to eslint
This commit is contained in:
parent
17d1a63f2d
commit
7389ce724f
51 changed files with 2217 additions and 643 deletions
2
.eslintignore
Normal file
2
.eslintignore
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/build/
|
||||
node_modules/
|
||||
65
.eslintrc.json
Normal file
65
.eslintrc.json
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
"argsIgnorePattern": "^_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"check-version-tracker.js",
|
||||
"rollup-common.js",
|
||||
"rollup.config.js",
|
||||
"web-test-runner.config.js"
|
||||
],
|
||||
"env": {
|
||||
"node": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"packages/lit-html/src/test/version-stability_test.js"
|
||||
],
|
||||
"env": {
|
||||
"mocha": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*_test.ts",
|
||||
"packages/labs/ssr/custom_typings/node.d.ts",
|
||||
"packages/labs/ssr/src/test/integration/tests/**",
|
||||
"packages/labs/ssr/src/lib/util/parse5-utils.ts"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
2462
package-lock.json
generated
2462
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -3,12 +3,14 @@
|
|||
"private": true,
|
||||
"devDependencies": {
|
||||
"@types/jasmine": "^3.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||
"@typescript-eslint/parser": "^5.14.0",
|
||||
"eslint": "^8.10.0",
|
||||
"generate-license-file": "^1.2.0",
|
||||
"husky": "^1.3.1",
|
||||
"jasmine": "^3.5.0",
|
||||
"prettier": "^2.4.1",
|
||||
"pretty-quick": "^3.1.1",
|
||||
"tslint": "^5.9.1",
|
||||
"typescript": "^4"
|
||||
},
|
||||
"engines": {
|
||||
|
|
@ -24,7 +26,7 @@
|
|||
"format:all": "prettier --write \"**/*.{cjs,html,js,json,md,ts}\"",
|
||||
"lint": "npm run lint:sh && npm run lint:ts",
|
||||
"lint:sh": "bash ./scripts/shellcheck.sh",
|
||||
"lint:ts": "npx tslint 'src/**/*.ts' -e '**/node_modules/**'",
|
||||
"lint:ts": "npx eslint \"**/*.{js,ts}\"",
|
||||
"test": "npm run lint && npm run action metrics_server/test && npm run action sentry_webhook/build && npm run action server_manager/test && npm run action shadowbox/test"
|
||||
},
|
||||
"workspaces": [
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import {
|
|||
postConnectionMetrics,
|
||||
} from './connection_metrics';
|
||||
import {InsertableTable} from './infrastructure/table';
|
||||
import {HourlyConnectionMetricsReport} from './model';
|
||||
|
||||
class FakeConnectionsTable implements InsertableTable<ConnectionRow> {
|
||||
public rows: ConnectionRow[] | undefined;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import {Table} from '@google-cloud/bigquery';
|
||||
import {InsertableTable} from './infrastructure/table';
|
||||
import {HourlyConnectionMetricsReport, HourlyUserConnectionMetricsReport} from './model';
|
||||
import {HourlyConnectionMetricsReport} from './model';
|
||||
|
||||
export interface ConnectionRow {
|
||||
serverId: string;
|
||||
|
|
@ -36,7 +36,7 @@ export class BigQueryConnectionsTable implements InsertableTable<ConnectionRow>
|
|||
export function postConnectionMetrics(
|
||||
table: InsertableTable<ConnectionRow>,
|
||||
report: HourlyConnectionMetricsReport
|
||||
) {
|
||||
): Promise<void> {
|
||||
return table.insert(getConnectionRowsFromReport(report));
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ function getConnectionRowsFromReport(report: HourlyConnectionMetricsReport): Con
|
|||
|
||||
// Returns true iff testObject contains a valid HourlyConnectionMetricsReport.
|
||||
export function isValidConnectionMetricsReport(
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
testObject: any
|
||||
): testObject is HourlyConnectionMetricsReport {
|
||||
if (!testObject) {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export async function postFeatureMetrics(
|
|||
}
|
||||
|
||||
// Returns true iff `obj` contains a valid DailyFeatureMetricsReport.
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function isValidFeatureMetricsReport(obj: any): obj is DailyFeatureMetricsReport {
|
||||
if (!obj) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ const SALESFORCE_FORM_VALUES_PROD: SalesforceFormValues = {
|
|||
|
||||
// Returns whether a Sentry event should be sent to Salesforce by checking that it contains an
|
||||
// email address.
|
||||
export function shouldPostEventToSalesforce(event: sentry.SentryEvent) {
|
||||
export function shouldPostEventToSalesforce(event: sentry.SentryEvent): boolean {
|
||||
return !!event.user && !!event.user.email;
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +141,7 @@ function getSalesforceFormData(
|
|||
form.push(encodeFormData(formFields.sentryEventUrl, getSentryEventUrl(project, event.event_id)));
|
||||
form.push(encodeFormData(formFields.description, event.message));
|
||||
form.push(encodeFormData(formFields.type, isClient ? 'Outline client' : 'Outline manager'));
|
||||
if (!!event.tags) {
|
||||
if (event.tags) {
|
||||
const tags = getTagsMap(event.tags);
|
||||
form.push(encodeFormData(formFields.category, tags.get('category')));
|
||||
form.push(encodeFormData(formFields.os, tags.get('os.name')));
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2020 The Outline Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
@ -74,7 +75,7 @@ exports.makeConfig = (options) => {
|
|||
// @sentry/electron depends on electron code, even though it's never activated
|
||||
// in the browser. Webpack still tries to build it, but fails with missing APIs.
|
||||
// The IgnorePlugin prevents the compilation of the electron dependency.
|
||||
new webpack.IgnorePlugin(/^electron$/),
|
||||
new webpack.IgnorePlugin({resourceRegExp: /^electron$/, contextRegExp: /@sentry\/electron/}),
|
||||
new CopyPlugin(
|
||||
[
|
||||
{from: 'index.html', to: '.'},
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2020 The Outline Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
|
|||
|
|
@ -248,5 +248,5 @@ export class RestApiSession implements DigitalOceanSession {
|
|||
// DigitalOcean APIs.
|
||||
function makeValidDropletName(name: string): string {
|
||||
// Remove all characters outside of A-Z, a-z, 0-9 and '-'.
|
||||
return name.replace(/[^A-Za-z0-9\-]/g, '');
|
||||
return name.replace(/[^A-Za-z0-9-]/g, '');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -615,7 +615,7 @@ export class RestApiClient {
|
|||
// 'GET', new URL('https://oauth2.googleapis.com/revoke'), headers, parameters);
|
||||
// }
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private async fetchAuthenticated<T>(method: string, url: URL, headers: Map<string, string>, parameters?: Map<string, string>, data?: any): Promise<T> {
|
||||
const httpHeaders = new Map(headers);
|
||||
|
||||
|
|
@ -627,7 +627,7 @@ export class RestApiClient {
|
|||
return this.fetchUnauthenticated(method, url, httpHeaders, parameters, data);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private async fetchUnauthenticated<T>(method: string, url: URL, headers: Map<string, string>, parameters?: Map<string, string>, data?: any): Promise<T> {
|
||||
const customHeaders = new Headers();
|
||||
headers.forEach((value, key) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2020 The Outline Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
@ -27,7 +28,7 @@ function generateRtlCss(css) {
|
|||
}
|
||||
// This is a Webpack loader that searches for <style> blocks and edits the CSS to support RTL
|
||||
// in a Polymer element.
|
||||
module.exports = function loader(content, map, meta) {
|
||||
module.exports = function loader(content, _map, _meta) {
|
||||
const callback = this.async();
|
||||
const styleRe = RegExp(/(<style[^>]*>)(\s*[^<\s](.*\n)*?\s*)(<\/style>)/gm);
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ export function runOauth(): OauthSession {
|
|||
</html>`);
|
||||
});
|
||||
|
||||
const rejectWrapper = {reject: (error: Error) => {}};
|
||||
const rejectWrapper = {reject: (_error: Error) => {}};
|
||||
const result = new Promise<string>((resolve, reject) => {
|
||||
rejectWrapper.reject = reject;
|
||||
// This is the POST endpoint that receives the access token and redirects to either DigitalOcean
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export function runOauth(): OauthSession {
|
|||
|
||||
// Handle OAuth redirect callback
|
||||
let isCancelled = false;
|
||||
const rejectWrapper = {reject: (error: Error) => {}};
|
||||
const rejectWrapper = {reject: (_error: Error) => {}};
|
||||
const tokenPromise = new Promise<string>((resolve, reject) => {
|
||||
rejectWrapper.reject = reject;
|
||||
app.get(REDIRECT_PATH, async (request: express.Request, response: express.Response) => {
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ function main() {
|
|||
});
|
||||
|
||||
const UPDATE_DOWNLOADED_EVENT = 'update-downloaded';
|
||||
autoUpdater.on(UPDATE_DOWNLOADED_EVENT, (ev, info) => {
|
||||
autoUpdater.on(UPDATE_DOWNLOADED_EVENT, (_ev, _info) => {
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send(UPDATE_DOWNLOADED_EVENT);
|
||||
}
|
||||
|
|
@ -228,7 +228,7 @@ function main() {
|
|||
});
|
||||
|
||||
// Restores the mainWindow if minimized and brings it into focus.
|
||||
ipcMain.on('bring-to-front', (event: IpcEvent) => {
|
||||
ipcMain.on('bring-to-front', (_event: IpcEvent) => {
|
||||
if (mainWindow.isMinimized()) {
|
||||
mainWindow.restore();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2020 The Outline Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2020 The Outline Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2020 The Outline Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export class InMemoryStorage implements Storage {
|
|||
return this.store.get(key) || null;
|
||||
}
|
||||
|
||||
key(index: number): string|null {
|
||||
key(_index: number): string|null {
|
||||
throw new Error('InMemoryStorage.key not implemented');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fs = require('fs');
|
||||
|
||||
const tarballBinary = fs.readFileSync(process.argv[2]);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fs = require('fs');
|
||||
|
||||
const tarballBinary = fs.readFileSync(process.argv[2]);
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ import {Region} from '../model/digitalocean';
|
|||
|
||||
|
||||
// Define functions from preload.ts.
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(global as any).onUpdateDownloaded = () => {};
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(global as any).bringToFront = () => {};
|
||||
|
||||
// Inject app-root element into DOM once before each test.
|
||||
|
|
|
|||
|
|
@ -121,10 +121,10 @@ export class App {
|
|||
private cloudAccounts: accounts.CloudAccounts) {
|
||||
appRoot.setAttribute('outline-version', this.version);
|
||||
|
||||
appRoot.addEventListener('ConnectDigitalOceanAccountRequested', (event: CustomEvent) => {
|
||||
appRoot.addEventListener('ConnectDigitalOceanAccountRequested', (_: CustomEvent) => {
|
||||
this.handleConnectDigitalOceanAccountRequest();
|
||||
});
|
||||
appRoot.addEventListener('CreateDigitalOceanServerRequested', (event: CustomEvent) => {
|
||||
appRoot.addEventListener('CreateDigitalOceanServerRequested', (_: CustomEvent) => {
|
||||
const digitalOceanAccount = this.cloudAccounts.getDigitalOceanAccount();
|
||||
if (digitalOceanAccount) {
|
||||
this.showDigitalOceanCreateServer(digitalOceanAccount);
|
||||
|
|
@ -135,8 +135,8 @@ export class App {
|
|||
});
|
||||
appRoot.addEventListener(
|
||||
'ConnectGcpAccountRequested',
|
||||
async (event: CustomEvent) => this.handleConnectGcpAccountRequest());
|
||||
appRoot.addEventListener('CreateGcpServerRequested', async (event: CustomEvent) => {
|
||||
async (_: CustomEvent) => this.handleConnectGcpAccountRequest());
|
||||
appRoot.addEventListener('CreateGcpServerRequested', async (_: CustomEvent) => {
|
||||
this.appRoot.getAndShowGcpCreateServerApp().start(this.gcpAccount);
|
||||
});
|
||||
appRoot.addEventListener('GcpServerCreated', (event: CustomEvent) => {
|
||||
|
|
@ -144,11 +144,11 @@ export class App {
|
|||
this.addServer(this.gcpAccount.getId(), server);
|
||||
this.showServer(server);
|
||||
});
|
||||
appRoot.addEventListener('DigitalOceanSignOutRequested', (event: CustomEvent) => {
|
||||
appRoot.addEventListener('DigitalOceanSignOutRequested', (_: CustomEvent) => {
|
||||
this.disconnectDigitalOceanAccount();
|
||||
this.showIntro();
|
||||
});
|
||||
appRoot.addEventListener('GcpSignOutRequested', (event: CustomEvent) => {
|
||||
appRoot.addEventListener('GcpSignOutRequested', (_: CustomEvent) => {
|
||||
this.disconnectGcpAccount();
|
||||
this.showIntro();
|
||||
});
|
||||
|
|
@ -165,7 +165,7 @@ export class App {
|
|||
this.forgetServer(event.detail.serverId);
|
||||
});
|
||||
|
||||
appRoot.addEventListener('AddAccessKeyRequested', (event: CustomEvent) => {
|
||||
appRoot.addEventListener('AddAccessKeyRequested', (_: CustomEvent) => {
|
||||
this.addAccessKey();
|
||||
});
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ export class App {
|
|||
this.setDefaultDataLimit(displayDataAmountToDataLimit(event.detail.limit));
|
||||
});
|
||||
|
||||
appRoot.addEventListener('RemoveDefaultDataLimitRequested', (event: CustomEvent) => {
|
||||
appRoot.addEventListener('RemoveDefaultDataLimitRequested', (_: CustomEvent) => {
|
||||
this.removeDefaultDataLimit();
|
||||
});
|
||||
|
||||
|
|
@ -239,11 +239,11 @@ export class App {
|
|||
});
|
||||
});
|
||||
|
||||
appRoot.addEventListener('EnableMetricsRequested', (event: CustomEvent) => {
|
||||
appRoot.addEventListener('EnableMetricsRequested', (_: CustomEvent) => {
|
||||
this.setMetricsEnabled(true);
|
||||
});
|
||||
|
||||
appRoot.addEventListener('DisableMetricsRequested', (event: CustomEvent) => {
|
||||
appRoot.addEventListener('DisableMetricsRequested', (_: CustomEvent) => {
|
||||
this.setMetricsEnabled(false);
|
||||
});
|
||||
|
||||
|
|
@ -270,7 +270,7 @@ export class App {
|
|||
this.renameServer(event.detail.newName);
|
||||
});
|
||||
|
||||
appRoot.addEventListener('CancelServerCreationRequested', (event: CustomEvent) => {
|
||||
appRoot.addEventListener('CancelServerCreationRequested', (_: CustomEvent) => {
|
||||
this.cancelServerCreation(this.selectedServer);
|
||||
});
|
||||
|
||||
|
|
@ -437,7 +437,8 @@ export class App {
|
|||
// Wait for server config to load, then update the server view and list.
|
||||
if (isManagedServer(server)) {
|
||||
try {
|
||||
for await (const _ of server.monitorInstallProgress()) {}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
for await (const _ of server.monitorInstallProgress()) {/* empty */}
|
||||
} catch (error) {
|
||||
if (error instanceof errors.ServerInstallCanceledError) {
|
||||
// User clicked "Cancel" on the loading screen.
|
||||
|
|
@ -486,7 +487,7 @@ export class App {
|
|||
this.disconnectDigitalOceanAccount();
|
||||
};
|
||||
const oauthUi = this.appRoot.getDigitalOceanOauthFlow(signOutAction);
|
||||
while (true) {
|
||||
for (;;) {
|
||||
const status = await this.digitalOceanRetry(async () => {
|
||||
if (cancelled) {
|
||||
throw CANCELLED_ERROR;
|
||||
|
|
@ -787,7 +788,7 @@ export class App {
|
|||
// Asynchronously load "My Connection" and other access keys in order to no block showing the
|
||||
// server.
|
||||
setTimeout(async () => {
|
||||
this.showMetricsOptInWhenNeeded(server, view);
|
||||
this.showMetricsOptInWhenNeeded(server);
|
||||
try {
|
||||
const serverAccessKeys = await server.listAccessKeys();
|
||||
view.accessKeyRows = serverAccessKeys.map(this.convertToUiAccessKey.bind(this));
|
||||
|
|
@ -822,13 +823,13 @@ export class App {
|
|||
view.serverName = this.makeDisplayName(server);
|
||||
view.selectedPage = 'progressView';
|
||||
try {
|
||||
for await (view.installProgress of server.monitorInstallProgress()) {}
|
||||
for await (view.installProgress of server.monitorInstallProgress()) {/* empty */}
|
||||
} catch {
|
||||
// Ignore any errors; they will be handled by `this.addServer`.
|
||||
}
|
||||
}
|
||||
|
||||
private showMetricsOptInWhenNeeded(selectedServer: server.Server, serverView: ServerView) {
|
||||
private showMetricsOptInWhenNeeded(selectedServer: server.Server) {
|
||||
const showMetricsOptInOnce = () => {
|
||||
// Sanity check to make sure the running server is still displayed, i.e.
|
||||
// it hasn't been deleted.
|
||||
|
|
@ -1094,7 +1095,7 @@ export class App {
|
|||
// Don't let `ManualServerRepository.addServer` throw to avoid redundant error handling if we
|
||||
// are adding an existing server. Query the repository instead to treat the UI accordingly.
|
||||
const storedServer = this.manualServerRepository.findServer(serverConfig);
|
||||
if (!!storedServer) {
|
||||
if (storedServer) {
|
||||
this.appRoot.showNotification(this.appRoot.localize('notification-server-exists'), 5000);
|
||||
this.showServer(storedServer);
|
||||
return;
|
||||
|
|
@ -1201,7 +1202,7 @@ export class App {
|
|||
this.appRoot.showError(this.appRoot.localize('error-server-rename'));
|
||||
const oldName = this.selectedServer.getName();
|
||||
view.serverName = oldName;
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(view.$.serverSettings as any).serverName = oldName;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,25 +12,25 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(window as any).trustCertificate = (fingerprint: string) => {
|
||||
console.log(`Requested to trust certificate with fingerprint ${fingerprint}`);
|
||||
};
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(window as any).openImage = (basename: string) => {
|
||||
window.open(`./images/${basename})`);
|
||||
};
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
(window as any).onUpdateDownloaded = (callback: () => void) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(window as any).onUpdateDownloaded = (_callback: () => void) => {
|
||||
console.info(`Requested registration of callbak for update download`);
|
||||
};
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(window as any).runDigitalOceanOauth = () => {
|
||||
let isCancelled = false;
|
||||
const rejectWrapper = {reject: (error: Error) => {}};
|
||||
const rejectWrapper = {reject: (_error: Error) => {}};
|
||||
const result = new Promise((resolve, reject) => {
|
||||
rejectWrapper.reject = reject;
|
||||
window.open('https://cloud.digitalocean.com/account/api/tokens/new', 'noopener,noreferrer');
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
};
|
||||
};
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(window as any).bringToFront = () => {
|
||||
console.info(`Requested bringToFront`);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -89,7 +89,8 @@ export class DigitalOceanAccount implements digitalocean.Account {
|
|||
const server = this.createDigitalOceanServer(this.digitalOcean, response.droplet);
|
||||
server.onceDropletActive.then(async () => {
|
||||
console.timeEnd('activeServer');
|
||||
for await (const _ of server.monitorInstallProgress()) {}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
for await (const _ of server.monitorInstallProgress()) {/* do nothing */}
|
||||
console.timeEnd('servingServer');
|
||||
}).catch(e => console.log('Couldn\'t time installation', e));
|
||||
return server;
|
||||
|
|
@ -122,7 +123,7 @@ export class DigitalOceanAccount implements digitalocean.Account {
|
|||
|
||||
function sanitizeDigitalOceanToken(input: string): string {
|
||||
const sanitizedInput = input.trim();
|
||||
const pattern = /^[A-Za-z0-9_\/-]+$/;
|
||||
const pattern = /^[A-Za-z0-9_/-]+$/;
|
||||
if (!pattern.test(sanitizedInput)) {
|
||||
throw new Error('Invalid DigitalOcean Token');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ async function makeLocalize(language: string) {
|
|||
window.alert(`Could not load messages for language "${language}"`);
|
||||
}
|
||||
return (msgId: string, ...args: string[]): string => {
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const params = {} as {[key: string]: any};
|
||||
for (let i = 0; i < args.length; i += 2) {
|
||||
params[args[i]] = args[i + 1];
|
||||
|
|
@ -134,7 +134,7 @@ export class TestApp extends LitElement {
|
|||
this.language = newLanguage;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private select(querySelector: string): any {
|
||||
return this.shadowRoot.querySelector(querySelector);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2020 The Outline Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@ describe('getShortName', () => {
|
|||
});
|
||||
|
||||
it('returns the ID when geoId is null', () => {
|
||||
expect(getShortName({id: 'fake-id', location: null}, msgId => {
|
||||
expect(getShortName({id: 'fake-id', location: null}, _msgId => {
|
||||
fail();
|
||||
return null;
|
||||
})).toEqual('fake-id');
|
||||
});
|
||||
|
||||
it('returns empty string when the location is null', () => {
|
||||
expect(getShortName(null, msgId => {
|
||||
expect(getShortName(null, _msgId => {
|
||||
fail();
|
||||
return null;
|
||||
})).toEqual('');
|
||||
|
|
@ -46,7 +46,7 @@ describe('getShortName', () => {
|
|||
});
|
||||
|
||||
describe('localizeCountry', () => {
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if (!(Intl as any).DisplayNames) {
|
||||
console.log('country localization requires modern Intl features');
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export function localizeCountry(geoLocation: GeoLocation, language: string): str
|
|||
return '';
|
||||
}
|
||||
// TODO: Remove typecast after https://github.com/microsoft/TypeScript/pull/44022
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const displayName = new (Intl as any).DisplayNames([language], {type: 'region'});
|
||||
return displayName.of(geoLocation.countryCode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export class ManualServerRepository implements server.ManualServerRepository {
|
|||
|
||||
addServer(config: server.ManualServerConfig): Promise<server.ManualServer> {
|
||||
const existingServer = this.findServer(config);
|
||||
if (!!existingServer) {
|
||||
if (existingServer) {
|
||||
console.debug('server already added');
|
||||
return Promise.resolve(existingServer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ export class ShadowboxServer implements server.Server {
|
|||
}
|
||||
|
||||
isHealthy(timeoutMs = 30000): Promise<boolean> {
|
||||
return new Promise<boolean>((fulfill, reject) => {
|
||||
return new Promise<boolean>((fulfill, _reject) => {
|
||||
// Query the API and expect a successful response to validate that the
|
||||
// service is up and running.
|
||||
this.getServerConfig().then(
|
||||
|
|
@ -193,7 +193,7 @@ export class ShadowboxServer implements server.Server {
|
|||
this.serverConfig = serverConfig;
|
||||
fulfill(true);
|
||||
},
|
||||
(e) => {
|
||||
(_e) => {
|
||||
fulfill(false);
|
||||
});
|
||||
// Return not healthy if API doesn't complete within timeoutMs.
|
||||
|
|
@ -287,7 +287,7 @@ export class ShadowboxServer implements server.Server {
|
|||
}
|
||||
return response.text();
|
||||
},
|
||||
(error) => {
|
||||
(_error) => {
|
||||
throw new errors.ServerApiError(
|
||||
`API request to ${path} failed due to network error`);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -70,22 +70,22 @@ export class FakeGcpAccount implements gcp.Account {
|
|||
getRefreshToken(): string {
|
||||
return this.refreshToken;
|
||||
}
|
||||
createServer(projectId: string, name: string, zone: gcp.Zone): Promise<server.ManagedServer> {
|
||||
createServer(_projectId: string, _name: string, _zone: gcp.Zone): Promise<server.ManagedServer> {
|
||||
return undefined;
|
||||
}
|
||||
async listLocations(projectId: string): Promise<Readonly<gcp.ZoneOption[]>> {
|
||||
async listLocations(_projectId: string): Promise<Readonly<gcp.ZoneOption[]>> {
|
||||
return this.locations;
|
||||
}
|
||||
async listServers(projectId: string): Promise<server.ManagedServer[]> {
|
||||
async listServers(_projectId: string): Promise<server.ManagedServer[]> {
|
||||
return [];
|
||||
}
|
||||
async createProject(id: string, billingAccountId: string): Promise<gcp.Project> {
|
||||
async createProject(_id: string, _billingAccountId: string): Promise<gcp.Project> {
|
||||
return {
|
||||
id: 'project-id',
|
||||
name: 'project-name',
|
||||
};
|
||||
}
|
||||
async isProjectHealthy(projectId: string): Promise<boolean> {
|
||||
async isProjectHealthy(_projectId: string): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
async listOpenBillingAccounts(): Promise<gcp.BillingAccount[]> {
|
||||
|
|
@ -142,13 +142,13 @@ export class FakeServer implements server.Server {
|
|||
addAccessKey() {
|
||||
return Promise.reject(new Error('FakeServer.addAccessKey not implemented'));
|
||||
}
|
||||
renameAccessKey(accessKeyId: server.AccessKeyId, name: string) {
|
||||
renameAccessKey(_accessKeyId: server.AccessKeyId, _name: string) {
|
||||
return Promise.reject(new Error('FakeServer.renameAccessKey not implemented'));
|
||||
}
|
||||
removeAccessKey(accessKeyId: server.AccessKeyId) {
|
||||
removeAccessKey(_accessKeyId: server.AccessKeyId) {
|
||||
return Promise.reject(new Error('FakeServer.removeAccessKey not implemented'));
|
||||
}
|
||||
setHostnameForAccessKeys(hostname: string) {
|
||||
setHostnameForAccessKeys(_hostname: string) {
|
||||
return Promise.reject(new Error('FakeServer.setHostname not implemented'));
|
||||
}
|
||||
getHostnameForAccessKeys() {
|
||||
|
|
@ -163,13 +163,13 @@ export class FakeServer implements server.Server {
|
|||
setPortForNewAccessKeys(): Promise<void> {
|
||||
return Promise.reject(new Error('FakeServer.setPortForNewAccessKeys not implemented'));
|
||||
}
|
||||
setAccessKeyDataLimit(accessKeyId: string, limit: server.DataLimit): Promise<void> {
|
||||
setAccessKeyDataLimit(_accessKeyId: string, _limit: server.DataLimit): Promise<void> {
|
||||
return Promise.reject(new Error('FakeServer.setAccessKeyDataLimit not implemented'));
|
||||
}
|
||||
removeAccessKeyDataLimit(accessKeyId: string): Promise<void> {
|
||||
removeAccessKeyDataLimit(_accessKeyId: string): Promise<void> {
|
||||
return Promise.reject(new Error('FakeServer.removeAccessKeyDataLimit not implemented'));
|
||||
}
|
||||
setDefaultDataLimit(limit: server.DataLimit): Promise<void> {
|
||||
setDefaultDataLimit(_limit: server.DataLimit): Promise<void> {
|
||||
return Promise.reject(new Error('FakeServer.setDefaultDataLimit not implemented'));
|
||||
}
|
||||
removeDefaultDataLimit(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -640,12 +640,11 @@ export class AppRoot extends polymerElementWithLocalize {
|
|||
// resolve or reject the Promise. Note that they need to clean up whichever event handler
|
||||
// didn't fire so we don't leak it, which could cause future language changes to not work
|
||||
// properly by triggering old event listeners.
|
||||
let successHandler: () => void, failureHandler: () => void;
|
||||
successHandler = () => {
|
||||
const successHandler = () => {
|
||||
this.removeEventListener('app-localize-resources-error', failureHandler);
|
||||
resolve();
|
||||
};
|
||||
failureHandler = () => {
|
||||
const failureHandler = () => {
|
||||
this.removeEventListener('app-localize-resources-loaded', successHandler);
|
||||
reject(new Error(`Failed to load resources for language ${language}`));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -146,8 +146,7 @@ export class GcpCreateServerApp extends LitElement {
|
|||
return this.renderProjectSetup();
|
||||
case 'regionPicker':
|
||||
return this.renderRegionPicker();
|
||||
default: {
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ Polymer({
|
|||
}
|
||||
},
|
||||
|
||||
_handleNameInputBlur(event: FocusEvent) {
|
||||
_handleNameInputBlur(_event: FocusEvent) {
|
||||
const newName = this.serverName;
|
||||
if (!newName) {
|
||||
this.serverName = this.initialName;
|
||||
|
|
|
|||
|
|
@ -940,7 +940,7 @@ export class ServerView extends DirMixin(PolymerElement) {
|
|||
return `${utilizationPercentage}%`;
|
||||
}
|
||||
|
||||
_accessKeysAddedOrRemoved(changeRecord: unknown) {
|
||||
_accessKeysAddedOrRemoved(_changeRecord: unknown) {
|
||||
// Check for myConnection and regular access keys.
|
||||
let hasNonAdminAccessKeys = false;
|
||||
for (const ui in this.accessKeyRows) {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@ import {PolymerElement} from '@polymer/polymer/polymer-element';
|
|||
import type {PolymerElementProperties} from '@polymer/polymer/interfaces';
|
||||
import type {PaperDialogElement} from '@polymer/paper-dialog/paper-dialog';
|
||||
|
||||
class OutlineSurveyDialog extends DirMixin
|
||||
(PolymerElement) {
|
||||
class OutlineSurveyDialog extends DirMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="cloud-install-styles"></style>
|
||||
|
|
|
|||
|
|
@ -15,15 +15,15 @@
|
|||
export interface Clock {
|
||||
// Returns the current time in milliseconds from the epoch.
|
||||
now(): number;
|
||||
setInterval(callback, intervalMs): void;
|
||||
setInterval(callback: () => void, intervalMs: number): void;
|
||||
}
|
||||
|
||||
export class RealClock implements Clock {
|
||||
now() {
|
||||
now(): number {
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
setInterval(callback, intervalMs) {
|
||||
setInterval(callback, intervalMs: number): void {
|
||||
setInterval(callback, intervalMs);
|
||||
}
|
||||
}
|
||||
|
|
@ -32,15 +32,13 @@ export class RealClock implements Clock {
|
|||
// Useful for tests.
|
||||
export class ManualClock implements Clock {
|
||||
public nowMs = 0;
|
||||
private callbacks = [] as Function[];
|
||||
private callbacks = [] as (() => void)[];
|
||||
|
||||
constructor() {}
|
||||
|
||||
now() {
|
||||
now(): number {
|
||||
return this.nowMs;
|
||||
}
|
||||
|
||||
setInterval(callback, intervalMs) {
|
||||
setInterval(callback, _intervalMs): void {
|
||||
this.callbacks.push(callback);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ describe('isPortUsed', () => {
|
|||
|
||||
function listen(): Promise<net.Server> {
|
||||
const server = net.createServer();
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise((resolve, _reject) => {
|
||||
server.listen({host: 'localhost', port: 0, exclusive: true}, () => {
|
||||
resolve(server);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export class PortProvider {
|
|||
async reserveNewPort(): Promise<number> {
|
||||
// TODO: consider using a set of available ports, so we don't randomly
|
||||
// try the same port multiple times.
|
||||
while (true) {
|
||||
for (;;) {
|
||||
const port = getRandomPortOver1023();
|
||||
if (this.reservedPorts.has(port)) {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ function getCallsite(): Callsite {
|
|||
};
|
||||
const error = new Error();
|
||||
Error.captureStackTrace(error, getCallsite);
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const stack = error.stack as any as Callsite[];
|
||||
Error.prepareStackTrace = originalPrepareStackTrace;
|
||||
return stack[1];
|
||||
|
|
|
|||
|
|
@ -125,12 +125,12 @@ async function waitForPrometheusReady(prometheusEndpoint: string) {
|
|||
}
|
||||
|
||||
function isHttpEndpointHealthy(endpoint: string): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise((resolve, _) => {
|
||||
http
|
||||
.get(endpoint, (response) => {
|
||||
resolve(response.statusCode >= 200 && response.statusCode < 300);
|
||||
})
|
||||
.on('error', (e) => {
|
||||
.on('error', () => {
|
||||
// Prometheus is not ready yet.
|
||||
resolve(false);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import {PrometheusClient, QueryResultData} from '../infrastructure/prometheus_scraper';
|
||||
import {DataUsageByUser} from '../model/metrics';
|
||||
import {PrometheusManagerMetrics} from './manager_metrics';
|
||||
import {FakePrometheusClient} from './mocks/mocks';
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ const EXPECTED_ACCESS_KEY_PROPERTIES = [
|
|||
'dataLimit',
|
||||
].sort();
|
||||
|
||||
const SEND_NOTHING = (_httpCode, _data) => {/* do nothing */};
|
||||
|
||||
describe('ShadowsocksManagerService', () => {
|
||||
// After processing the response callback, we should set
|
||||
// responseProcessed=true. This is so we can detect that first the response
|
||||
|
|
@ -149,7 +151,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
'2606:2800:220:1:248:1893:25c8:1946',
|
||||
];
|
||||
for (const hostname of goodHostnames) {
|
||||
service.setHostnameForAccessKeys({params: {hostname}}, res, () => {});
|
||||
service.setHostnameForAccessKeys({params: {hostname}}, res, () => {/* do nothing */});
|
||||
}
|
||||
|
||||
responseProcessed = true;
|
||||
|
|
@ -162,7 +164,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
.accessKeys(getAccessKeyRepository())
|
||||
.build();
|
||||
|
||||
const res = {send: (httpCode) => {}};
|
||||
const res = {send: SEND_NOTHING};
|
||||
const next = (error) => {
|
||||
expect(error.statusCode).toEqual(400);
|
||||
};
|
||||
|
|
@ -205,7 +207,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
.serverConfig(serverConfig)
|
||||
.accessKeys(getAccessKeyRepository())
|
||||
.build();
|
||||
const res = {send: (httpCode) => {}};
|
||||
const res = {send: SEND_NOTHING};
|
||||
const next = (error) => {
|
||||
expect(error.statusCode).toEqual(400);
|
||||
responseProcessed = true;
|
||||
|
|
@ -220,13 +222,13 @@ describe('ShadowsocksManagerService', () => {
|
|||
.serverConfig(serverConfig)
|
||||
.accessKeys(getAccessKeyRepository())
|
||||
.build();
|
||||
const res = {send: (httpCode) => {}};
|
||||
const res = {send: SEND_NOTHING};
|
||||
const next = (error) => {
|
||||
expect(error.statusCode).toEqual(400);
|
||||
responseProcessed = true;
|
||||
done();
|
||||
};
|
||||
// tslint:disable-next-line: no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const badHostname = {params: {hostname: 123}} as any as {params: {hostname: string}};
|
||||
service.setHostnameForAccessKeys(badHostname, res, next);
|
||||
});
|
||||
|
|
@ -296,7 +298,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
spyOn(repo, 'createNewAccessKey').and.throwError('cannot write to disk');
|
||||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
|
||||
const res = {send: (httpCode, data) => {}};
|
||||
const res = {send: SEND_NOTHING};
|
||||
service.createNewAccessKey({params: {}}, res, (error) => {
|
||||
expect(error.statusCode).toEqual(500);
|
||||
responseProcessed = true; // required for afterEach to pass.
|
||||
|
|
@ -319,7 +321,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
expect(httpCode).toEqual(204);
|
||||
},
|
||||
};
|
||||
await service.setPortForNewAccessKeys({params: {port: NEW_PORT}}, res, () => {});
|
||||
await service.setPortForNewAccessKeys({params: {port: NEW_PORT}}, res, () => {/* do nothing */});
|
||||
const newKey = await repo.createNewAccessKey();
|
||||
expect(newKey.proxyParams.portNumber).toEqual(NEW_PORT);
|
||||
expect(oldKey.proxyParams.portNumber).not.toEqual(NEW_PORT);
|
||||
|
|
@ -410,8 +412,8 @@ describe('ShadowsocksManagerService', () => {
|
|||
.accessKeys(repo)
|
||||
.build();
|
||||
|
||||
await service.createNewAccessKey({params: {}}, {send: () => {}}, () => {});
|
||||
await service.setPortForNewAccessKeys({params: {port: NEW_PORT}}, {send: () => {}}, () => {});
|
||||
await service.createNewAccessKey({params: {}}, {send: () => {/* do nothing */}}, () => {/* do nothing */});
|
||||
await service.setPortForNewAccessKeys({params: {port: NEW_PORT}}, {send: () => {/* do nothing */}}, () => {/* do nothing */});
|
||||
const res = {
|
||||
send: (httpCode) => {
|
||||
expect(httpCode).toEqual(204);
|
||||
|
|
@ -421,7 +423,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
|
||||
const firstKeyConnection = new net.Server();
|
||||
firstKeyConnection.listen(OLD_PORT, async () => {
|
||||
await service.setPortForNewAccessKeys({params: {port: OLD_PORT}}, res, () => {});
|
||||
await service.setPortForNewAccessKeys({params: {port: OLD_PORT}}, res, () => {/* do nothing */});
|
||||
firstKeyConnection.close();
|
||||
done();
|
||||
});
|
||||
|
|
@ -451,7 +453,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
|
||||
const nonNumericPort = {params: {port: 'abc'}};
|
||||
await service.setPortForNewAccessKeys(
|
||||
// tslint:disable-next-line: no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
nonNumericPort as any as {params: {port: number}},
|
||||
res,
|
||||
next
|
||||
|
|
@ -469,7 +471,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
const key1 = await repo.createNewAccessKey();
|
||||
const key2 = await repo.createNewAccessKey();
|
||||
const res = {
|
||||
send: (httpCode, data) => {
|
||||
send: (httpCode, _data) => {
|
||||
expect(httpCode).toEqual(204);
|
||||
// expect that the only remaining key is the 2nd key we created.
|
||||
const keys = repo.listAccessKeys();
|
||||
|
|
@ -486,7 +488,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
spyOn(repo, 'removeAccessKey').and.throwError('cannot write to disk');
|
||||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
const key = await createNewAccessKeyWithName(repo, 'keyName1');
|
||||
const res = {send: (httpCode, data) => {}};
|
||||
const res = {send: (_httpCode, _data) => {/* do nothing */}};
|
||||
service.removeAccessKey({params: {id: key.id}}, res, (error) => {
|
||||
expect(error.statusCode).toEqual(500);
|
||||
responseProcessed = true; // required for afterEach to pass.
|
||||
|
|
@ -505,7 +507,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
const key = await createNewAccessKeyWithName(repo, OLD_NAME);
|
||||
expect(key.name === OLD_NAME);
|
||||
const res = {
|
||||
send: (httpCode, data) => {
|
||||
send: (httpCode, _) => {
|
||||
expect(httpCode).toEqual(204);
|
||||
expect(key.name === NEW_NAME);
|
||||
responseProcessed = true; // required for afterEach to pass.
|
||||
|
|
@ -517,8 +519,8 @@ describe('ShadowsocksManagerService', () => {
|
|||
const repo = getAccessKeyRepository();
|
||||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
|
||||
const key = await repo.createNewAccessKey();
|
||||
const res = {send: (httpCode, data) => {}};
|
||||
await repo.createNewAccessKey();
|
||||
const res = {send: SEND_NOTHING};
|
||||
service.renameAccessKey({params: {id: 123}}, res, (error) => {
|
||||
expect(error.statusCode).toEqual(400);
|
||||
responseProcessed = true; // required for afterEach to pass.
|
||||
|
|
@ -531,7 +533,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
|
||||
const key = await createNewAccessKeyWithName(repo, 'oldName');
|
||||
const res = {send: (httpCode, data) => {}};
|
||||
const res = {send: SEND_NOTHING};
|
||||
service.renameAccessKey({params: {id: key.id, name: 'newName'}}, res, (error) => {
|
||||
expect(error.statusCode).toEqual(500);
|
||||
responseProcessed = true; // required for afterEach to pass.
|
||||
|
|
@ -554,7 +556,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
done();
|
||||
},
|
||||
};
|
||||
service.setAccessKeyDataLimit({params: {id: key.id, limit}}, res, () => {});
|
||||
service.setAccessKeyDataLimit({params: {id: key.id, limit}}, res, () => {/* do nothing */});
|
||||
});
|
||||
|
||||
it('rejects negative numbers', async (done) => {
|
||||
|
|
@ -562,7 +564,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
const keyId = (await repo.createNewAccessKey()).id;
|
||||
const limit = {bytes: -1};
|
||||
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {}}, (error) => {
|
||||
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {/* do nothing */}}, (error) => {
|
||||
expect(error.statusCode).toEqual(400);
|
||||
responseProcessed = true;
|
||||
done();
|
||||
|
|
@ -574,7 +576,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
const keyId = (await repo.createNewAccessKey()).id;
|
||||
const limit = {bytes: '1'};
|
||||
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {}}, (error) => {
|
||||
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {/* do nothing */}}, (error) => {
|
||||
expect(error.statusCode).toEqual(400);
|
||||
responseProcessed = true;
|
||||
done();
|
||||
|
|
@ -586,7 +588,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
const keyId = (await repo.createNewAccessKey()).id;
|
||||
const limit = {} as DataLimit;
|
||||
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {}}, (error) => {
|
||||
service.setAccessKeyDataLimit({params: {id: keyId, limit}}, {send: () => {/* do nothing */}}, (error) => {
|
||||
expect(error.statusCode).toEqual(400);
|
||||
responseProcessed = true;
|
||||
done();
|
||||
|
|
@ -600,7 +602,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
const limit: DataLimit = {bytes: 1000};
|
||||
service.setAccessKeyDataLimit(
|
||||
{params: {id: 'not an id', limit}},
|
||||
{send: () => {}},
|
||||
{send: () => {/* do nothing */}},
|
||||
(error) => {
|
||||
expect(error.statusCode).toEqual(404);
|
||||
responseProcessed = true;
|
||||
|
|
@ -625,13 +627,13 @@ describe('ShadowsocksManagerService', () => {
|
|||
done();
|
||||
},
|
||||
};
|
||||
service.removeAccessKeyDataLimit({params: {id: key.id}}, res, () => {});
|
||||
service.removeAccessKeyDataLimit({params: {id: key.id}}, res, () => {/* do nothing */});
|
||||
});
|
||||
it('returns 404 for a nonexistent key', async (done) => {
|
||||
const repo = getAccessKeyRepository();
|
||||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
await repo.createNewAccessKey();
|
||||
service.removeAccessKeyDataLimit({params: {id: 'not an id'}}, {send: () => {}}, (error) => {
|
||||
service.removeAccessKeyDataLimit({params: {id: 'not an id'}}, {send: () => {/* do nothing */}}, (error) => {
|
||||
expect(error.statusCode).toEqual(404);
|
||||
responseProcessed = true;
|
||||
done();
|
||||
|
|
@ -650,7 +652,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
.build();
|
||||
const limit = {bytes: 10000};
|
||||
const res = {
|
||||
send: (httpCode, data) => {
|
||||
send: (httpCode, _data) => {
|
||||
expect(httpCode).toEqual(204);
|
||||
expect(serverConfig.data().accessKeyDataLimit).toEqual(limit);
|
||||
expect(repo.setDefaultDataLimit).toHaveBeenCalledWith(limit);
|
||||
|
|
@ -672,9 +674,9 @@ describe('ShadowsocksManagerService', () => {
|
|||
it('returns 400 when limit is missing values', async (done) => {
|
||||
const repo = getAccessKeyRepository();
|
||||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
const accessKey = await repo.createNewAccessKey();
|
||||
await repo.createNewAccessKey();
|
||||
const limit = {} as DataLimit;
|
||||
const res = {send: (httpCode, data) => {}};
|
||||
const res = {send: SEND_NOTHING};
|
||||
service.setDefaultDataLimit({params: {limit}}, res, (error) => {
|
||||
expect(error.statusCode).toEqual(400);
|
||||
responseProcessed = true; // required for afterEach to pass.
|
||||
|
|
@ -684,9 +686,9 @@ describe('ShadowsocksManagerService', () => {
|
|||
it('returns 400 when limit has negative values', async (done) => {
|
||||
const repo = getAccessKeyRepository();
|
||||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
const accessKey = await repo.createNewAccessKey();
|
||||
await repo.createNewAccessKey();
|
||||
const limit = {bytes: -1};
|
||||
const res = {send: (httpCode, data) => {}};
|
||||
const res = {send: SEND_NOTHING};
|
||||
service.setDefaultDataLimit({params: {limit}}, res, (error) => {
|
||||
expect(error.statusCode).toEqual(400);
|
||||
responseProcessed = true; // required for afterEach to pass.
|
||||
|
|
@ -699,7 +701,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
await repo.createNewAccessKey();
|
||||
const limit = {bytes: 10000};
|
||||
const res = {send: (httpCode, data) => {}};
|
||||
const res = {send: SEND_NOTHING};
|
||||
service.setDefaultDataLimit({params: {limit}}, res, (error) => {
|
||||
expect(error.statusCode).toEqual(500);
|
||||
responseProcessed = true; // required for afterEach to pass.
|
||||
|
|
@ -720,7 +722,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
.build();
|
||||
await repo.setDefaultDataLimit(limit);
|
||||
const res = {
|
||||
send: (httpCode, data) => {
|
||||
send: (httpCode, _data) => {
|
||||
expect(httpCode).toEqual(204);
|
||||
expect(serverConfig.data().accessKeyDataLimit).toBeUndefined();
|
||||
expect(repo.removeDefaultDataLimit).toHaveBeenCalled();
|
||||
|
|
@ -734,7 +736,7 @@ describe('ShadowsocksManagerService', () => {
|
|||
spyOn(repo, 'removeDefaultDataLimit').and.throwError('cannot write to disk');
|
||||
const service = new ShadowsocksManagerServiceBuilder().accessKeys(repo).build();
|
||||
const accessKey = await repo.createNewAccessKey();
|
||||
const res = {send: (httpCode, data) => {}};
|
||||
const res = {send: SEND_NOTHING};
|
||||
service.removeDefaultDataLimit({params: {id: accessKey.id}}, res, (error) => {
|
||||
expect(error.statusCode).toEqual(500);
|
||||
responseProcessed = true; // required for afterEach to pass.
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ export class ShadowsocksManagerService {
|
|||
// Hostnames can have any number of segments of alphanumeric characters and hyphens, separated
|
||||
// by periods. No segment may start or end with a hyphen.
|
||||
const hostnameRegex =
|
||||
/^([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)*[A-Za-z0-9]([A-Za-z0-9\-]*[A-Za-z0-9])?$/;
|
||||
/^([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)*[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$/;
|
||||
if (!hostnameRegex.test(hostname) && !ipRegex({includeBoundaries: true}).test(hostname)) {
|
||||
return next(
|
||||
new restifyErrors.InvalidArgumentError(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
// limitations under the License.
|
||||
|
||||
import {PrometheusClient, QueryResultData} from '../../infrastructure/prometheus_scraper';
|
||||
import {DataUsageByUser} from '../../model/metrics';
|
||||
import {ShadowsocksAccessKey, ShadowsocksServer} from '../../model/shadowsocks_server';
|
||||
import {TextFile} from '../../model/text_file';
|
||||
|
||||
|
|
@ -25,7 +24,7 @@ export class InMemoryFile implements TextFile {
|
|||
return this.savedText;
|
||||
} else {
|
||||
const err = new Error('no such file or directory');
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(err as any).code = 'ENOENT';
|
||||
throw err;
|
||||
}
|
||||
|
|
@ -54,7 +53,7 @@ export class FakePrometheusClient extends PrometheusClient {
|
|||
super('');
|
||||
}
|
||||
|
||||
async query(query: string): Promise<QueryResultData> {
|
||||
async query(_query: string): Promise<QueryResultData> {
|
||||
const queryResultData = {result: []} as QueryResultData;
|
||||
for (const accessKeyId of Object.keys(this.bytesTransferredById)) {
|
||||
const bytesTransferred = this.bytesTransferredById[accessKeyId] || 0;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import * as net from 'net';
|
|||
import {ManualClock} from '../infrastructure/clock';
|
||||
import {PortProvider} from '../infrastructure/get_port';
|
||||
import {InMemoryConfig} from '../infrastructure/json_config';
|
||||
import {AccessKey, AccessKeyId, AccessKeyRepository, DataLimit} from '../model/access_key';
|
||||
import {AccessKeyId, AccessKeyRepository, DataLimit} from '../model/access_key';
|
||||
import * as errors from '../model/errors';
|
||||
|
||||
import {FakePrometheusClient, FakeShadowsocksServer} from './mocks/mocks';
|
||||
|
|
@ -57,7 +57,7 @@ describe('ServerAccessKeyRepository', () => {
|
|||
|
||||
it('removeAccessKey throws for missing keys', (done) => {
|
||||
const repo = new RepoBuilder().build();
|
||||
repo.createNewAccessKey().then((accessKey) => {
|
||||
repo.createNewAccessKey().then((_accessKey) => {
|
||||
expect(countAccessKeys(repo)).toEqual(1);
|
||||
expect(repo.removeAccessKey.bind(repo, 'badId')).toThrowError(errors.AccessKeyNotFound);
|
||||
expect(countAccessKeys(repo)).toEqual(1);
|
||||
|
|
@ -79,7 +79,7 @@ describe('ServerAccessKeyRepository', () => {
|
|||
|
||||
it('renameAccessKey throws for missing keys', (done) => {
|
||||
const repo = new RepoBuilder().build();
|
||||
repo.createNewAccessKey().then((accessKey) => {
|
||||
repo.createNewAccessKey().then((_accessKey) => {
|
||||
const NEW_NAME = 'newName';
|
||||
expect(repo.renameAccessKey.bind(repo, 'badId', NEW_NAME)).toThrowError(
|
||||
errors.AccessKeyNotFound
|
||||
|
|
@ -515,11 +515,11 @@ describe('ServerAccessKeyRepository', () => {
|
|||
.defaultDataLimit({bytes: 200})
|
||||
.build();
|
||||
|
||||
const accessKey1 = await repo.createNewAccessKey();
|
||||
await repo.createNewAccessKey();
|
||||
const accessKey2 = await repo.createNewAccessKey();
|
||||
|
||||
await repo.enforceAccessKeyDataLimits();
|
||||
const accessKeys = await repo.listAccessKeys();
|
||||
await repo.listAccessKeys();
|
||||
let serverAccessKeys = server.getAccessKeys();
|
||||
expect(serverAccessKeys.length).toEqual(1);
|
||||
expect(serverAccessKeys[0].id).toEqual(accessKey2.id);
|
||||
|
|
@ -641,7 +641,7 @@ async function expectNoAsyncThrow(fn: Function) {
|
|||
|
||||
// Convenience function to expect that an asynchronous function throws an error. Fails if the thrown
|
||||
// error does not match `errorType`, when defined.
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
async function expectAsyncThrow(fn: Function, errorType?: new (...args: any[]) => Error) {
|
||||
try {
|
||||
await fn();
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ describe('OutlineSharedMetricsPublisher', () => {
|
|||
serverConfig,
|
||||
keyConfig,
|
||||
new ManualUsageMetrics(),
|
||||
(id: AccessKeyId) => '',
|
||||
(_id: AccessKeyId) => '',
|
||||
metricsCollector
|
||||
);
|
||||
|
||||
|
|
@ -229,12 +229,12 @@ describe('OutlineSharedMetricsPublisher', () => {
|
|||
const metricsCollector = new FakeMetricsCollector();
|
||||
spyOn(metricsCollector, 'collectServerUsageMetrics').and.callThrough();
|
||||
spyOn(metricsCollector, 'collectFeatureMetrics').and.callThrough();
|
||||
const publisher = new OutlineSharedMetricsPublisher(
|
||||
new OutlineSharedMetricsPublisher(
|
||||
clock,
|
||||
serverConfig,
|
||||
new InMemoryConfig<AccessKeyConfigJson>({}),
|
||||
new ManualUsageMetrics(),
|
||||
(id: AccessKeyId) => '',
|
||||
(_id: AccessKeyId) => '',
|
||||
metricsCollector
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2020 The Outline Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
|
|||
48
tslint.json
48
tslint.json
|
|
@ -1,48 +0,0 @@
|
|||
// Copied from google.tslint.json, with internal rules removed
|
||||
{
|
||||
"rules": {
|
||||
"array-type": [true, "array-simple"],
|
||||
"arrow-return-shorthand": true,
|
||||
"ban-types": [
|
||||
true,
|
||||
["Object", "Use {} instead."],
|
||||
["String", "Use 'string' instead."],
|
||||
["Number", "Use 'number' instead."],
|
||||
["Boolean", "Use 'boolean' instead."]
|
||||
],
|
||||
"class-name": true,
|
||||
"forin": true,
|
||||
"interface-name": [true, "never-prefix"],
|
||||
"jsdoc-format": true,
|
||||
"label-position": true,
|
||||
"new-parens": true,
|
||||
"no-angle-bracket-type-assertion": true,
|
||||
"no-any": true,
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-default-export": true,
|
||||
"no-inferrable-types": true,
|
||||
"no-namespace": [true, "allow-declarations"],
|
||||
"no-reference": true,
|
||||
"no-require-imports": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": false,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-shorthand": true,
|
||||
"only-arrow-functions": [true, "allow-declarations", "allow-named-functions"],
|
||||
"prefer-const": true,
|
||||
"radix": true,
|
||||
"semicolon": [true, "always", "ignore-bound-class-methods"],
|
||||
"no-string-throw": true,
|
||||
"switch-default": true,
|
||||
"triple-equals": [true, "allow-null-check"],
|
||||
"use-isnan": true,
|
||||
"variable-name": [
|
||||
true,
|
||||
"check-format",
|
||||
"ban-keywords",
|
||||
"allow-leading-underscore",
|
||||
"allow-trailing-underscore"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue