1
0
mirror of https://github.com/bitwarden/directory-connector synced 2025-12-16 00:04:34 +00:00

Compare commits

...

11 Commits

Author SHA1 Message Date
Brandon
a6f77318eb resolve lint errors, upgrade eslint, replace unmaintained packages 2025-12-12 14:20:35 -05:00
renovate[bot]
1f489f0122 [deps]: Update eslint to v9 2025-12-11 18:04:58 +00:00
renovate[bot]
a0c30350d4 [deps]: Update sass to v1.94.2 (#935)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 18:00:14 +00:00
renovate[bot]
6f3d8f73e1 [deps]: Update actions/checkout action to v6 (#946)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 14:13:24 +00:00
renovate[bot]
d7be5486c7 [deps]: Update prettier to v3.7.4 (#941)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 14:09:43 +00:00
gitclonebrian
ce43f651ab added permissions to token generation step to limit scope of token (#929) 2025-12-10 17:46:23 -05:00
renovate[bot]
eda713bcc9 [deps]: Update type-fest to v5.3.0 (#907)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 09:55:29 -05:00
renovate[bot]
b53e145e62 [deps]: Update typescript-eslint monorepo to v8.48.0 (#942)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 08:53:34 +10:00
renovate[bot]
2ad35be82e [deps]: Update @angular/compiler to v20.3.15 [SECURITY] (#939)
* [deps]: Update @angular/compiler to v20.3.15 [SECURITY]

* Upgrade Angular packages to v20.3.15

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Rui Tome <rtome@bitwarden.com>
2025-12-02 15:57:14 +00:00
renovate[bot]
bdfc8ae5eb [deps]: Update node-forge to v1.3.2 [SECURITY] (#937)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 11:08:58 -05:00
renovate[bot]
7d218eac2f [deps]: Update @angular/common to v20.3.14 [SECURITY] (#938)
* [deps]: Update @angular/common to v20.3.14 [SECURITY]

* Upgrade all @angular packages to 20.3.14

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Thomas Rittson <trittson@bitwarden.com>
2025-11-28 10:52:30 +10:00
33 changed files with 1561 additions and 1532 deletions

View File

@@ -1,10 +0,0 @@
dist
build
build-cli
webpack.cli.js
webpack.main.js
webpack.renderer.js
**/node_modules
**/jest.config.js

View File

@@ -1,95 +0,0 @@
{
"root": true,
"env": {
"browser": true,
"node": true
},
"overrides": [
{
"files": ["*.ts", "*.js"],
"plugins": ["@typescript-eslint", "rxjs", "rxjs-angular", "import"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": ["./tsconfig.eslint.json"],
"sourceType": "module",
"ecmaVersion": 2020
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
"prettier",
"plugin:rxjs/recommended"
],
"settings": {
"import/parsers": {
"@typescript-eslint/parser": [".ts"]
},
"import/resolver": {
"typescript": {
"alwaysTryTypes": true
}
}
},
"rules": {
"@typescript-eslint/explicit-member-accessibility": [
"error",
{ "accessibility": "no-public" }
],
"@typescript-eslint/no-explicit-any": "off", // TODO: This should be re-enabled
"@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }],
"@typescript-eslint/no-this-alias": ["error", { "allowedNames": ["self"] }],
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
"no-console": "error",
"import/no-unresolved": "off", // TODO: Look into turning off once each package is an actual package.
"import/order": [
"error",
{
"alphabetize": {
"order": "asc"
},
"newlines-between": "always",
"pathGroups": [
{
"pattern": "@/jslib/**/*",
"group": "external",
"position": "after"
},
{
"pattern": "@/src/**/*",
"group": "parent",
"position": "before"
}
],
"pathGroupsExcludedImportTypes": ["builtin"]
}
],
"rxjs-angular/prefer-takeuntil": "error",
"rxjs/no-exposed-subjects": ["error", { "allowProtected": true }],
"no-restricted-syntax": [
"error",
{
"message": "Calling `svgIcon` directly is not allowed",
"selector": "CallExpression[callee.name='svgIcon']"
},
{
"message": "Accessing FormGroup using `get` is not allowed, use `.value` instead",
"selector": "ChainExpression[expression.object.callee.property.name='get'][expression.property.name='value']"
}
],
"curly": ["error", "all"],
"import/namespace": ["off"], // This doesn't resolve namespace imports correctly, but TS will throw for this anyway
"no-restricted-imports": ["error", { "patterns": ["src/**/*"] }]
}
},
{
"files": ["*.html"],
"parser": "@angular-eslint/template-parser",
"plugins": ["@angular-eslint/template"],
"rules": {
"@angular-eslint/template/button-has-type": "error"
}
}
]
}

View File

@@ -23,7 +23,7 @@ jobs:
node_version: ${{ steps.retrieve-node-version.outputs.node_version }} node_version: ${{ steps.retrieve-node-version.outputs.node_version }}
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
@@ -51,7 +51,7 @@ jobs:
contents: read contents: read
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
@@ -129,7 +129,7 @@ jobs:
_NODE_VERSION: ${{ needs.setup.outputs.node_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }}
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
@@ -200,7 +200,7 @@ jobs:
_NODE_VERSION: ${{ needs.setup.outputs.node_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }}
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
@@ -279,7 +279,7 @@ jobs:
HUSKY: 0 HUSKY: 0
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
@@ -379,7 +379,7 @@ jobs:
HUSKY: 0 HUSKY: 0
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
@@ -439,7 +439,7 @@ jobs:
HUSKY: 0 HUSKY: 0
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -40,7 +40,7 @@ jobs:
steps: steps:
- name: Check out repo - name: Check out repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -26,7 +26,7 @@ jobs:
release_version: ${{ steps.version.outputs.version }} release_version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -22,7 +22,7 @@ jobs:
steps: steps:
- name: Check out repo - name: Check out repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -47,9 +47,10 @@ jobs:
with: with:
app-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }} app-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }}
private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }} private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }}
permission-contents: write
- name: Checkout Branch - name: Checkout Branch
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
token: ${{ steps.app-token.outputs.token }} token: ${{ steps.app-token.outputs.token }}
persist-credentials: true persist-credentials: true

149
eslint.config.mjs Normal file
View File

@@ -0,0 +1,149 @@
// @ts-check
import eslint from "@eslint/js";
import tsParser from "@typescript-eslint/parser";
import tsPlugin from "@typescript-eslint/eslint-plugin";
import prettierConfig from "eslint-config-prettier";
import importPlugin from "eslint-plugin-import";
import rxjsX from "eslint-plugin-rxjs-x";
import rxjsAngularX from "eslint-plugin-rxjs-angular-x";
import angularEslint from "@angular-eslint/eslint-plugin-template";
import angularParser from "@angular-eslint/template-parser";
import globals from "globals";
export default [
// Global ignores (replaces .eslintignore)
{
ignores: [
"dist/**",
"dist-cli/**",
"build/**",
"build-cli/**",
"coverage/**",
"**/*.cjs",
"eslint.config.mjs",
"scripts/**/*.js",
"**/node_modules/**",
],
},
// Base config for all JavaScript/TypeScript files
{
files: ["**/*.ts", "**/*.js"],
languageOptions: {
ecmaVersion: 2020,
sourceType: "module",
parser: tsParser,
parserOptions: {
project: ["./tsconfig.eslint.json"],
},
globals: {
...globals.browser,
...globals.node,
},
},
plugins: {
"@typescript-eslint": tsPlugin,
import: importPlugin,
"rxjs-x": rxjsX,
"rxjs-angular-x": rxjsAngularX,
},
settings: {
"import/parsers": {
"@typescript-eslint/parser": [".ts"],
},
"import/resolver": {
typescript: {
alwaysTryTypes: true,
},
},
},
rules: {
// ESLint recommended rules
...eslint.configs.recommended.rules,
// TypeScript ESLint recommended rules
...tsPlugin.configs.recommended.rules,
// Import plugin recommended rules
...importPlugin.flatConfigs.recommended.rules,
// RxJS recommended rules
...rxjsX.configs.recommended.rules,
// Custom project rules
"@typescript-eslint/explicit-member-accessibility": ["error", { accessibility: "no-public" }],
"@typescript-eslint/no-explicit-any": "off", // TODO: This should be re-enabled
"@typescript-eslint/no-misused-promises": ["error", { checksVoidReturn: false }],
"@typescript-eslint/no-this-alias": ["error", { allowedNames: ["self"] }],
"@typescript-eslint/no-unused-vars": ["error", { args: "none" }],
"no-console": "error",
"import/no-unresolved": "off", // TODO: Look into turning on once each package is an actual package.
"import/order": [
"error",
{
alphabetize: {
order: "asc",
},
"newlines-between": "always",
pathGroups: [
{
pattern: "@/jslib/**/*",
group: "external",
position: "after",
},
{
pattern: "@/src/**/*",
group: "parent",
position: "before",
},
],
pathGroupsExcludedImportTypes: ["builtin"],
},
],
"rxjs-angular-x/prefer-takeuntil": "error",
"rxjs-x/no-exposed-subjects": ["error", { allowProtected: true }],
"no-restricted-syntax": [
"error",
{
message: "Calling `svgIcon` directly is not allowed",
selector: "CallExpression[callee.name='svgIcon']",
},
{
message: "Accessing FormGroup using `get` is not allowed, use `.value` instead",
selector:
"ChainExpression[expression.object.callee.property.name='get'][expression.property.name='value']",
},
],
curly: ["error", "all"],
"import/namespace": ["off"], // This doesn't resolve namespace imports correctly, but TS will throw for this anyway
"no-restricted-imports": ["error", { patterns: ["src/**/*"] }],
},
},
// Jest test files (includes any test-related files)
{
files: ["**/*.spec.ts", "**/test.setup.ts", "**/spec/**/*.ts", "**/utils/**/*fixtures*.ts"],
languageOptions: {
globals: {
...globals.jest,
},
},
},
// Angular HTML templates
{
files: ["**/*.html"],
languageOptions: {
parser: angularParser,
},
plugins: {
"@angular-eslint/template": angularEslint,
},
rules: {
"@angular-eslint/template/button-has-type": "error",
},
},
// Prettier config (must be last to override other configs)
prettierConfig,
];

View File

@@ -26,7 +26,6 @@ module.exports = {
modulePaths: [compilerOptions.baseUrl], modulePaths: [compilerOptions.baseUrl],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: "<rootDir>/" }), moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: "<rootDir>/" }),
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"], setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
// Workaround for a memory leak that crashes tests in CI: // Workaround for a memory leak that crashes tests in CI:
// https://github.com/facebook/jest/issues/9430#issuecomment-1149882002 // https://github.com/facebook/jest/issues/9430#issuecomment-1149882002
// Also anecdotally improves performance when run locally // Also anecdotally improves performance when run locally

View File

@@ -1,5 +1,4 @@
import { Observable, Subject } from "rxjs"; import { lastValueFrom, Observable, Subject } from "rxjs";
import { first } from "rxjs/operators";
export class ModalRef { export class ModalRef {
onCreated: Observable<HTMLElement>; // Modal added to the DOM. onCreated: Observable<HTMLElement>; // Modal added to the DOM.
@@ -45,6 +44,6 @@ export class ModalRef {
} }
onClosedPromise(): Promise<any> { onClosedPromise(): Promise<any> {
return this.onClosed.pipe(first()).toPromise(); return lastValueFrom(this.onClosed);
} }
} }

View File

@@ -1,5 +1,5 @@
import { Directive, ElementRef, Input, NgZone } from "@angular/core"; import { Directive, ElementRef, Input, NgZone } from "@angular/core";
import { take } from "rxjs/operators"; import { take } from "rxjs";
import { Utils } from "@/jslib/common/src/misc/utils"; import { Utils } from "@/jslib/common/src/misc/utils";

View File

@@ -9,7 +9,7 @@ import {
Type, Type,
ViewContainerRef, ViewContainerRef,
} from "@angular/core"; } from "@angular/core";
import { first } from "rxjs/operators"; import { first, firstValueFrom } from "rxjs";
import { DynamicModalComponent } from "../components/modal/dynamic-modal.component"; import { DynamicModalComponent } from "../components/modal/dynamic-modal.component";
import { ModalInjector } from "../components/modal/modal-injector"; import { ModalInjector } from "../components/modal/modal-injector";
@@ -58,7 +58,7 @@ export class ModalService {
viewContainerRef.insert(modalComponentRef.hostView); viewContainerRef.insert(modalComponentRef.hostView);
await modalRef.onCreated.pipe(first()).toPromise(); await firstValueFrom(modalRef.onCreated);
return [modalRef, modalComponentRef.instance.componentRef.instance]; return [modalRef, modalComponentRef.instance.componentRef.instance];
} }

View File

@@ -8,15 +8,12 @@ declare let console: any;
export function interceptConsole(interceptions: any): object { export function interceptConsole(interceptions: any): object {
console = { console = {
log: function () { log: function () {
// eslint-disable-next-line
interceptions.log = arguments; interceptions.log = arguments;
}, },
warn: function () { warn: function () {
// eslint-disable-next-line
interceptions.warn = arguments; interceptions.warn = arguments;
}, },
error: function () { error: function () {
// eslint-disable-next-line
interceptions.error = arguments; interceptions.error = arguments;
}, },
}; };

View File

@@ -1,9 +1,11 @@
/* eslint-disable no-useless-escape */ /* eslint-disable no-useless-escape */
import * as url from "url";
import { I18nService } from "../abstractions/i18n.service"; import { I18nService } from "../abstractions/i18n.service";
import * as tldjs from "tldjs"; import * as tldjs from "tldjs";
const nodeURL = typeof window === "undefined" ? require("url") : null; const nodeURL = typeof window === "undefined" ? url : null;
export class Utils { export class Utils {
static inited = false; static inited = false;
@@ -247,7 +249,7 @@ export class Utils {
const urlDomain = const urlDomain =
tldjs != null && tldjs.getDomain != null ? tldjs.getDomain(url.hostname) : null; tldjs != null && tldjs.getDomain != null ? tldjs.getDomain(url.hostname) : null;
return urlDomain != null ? urlDomain : url.hostname; return urlDomain != null ? urlDomain : url.hostname;
} catch (e) { } catch {
// Invalid domain, try another approach below. // Invalid domain, try another approach below.
} }
} }
@@ -395,7 +397,7 @@ export class Utils {
anchor.href = uriString; anchor.href = uriString;
return anchor as any; return anchor as any;
} }
} catch (e) { } catch {
// Ignore error // Ignore error
} }

View File

@@ -53,7 +53,7 @@ export class EncString {
try { try {
this.encryptionType = parseInt(headerPieces[0], null); this.encryptionType = parseInt(headerPieces[0], null);
encPieces = headerPieces[1].split("|"); encPieces = headerPieces[1].split("|");
} catch (e) { } catch {
return; return;
} }
} else { } else {
@@ -114,7 +114,7 @@ export class EncString {
key = await cryptoService.getOrgKey(orgId); key = await cryptoService.getOrgKey(orgId);
} }
this.decryptedValue = await cryptoService.decryptToUtf8(this, key); this.decryptedValue = await cryptoService.decryptToUtf8(this, key);
} catch (e) { } catch {
this.decryptedValue = "[error: cannot decrypt]"; this.decryptedValue = "[error: cannot decrypt]";
} }
return this.decryptedValue; return this.decryptedValue;

View File

@@ -1,5 +1,4 @@
import { ClientType } from "../../../enums/clientType"; import { ClientType } from "../../../enums/clientType";
import { Utils } from "../../../misc/utils";
import { CaptchaProtectedRequest } from "../captchaProtectedRequest"; import { CaptchaProtectedRequest } from "../captchaProtectedRequest";
import { DeviceRequest } from "../deviceRequest"; import { DeviceRequest } from "../deviceRequest";
@@ -30,5 +29,4 @@ export class PasswordTokenRequest extends TokenRequest implements CaptchaProtect
return obj; return obj;
} }
} }

View File

@@ -12,7 +12,6 @@ export abstract class TokenRequest {
this.device = device != null ? device : null; this.device = device != null ? device : null;
} }
// eslint-disable-next-line
alterIdentityTokenHeaders(headers: Headers) { alterIdentityTokenHeaders(headers: Headers) {
// Implemented in subclass if required // Implemented in subclass if required
} }

View File

@@ -335,9 +335,11 @@ export class CryptoService implements CryptoServiceAbstraction {
} }
async clearStoredKey(keySuffix: KeySuffixOptions) { async clearStoredKey(keySuffix: KeySuffixOptions) {
keySuffix === KeySuffixOptions.Auto if (keySuffix === KeySuffixOptions.Auto) {
? await this.stateService.setCryptoMasterKeyAuto(null) await this.stateService.setCryptoMasterKeyAuto(null);
: await this.stateService.setCryptoMasterKeyBiometric(null); } else {
await this.stateService.setCryptoMasterKeyBiometric(null);
}
} }
async clearKeyHash(userId?: string): Promise<any> { async clearKeyHash(userId?: string): Promise<any> {
@@ -717,7 +719,7 @@ export class CryptoService implements CryptoServiceAbstraction {
const privateKey = await this.decryptToBytes(new EncString(encPrivateKey), encKey); const privateKey = await this.decryptToBytes(new EncString(encPrivateKey), encKey);
await this.cryptoFunctionService.rsaExtractPublicKey(privateKey); await this.cryptoFunctionService.rsaExtractPublicKey(privateKey);
} catch (e) { } catch {
return false; return false;
} }

View File

@@ -38,8 +38,7 @@ const partialKeys = {
export class StateService< export class StateService<
TGlobalState extends GlobalState = GlobalState, TGlobalState extends GlobalState = GlobalState,
TAccount extends Account = Account, TAccount extends Account = Account,
> implements StateServiceAbstraction<TAccount> > implements StateServiceAbstraction<TAccount> {
{
protected accountsSubject = new BehaviorSubject<{ [userId: string]: TAccount }>({}); protected accountsSubject = new BehaviorSubject<{ [userId: string]: TAccount }>({});
accounts$ = this.accountsSubject.asObservable(); accounts$ = this.accountsSubject.asObservable();

View File

@@ -1,6 +1,14 @@
import * as path from "path"; import * as path from "path";
import { app, BrowserWindow, Menu, MenuItemConstructorOptions, nativeImage, Tray } from "electron"; import {
app,
BrowserWindow,
Menu,
MenuItemConstructorOptions,
NativeImage,
nativeImage,
Tray,
} from "electron";
import { I18nService } from "@/jslib/common/src/abstractions/i18n.service"; import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
import { StateService } from "@/jslib/common/src/abstractions/state.service"; import { StateService } from "@/jslib/common/src/abstractions/state.service";
@@ -12,8 +20,8 @@ export class TrayMain {
private appName: string; private appName: string;
private tray: Tray; private tray: Tray;
private icon: string | Electron.NativeImage; private icon: string | NativeImage;
private pressedIcon: Electron.NativeImage; private pressedIcon: NativeImage;
constructor( constructor(
private windowMain: WindowMain, private windowMain: WindowMain,

View File

@@ -1,7 +1,7 @@
import * as path from "path"; import * as path from "path";
import * as url from "url"; import * as url from "url";
import { app, BrowserWindow, screen } from "electron"; import { app, BrowserWindow, Rectangle, screen } from "electron";
import { LogService } from "@/jslib/common/src/abstractions/log.service"; import { LogService } from "@/jslib/common/src/abstractions/log.service";
import { StateService } from "@/jslib/common/src/abstractions/state.service"; import { StateService } from "@/jslib/common/src/abstractions/state.service";
@@ -14,7 +14,7 @@ export class WindowMain {
win: BrowserWindow; win: BrowserWindow;
isQuitting = false; isQuitting = false;
private windowStateChangeTimer: NodeJS.Timeout; private windowStateChangeTimer: ReturnType<typeof setTimeout>;
private windowStates: { [key: string]: any } = {}; private windowStates: { [key: string]: any } = {};
private enableAlwaysOnTop = false; private enableAlwaysOnTop = false;
@@ -37,7 +37,6 @@ export class WindowMain {
app.quit(); app.quit();
return; return;
} else { } else {
// eslint-disable-next-line
app.on("second-instance", (event, argv, workingDirectory) => { app.on("second-instance", (event, argv, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window. // Someone tried to run a second instance, we should focus our window.
if (this.win != null) { if (this.win != null) {
@@ -241,7 +240,7 @@ export class WindowMain {
const state = await this.stateService.getWindow(); const state = await this.stateService.getWindow();
const isValid = state != null && (this.stateHasBounds(state) || state.isMaximized); const isValid = state != null && (this.stateHasBounds(state) || state.isMaximized);
let displayBounds: Electron.Rectangle = null; let displayBounds: Rectangle = null;
if (!isValid) { if (!isValid) {
state.width = defaultWidth; state.width = defaultWidth;
state.height = defaultHeight; state.height = defaultHeight;

2672
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -31,14 +31,14 @@
"lint": "eslint . && prettier --check .", "lint": "eslint . && prettier --check .",
"lint:fix": "eslint . --fix", "lint:fix": "eslint . --fix",
"build": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\"", "build": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\"",
"build:main": "webpack --config webpack.main.js", "build:main": "webpack --config webpack.main.cjs",
"build:renderer": "webpack --config webpack.renderer.js", "build:renderer": "webpack --config webpack.renderer.cjs",
"build:renderer:watch": "webpack --config webpack.renderer.js --watch", "build:renderer:watch": "webpack --config webpack.renderer.cjs --watch",
"build:dist": "npm run reset && npm run rebuild && npm run build", "build:dist": "npm run reset && npm run rebuild && npm run build",
"build:cli": "webpack --config webpack.cli.js", "build:cli": "webpack --config webpack.cli.cjs",
"build:cli:watch": "webpack --config webpack.cli.js --watch", "build:cli:watch": "webpack --config webpack.cli.cjs --watch",
"build:cli:prod": "cross-env NODE_ENV=production webpack --config webpack.cli.js", "build:cli:prod": "cross-env NODE_ENV=production webpack --config webpack.cli.cjs",
"build:cli:prod:watch": "cross-env NODE_ENV=production webpack --config webpack.cli.js --watch", "build:cli:prod:watch": "cross-env NODE_ENV=production webpack --config webpack.cli.cjs --watch",
"electron": "npm run build:main && concurrently -k -n Main,Rend -c yellow,cyan \"electron --inspect=5858 ./build --watch\" \"npm run build:renderer:watch\"", "electron": "npm run build:main && concurrently -k -n Main,Rend -c yellow,cyan \"electron --inspect=5858 ./build --watch\" \"npm run build:renderer:watch\"",
"electron:ignore": "npm run build:main && concurrently -k -n Main,Rend -c yellow,cyan \"electron --inspect=5858 --ignore-certificate-errors ./build --watch\" \"npm run build:renderer:watch\"", "electron:ignore": "npm run build:main && concurrently -k -n Main,Rend -c yellow,cyan \"electron --inspect=5858 --ignore-certificate-errors ./build --watch\" \"npm run build:renderer:watch\"",
"clean:dist": "rimraf --glob ./dist/*", "clean:dist": "rimraf --glob ./dist/*",
@@ -76,7 +76,7 @@
"@angular-devkit/build-angular": "20.3.3", "@angular-devkit/build-angular": "20.3.3",
"@angular-eslint/eslint-plugin-template": "20.6.0", "@angular-eslint/eslint-plugin-template": "20.6.0",
"@angular-eslint/template-parser": "20.6.0", "@angular-eslint/template-parser": "20.6.0",
"@angular/compiler-cli": "20.3.3", "@angular/compiler-cli": "20.3.15",
"@electron/notarize": "2.5.0", "@electron/notarize": "2.5.0",
"@electron/rebuild": "4.0.1", "@electron/rebuild": "4.0.1",
"@fluffy-spoon/substitute": "1.208.0", "@fluffy-spoon/substitute": "1.208.0",
@@ -89,9 +89,10 @@
"@types/node-fetch": "2.6.12", "@types/node-fetch": "2.6.12",
"@types/node-forge": "1.3.11", "@types/node-forge": "1.3.11",
"@types/proper-lockfile": "4.1.4", "@types/proper-lockfile": "4.1.4",
"@types/semver": "7.7.1",
"@types/tldjs": "2.3.4", "@types/tldjs": "2.3.4",
"@typescript-eslint/eslint-plugin": "8.46.0", "@typescript-eslint/eslint-plugin": "8.48.0",
"@typescript-eslint/parser": "8.46.0", "@typescript-eslint/parser": "8.48.0",
"@yao-pkg/pkg": "5.16.1", "@yao-pkg/pkg": "5.16.1",
"clean-webpack-plugin": "4.0.0", "clean-webpack-plugin": "4.0.0",
"concurrently": "9.2.0", "concurrently": "9.2.0",
@@ -105,12 +106,12 @@
"electron-reload": "2.0.0-alpha.1", "electron-reload": "2.0.0-alpha.1",
"electron-store": "8.2.0", "electron-store": "8.2.0",
"electron-updater": "6.6.2", "electron-updater": "6.6.2",
"eslint": "8.57.1", "eslint": "9.39.1",
"eslint-config-prettier": "10.1.5", "eslint-config-prettier": "10.1.5",
"eslint-import-resolver-typescript": "4.4.4", "eslint-import-resolver-typescript": "4.4.4",
"eslint-plugin-import": "2.32.0", "eslint-plugin-import": "2.32.0",
"eslint-plugin-rxjs": "5.0.3", "eslint-plugin-rxjs-angular-x": "0.1.0",
"eslint-plugin-rxjs-angular": "2.0.1", "eslint-plugin-rxjs-x": "0.8.3",
"form-data": "4.0.4", "form-data": "4.0.4",
"glob": "11.1.0", "glob": "11.1.0",
"html-loader": "5.1.0", "html-loader": "5.1.0",
@@ -123,17 +124,17 @@
"lint-staged": "16.2.6", "lint-staged": "16.2.6",
"mini-css-extract-plugin": "2.9.2", "mini-css-extract-plugin": "2.9.2",
"minimatch": "5.1.2", "minimatch": "5.1.2",
"node-forge": "1.3.1", "node-forge": "1.3.2",
"node-loader": "2.1.0", "node-loader": "2.1.0",
"prettier": "3.6.2", "prettier": "3.7.4",
"rimraf": "6.1.0", "rimraf": "6.1.0",
"rxjs": "7.8.2", "rxjs": "7.8.2",
"sass": "1.93.2", "sass": "1.94.2",
"sass-loader": "16.0.5", "sass-loader": "16.0.5",
"ts-jest": "29.4.1", "ts-jest": "29.4.1",
"ts-loader": "9.5.2", "ts-loader": "9.5.2",
"tsconfig-paths-webpack-plugin": "4.2.0", "tsconfig-paths-webpack-plugin": "4.2.0",
"type-fest": "5.0.1", "type-fest": "5.3.0",
"typescript": "5.8.3", "typescript": "5.8.3",
"webpack": "5.102.1", "webpack": "5.102.1",
"webpack-cli": "6.0.1", "webpack-cli": "6.0.1",
@@ -142,16 +143,16 @@
"zone.js": "0.15.1" "zone.js": "0.15.1"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "20.3.3", "@angular/animations": "20.3.15",
"@angular/cdk": "20.2.7", "@angular/cdk": "20.2.14",
"@angular/cli": "20.3.3", "@angular/cli": "20.3.3",
"@angular/common": "20.3.3", "@angular/common": "20.3.15",
"@angular/compiler": "20.3.3", "@angular/compiler": "20.3.15",
"@angular/core": "20.3.3", "@angular/core": "20.3.15",
"@angular/forms": "20.3.3", "@angular/forms": "20.3.15",
"@angular/platform-browser": "20.3.3", "@angular/platform-browser": "20.3.15",
"@angular/platform-browser-dynamic": "20.3.3", "@angular/platform-browser-dynamic": "20.3.15",
"@angular/router": "20.3.3", "@angular/router": "20.3.15",
"@microsoft/microsoft-graph-client": "3.0.7", "@microsoft/microsoft-graph-client": "3.0.7",
"big-integer": "1.6.52", "big-integer": "1.6.52",
"bootstrap": "5.3.7", "bootstrap": "5.3.7",

View File

@@ -23,7 +23,7 @@ import { EnvironmentComponent } from "./environment.component";
// The only subscription in this component is closed from a child component, confusing eslint. // The only subscription in this component is closed from a child component, confusing eslint.
// https://github.com/cartant/eslint-plugin-rxjs-angular/blob/main/docs/rules/prefer-takeuntil.md // https://github.com/cartant/eslint-plugin-rxjs-angular/blob/main/docs/rules/prefer-takeuntil.md
// //
// eslint-disable-next-line rxjs-angular/prefer-takeuntil // eslint-disable-next-line rxjs-angular-x/prefer-takeuntil
export class ApiKeyComponent { export class ApiKeyComponent {
@ViewChild("environment", { read: ViewContainerRef, static: true }) @ViewChild("environment", { read: ViewContainerRef, static: true })
environmentModal: ViewContainerRef; environmentModal: ViewContainerRef;
@@ -100,7 +100,7 @@ export class ApiKeyComponent {
this.environmentModal, this.environmentModal,
); );
// eslint-disable-next-line rxjs-angular/prefer-takeuntil // eslint-disable-next-line rxjs-angular-x/prefer-takeuntil
childComponent.onSaved.pipe(takeUntil(modalRef.onClosed)).subscribe(() => { childComponent.onSaved.pipe(takeUntil(modalRef.onClosed)).subscribe(() => {
modalRef.close(); modalRef.close();
}); });

View File

@@ -3,8 +3,7 @@ import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { isDev } from "@/jslib/electron/src/utils"; import { isDev } from "@/jslib/electron/src/utils";
// tslint:disable-next-line import "../scss/styles.scss";
require("../scss/styles.scss");
import { AppModule } from "./app.module"; import { AppModule } from "./app.module";

View File

@@ -9,7 +9,7 @@ import { MenuMain } from "./menu.main";
const SyncCheckInterval = 60 * 1000; // 1 minute const SyncCheckInterval = 60 * 1000; // 1 minute
export class MessagingMain { export class MessagingMain {
private syncTimeout: NodeJS.Timeout; private syncTimeout: ReturnType<typeof setTimeout>;
constructor( constructor(
private windowMain: WindowMain, private windowMain: WindowMain,

View File

@@ -132,7 +132,7 @@ export class EntraIdDirectoryService extends BaseDirectoryService implements IDi
} }
const setFilter = this.createCustomUserSet(this.syncConfig.userFilter); const setFilter = this.createCustomUserSet(this.syncConfig.userFilter);
// eslint-disable-next-line
while (true) { while (true) {
const users: graphType.User[] = res.value; const users: graphType.User[] = res.value;
if (users != null) { if (users != null) {
@@ -211,7 +211,7 @@ export class EntraIdDirectoryService extends BaseDirectoryService implements IDi
let auMembers = await this.client let auMembers = await this.client
.api(`${this.getGraphApiEndpoint()}/v1.0/directory/administrativeUnits/${p}/members`) .api(`${this.getGraphApiEndpoint()}/v1.0/directory/administrativeUnits/${p}/members`)
.get(); .get();
// eslint-disable-next-line
while (true) { while (true) {
for (const auMember of auMembers.value) { for (const auMember of auMembers.value) {
const groupId = auMember.id; const groupId = auMember.id;
@@ -328,7 +328,7 @@ export class EntraIdDirectoryService extends BaseDirectoryService implements IDi
const entries: GroupEntry[] = []; const entries: GroupEntry[] = [];
const groupsReq = this.client.api("/groups"); const groupsReq = this.client.api("/groups");
let res = await groupsReq.get(); let res = await groupsReq.get();
// eslint-disable-next-line
while (true) { while (true) {
const groups: graphType.Group[] = res.value; const groups: graphType.Group[] = res.value;
if (groups != null) { if (groups != null) {
@@ -421,7 +421,7 @@ export class EntraIdDirectoryService extends BaseDirectoryService implements IDi
const memReq = this.client.api("/groups/" + group.id + "/members"); const memReq = this.client.api("/groups/" + group.id + "/members");
let memRes = await memReq.get(); let memRes = await memReq.get();
// eslint-disable-next-line
while (true) { while (true) {
const members: any = memRes.value; const members: any = memRes.value;
if (members != null) { if (members != null) {

View File

@@ -71,7 +71,7 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements IDir
let nextPageToken: string = null; let nextPageToken: string = null;
const filter = this.createCustomSet(this.syncConfig.userFilter); const filter = this.createCustomSet(this.syncConfig.userFilter);
// eslint-disable-next-line
while (true) { while (true) {
this.logService.info("Querying users - nextPageToken:" + nextPageToken); this.logService.info("Querying users - nextPageToken:" + nextPageToken);
const p = Object.assign({ query: query, pageToken: nextPageToken }, this.authParams); const p = Object.assign({ query: query, pageToken: nextPageToken }, this.authParams);
@@ -99,7 +99,7 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements IDir
} }
nextPageToken = null; nextPageToken = null;
// eslint-disable-next-line
while (true) { while (true) {
this.logService.info("Querying deleted users - nextPageToken:" + nextPageToken); this.logService.info("Querying deleted users - nextPageToken:" + nextPageToken);
const p = Object.assign( const p = Object.assign(
@@ -154,7 +154,6 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements IDir
const query = this.createDirectoryQuery(this.syncConfig.groupFilter); const query = this.createDirectoryQuery(this.syncConfig.groupFilter);
let nextPageToken: string = null; let nextPageToken: string = null;
// eslint-disable-next-line
while (true) { while (true) {
this.logService.info("Querying groups - nextPageToken:" + nextPageToken); this.logService.info("Querying groups - nextPageToken:" + nextPageToken);
let p = null; let p = null;
@@ -194,7 +193,6 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements IDir
entry.externalId = group.id; entry.externalId = group.id;
entry.name = group.name; entry.name = group.name;
// eslint-disable-next-line
while (true) { while (true) {
const p = Object.assign({ groupKey: group.id, pageToken: nextPageToken }, this.authParams); const p = Object.assign({ groupKey: group.id, pageToken: nextPageToken }, this.authParams);
const memRes = await this.service.members.list(p); const memRes = await this.service.members.list(p);

View File

@@ -116,6 +116,7 @@ describe("SyncService", () => {
stateService.getLastSyncHash.mockResolvedValue("unique hash"); stateService.getLastSyncHash.mockResolvedValue("unique hash");
// @ts-expect-error This is a workaround to make the batchsize smaller to trigger the batching logic since its a const. // @ts-expect-error This is a workaround to make the batchsize smaller to trigger the batching logic since its a const.
// eslint-disable-next-line no-import-assign
constants.batchSize = 4; constants.batchSize = 4;
const syncResult = await syncService.sync(false, false); const syncResult = await syncService.sync(false, false);
@@ -130,6 +131,7 @@ describe("SyncService", () => {
expect(apiService.postPublicImportDirectory).toHaveBeenCalledTimes(7); expect(apiService.postPublicImportDirectory).toHaveBeenCalledTimes(7);
// @ts-expect-error Reset batch size to original state. // @ts-expect-error Reset batch size to original state.
// eslint-disable-next-line no-import-assign
constants.batchSize = originalBatchSize; constants.batchSize = originalBatchSize;
}); });
}); });

View File

@@ -97,6 +97,7 @@ describe("SyncService", () => {
stateService.getLastSyncHash.mockResolvedValue("unique hash"); stateService.getLastSyncHash.mockResolvedValue("unique hash");
// @ts-expect-error This is a workaround to make the batchsize smaller to trigger the batching logic since its a const. // @ts-expect-error This is a workaround to make the batchsize smaller to trigger the batching logic since its a const.
// eslint-disable-next-line no-import-assign
constants.batchSize = 4; constants.batchSize = 4;
const mockRequests = new Array(6).fill({ const mockRequests = new Array(6).fill({
@@ -119,6 +120,7 @@ describe("SyncService", () => {
expect(apiService.postPublicImportDirectory).toHaveBeenCalledWith(mockRequests[5]); expect(apiService.postPublicImportDirectory).toHaveBeenCalledWith(mockRequests[5]);
// @ts-expect-error Reset batch size back to original value. // @ts-expect-error Reset batch size back to original value.
// eslint-disable-next-line no-import-assign
constants.batchSize = originalBatchSize; constants.batchSize = originalBatchSize;
}); });