Store api key in separate storage to prevent accidentally leaking when asking for the config file for support

This commit is contained in:
Lynn
2022-02-19 16:51:50 +01:00
parent e18e796809
commit b436a33624
24 changed files with 140 additions and 37 deletions

View File

@@ -8,14 +8,17 @@ import {
IPC_STORE_REMOVE_OBJECT,
IPC_STORE_SET_OBJECT,
PREFERENCE_STORE_NAME,
SENSITIVE_STORE_NAME,
} from "../src/common/constants";
export const addonStore = new Store({ name: ADDON_STORE_NAME });
export const preferenceStore = new Store({ name: PREFERENCE_STORE_NAME });
export const sensitiveStore = new Store({ name: SENSITIVE_STORE_NAME });
const stores: { [storeName: string]: Store } = {
[ADDON_STORE_NAME]: addonStore,
[PREFERENCE_STORE_NAME]: preferenceStore,
[SENSITIVE_STORE_NAME]: sensitiveStore,
};
export function initializeStoreIpcHandlers(): void {

View File

@@ -50,7 +50,7 @@ import { AddonProvider, GetAllBatchResult, GetAllResult, SearchByUrlResult } fro
import { strictFilter } from "../utils/array.utils";
import { TocService } from "../services/toc/toc.service";
import { WarcraftService } from "../services/warcraft/warcraft.service";
import { PreferenceStorageService } from "../services/storage/preference-storage.service";
import { SensitiveStorageService } from "../services/storage/sensitive-storage.service";
interface ProtocolData {
addonId: number;
@@ -99,7 +99,7 @@ export class CurseAddonV2Provider extends AddonProvider {
private _wowupApiService: WowUpApiService,
private _warcraftService: WarcraftService,
private _tocService: TocService,
private _preferenceStorageService: PreferenceStorageService,
private _sensitiveStorageService: SensitiveStorageService,
_networkService: NetworkService
) {
super();
@@ -1045,7 +1045,7 @@ export class CurseAddonV2Provider extends AddonProvider {
return this._cfClient;
}
const apiKey = await this._preferenceStorageService.getAsync(PREF_CF2_API_KEY);
const apiKey = await this._sensitiveStorageService.getAsync(PREF_CF2_API_KEY);
if (typeof apiKey !== "string" || apiKey.length === 0) {
return undefined;
}

View File

@@ -4,7 +4,7 @@ import { MatSelectionListChange } from "@angular/material/list";
import { AddonProviderFactory } from "../../../services/addons/addon.provider.factory";
import { AddonProviderType } from "../../../addon-providers/addon-provider";
import { BehaviorSubject, catchError, debounceTime, first, from, map, of, Subject, switchMap, takeUntil } from "rxjs";
import { PreferenceStorageService } from "../../../services/storage/preference-storage.service";
import { SensitiveStorageService } from "../../../services/storage/sensitive-storage.service";
import { PREF_CF2_API_KEY } from "../../../../common/constants";
import { FormControl, FormGroup } from "@angular/forms";
@@ -29,7 +29,7 @@ export class OptionsAddonSectionComponent implements OnInit, OnDestroy {
public constructor(
private _addonProviderService: AddonProviderFactory,
private _preferenceStorageService: PreferenceStorageService
private _sensitiveStorageService: SensitiveStorageService
) {
this._addonProviderService.addonProviderChange$.subscribe(() => {
this.loadProviderStates();
@@ -41,7 +41,7 @@ export class OptionsAddonSectionComponent implements OnInit, OnDestroy {
debounceTime(300),
switchMap((ch) => {
if (ch.cfV2ApiKey) {
return from(this._preferenceStorageService.setAsync(PREF_CF2_API_KEY, ch.cfV2ApiKey));
return from(this._sensitiveStorageService.setAsync(PREF_CF2_API_KEY, ch.cfV2ApiKey));
}
return of(undefined);
}),
@@ -71,7 +71,7 @@ export class OptionsAddonSectionComponent implements OnInit, OnDestroy {
}
private loadCfV2ApiKey() {
from(this._preferenceStorageService.getAsync(PREF_CF2_API_KEY))
from(this._sensitiveStorageService.getAsync(PREF_CF2_API_KEY))
.pipe(
first(),
map((apiKey) => {

View File

@@ -16,6 +16,20 @@
</div>
</div>
</div>
<!-- SHOW CONFIG FILES -->
<div class="section">
<div class="row align-items-center">
<div class="flex-grow-1">
<div>{{ "PAGES.OPTIONS.DEBUG.CONFIG_FILES_LABEL" | translate }}</div>
<small class="text-2">{{ "PAGES.OPTIONS.DEBUG.CONFIG_FILES_DESCRIPTION" | translate }}</small>
</div>
<div>
<button id="show-config-btn" mat-flat-button color="primary" (click)="onShowConfig()">
{{ "PAGES.OPTIONS.DEBUG.CONFIG_FILES_BUTTON" | translate }}
</button>
</div>
</div>
</div>
<!-- DUMP DEBUG DATA -->
<div class="section">
<div class="row align-items-center">

View File

@@ -22,6 +22,10 @@ export class OptionsDebugSectionComponent {
await this._wowupService.showLogsFolder();
}
public async onShowConfig(): Promise<void> {
await this._wowupService.showConfigFolder();
}
public async onLogDebugData(): Promise<void> {
try {
this.dumpingDebugData = true;

View File

@@ -23,6 +23,7 @@ import { Subject } from "rxjs";
import { PreferenceStorageService } from "../storage/preference-storage.service";
import { CurseAddonV2Provider } from "../../addon-providers/curse-addon-v2-provider";
import { CurseAddonProvider } from "../../addon-providers/curse-addon-provider";
import { SensitiveStorageService } from "../storage/sensitive-storage.service";
@Injectable({
providedIn: "root",
@@ -44,7 +45,8 @@ export class AddonProviderFactory {
private _tocService: TocService,
private _warcraftService: WarcraftService,
private _wowupApiService: WowUpApiService,
private _preferenceStorageService: PreferenceStorageService
private _preferenceStorageService: PreferenceStorageService,
private _sensitiveStorageService: SensitiveStorageService,
) {}
/** This is part of the APP_INITIALIZER and called before the app is bootstrapped */
@@ -134,7 +136,7 @@ export class AddonProviderFactory {
this._wowupApiService,
this._warcraftService,
this._tocService,
this._preferenceStorageService,
this._sensitiveStorageService,
this._networkService
);
}

View File

@@ -1,38 +1,17 @@
import { Injectable } from "@angular/core";
import {
IPC_STORE_GET_OBJECT,
IPC_STORE_GET_OBJECT_SYNC,
IPC_STORE_SET_OBJECT,
PREFERENCE_STORE_NAME,
TRUE_STR,
} from "../../../common/constants";
import { PREFERENCE_STORE_NAME } from "../../../common/constants";
import { StorageService } from "./storage.service";
import { ElectronService } from "../electron/electron.service";
@Injectable({
providedIn: "root",
})
export class PreferenceStorageService {
public constructor(private _electronService: ElectronService) {}
export class PreferenceStorageService extends StorageService {
protected readonly storageName = PREFERENCE_STORE_NAME;
public async getBool(key: string): Promise<boolean> {
const val = await this.getAsync(key);
return val === TRUE_STR;
}
public getAsync<T = string>(key: string): Promise<T> {
return this._electronService.invoke(IPC_STORE_GET_OBJECT, PREFERENCE_STORE_NAME, key);
}
public getSync<T = string>(key: string): T {
return this._electronService.sendSync<T>(IPC_STORE_GET_OBJECT_SYNC, PREFERENCE_STORE_NAME, key);
}
public async setAsync(key: string, value: unknown): Promise<void> {
return await this._electronService.invoke(IPC_STORE_SET_OBJECT, PREFERENCE_STORE_NAME, key, value);
}
public getObjectAsync<T>(key: string): Promise<T | undefined> {
return this._electronService.invoke(IPC_STORE_GET_OBJECT, PREFERENCE_STORE_NAME, key);
public constructor(electronService: ElectronService) {
super(electronService);
}
}

View File

@@ -0,0 +1,16 @@
import { Injectable } from "@angular/core";
import { SENSITIVE_STORE_NAME } from "../../../common/constants";
import { StorageService } from "./storage.service";
import { ElectronService } from "../electron/electron.service";
@Injectable({
providedIn: "root",
})
export class SensitiveStorageService extends StorageService {
protected readonly storageName = SENSITIVE_STORE_NAME;
public constructor(electronService: ElectronService) {
super(electronService);
}
}

View File

@@ -0,0 +1,34 @@
import {
IPC_STORE_GET_OBJECT,
IPC_STORE_GET_OBJECT_SYNC,
IPC_STORE_SET_OBJECT,
TRUE_STR,
} from "../../../common/constants";
import { ElectronService } from "../electron/electron.service";
export abstract class StorageService {
protected abstract readonly storageName: string;
protected constructor(private _electronService: ElectronService) {}
public async getBool(key: string): Promise<boolean> {
const val = await this.getAsync(key);
return val === TRUE_STR;
}
public getAsync<T = string>(key: string): Promise<T> {
return this._electronService.invoke(IPC_STORE_GET_OBJECT, this.storageName, key);
}
public getSync<T = string>(key: string): T {
return this._electronService.sendSync<T>(IPC_STORE_GET_OBJECT_SYNC, this.storageName, key);
}
public async setAsync(key: string, value: unknown): Promise<void> {
return await this._electronService.invoke(IPC_STORE_SET_OBJECT, this.storageName, key, value);
}
public getObjectAsync<T>(key: string): Promise<T | undefined> {
return this._electronService.invoke(IPC_STORE_GET_OBJECT, this.storageName, key);
}
}

View File

@@ -328,6 +328,10 @@ export class WowUpService {
await this._fileService.showDirectory(this.applicationLogsFolderPath);
}
public async showConfigFolder(): Promise<void> {
await this._fileService.showDirectory(this.applicationFolderPath);
}
public checkForAppUpdate(): void {
this._electronService.send(IPC_APP_CHECK_UPDATE);
}

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Allow WowUp to scan symlink folders in your addon folder. Warning: they will be replaced when updating/installing."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "Uložit debugovací data",
"DEBUG_DATA_DESCRIPTION": "Zaloguje debugovací data do logovacího souboru pro případnou diagnostiku problémů s aplikací. Pro zvědavce: Tato data naleznete v nejnovějším logovacím souboru.",
"DEBUG_DATA_LABEL": "Debug data",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Erlaubt WowUp Symlink-Ordner in deinem Addon-Ordner zu scannen. Warnung: Diese werden beim Aktualisieren/Installieren ersetzt."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "Debug-Daten speichern",
"DEBUG_DATA_DESCRIPTION": "Protokolliere Debug-Daten, um mögliche Probleme zu diagnostizieren. Dies findest Du in Deiner aktuellen Protokolldatei (für Neugierige).",
"DEBUG_DATA_LABEL": "Debug-Daten",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Allow WowUp to scan symlink folders in your addon folder. Warning: they will be replaced when updating/installing."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "Dump Debug Data",
"DEBUG_DATA_DESCRIPTION": "Log debug data to help with diagnosing potential issues. This can be found in your latest log file for the curious.",
"DEBUG_DATA_LABEL": "Debug Data",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Permite a WowUp escanear enlaces simbólicos en la carpeta de addons.\nAdvertecia: Los enlaces serán reemplazados al actualizar/instalar los addons."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "Eliminar datos de depuración",
"DEBUG_DATA_DESCRIPTION": "Registra datos de depuración y ayuda a diagnosticar problemas potenciales. Puede curiosearlo abriendo el último archivo de registro.",
"DEBUG_DATA_LABEL": "Datos de depuración",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Allow WowUp to scan symlink folders in your addon folder. Warning: they will be replaced when updating/installing."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "Dump des données de débogage",
"DEBUG_DATA_DESCRIPTION": "Log les données de débogage pour aider à diagnostiquer les problèmes potentiels. Cela peut être trouvé dans votre dernier fichier journal pour les curieux.",
"DEBUG_DATA_LABEL": "Déboguer les données",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Consenti a WowUp di scansionare le cartelle dei symlinks nella cartella dell'addon. Attenzione: verranno sostituiti durante l'aggiornamento/installazione."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "Dump Dati Di Debug",
"DEBUG_DATA_DESCRIPTION": "Registra i dati di debug per aiutare a diagnosticare potenziali problemi. Questi dati possono essere trovati nei tuoi ultimi file di log.",
"DEBUG_DATA_LABEL": "Dati di Debug",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Allow WowUp to scan symlink folders in your addon folder. Warning: they will be replaced when updating/installing."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "디버그 데이터 덤프",
"DEBUG_DATA_DESCRIPTION": "잠재적인 문제를 진단하는데 도움을 주기 위해 디버그 데이터를 기록합니다. 궁금하시다면 최신 로그 파일에서 확인하실 수 있습니다.",
"DEBUG_DATA_LABEL": "디버그 데이터",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Allow WowUp to scan symlink folders in your addon folder. Warning: they will be replaced when updating/installing."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "Dump Debugdata",
"DEBUG_DATA_DESCRIPTION": "Loggfør debugdata for å hjelpe til med å diagnotisere eventuelle problemer. Hvis du er nyskgjerrig kan du finne dette i din siste loggfil.",
"DEBUG_DATA_LABEL": "Debugdata",

View File

@@ -149,6 +149,8 @@
"IGNORED": "Zignorowany",
"INSTALL": "Zainstaluj",
"PENDING": "W toku",
"UNAVAILABLE": "Unavailable",
"UNAVAILABLE_TOOLTIP": "This author or provider has made this addon unavailable",
"UNINSTALL": "Odinstaluj",
"UNKNOWN": "",
"UPDATE": "Aktualizacja",
@@ -469,6 +471,11 @@
"OPTIONS": {
"ADDON": {
"AD_REQUIRED_HINT": "Reklama wymagana",
"CURSE_FORGE_V2": {
"API_KEY_DESCRIPTION": "If you have requested a CurseForge API key you can input it here to connect to their API.",
"API_KEY_TITLE": "CurseForge API Key",
"PROVIDER_NOTE": "API Key Required"
},
"ENABLED_PROVIDERS": {
"DESCRIPTION": "Wybierz, którzy dostawcy mogą być używani do wyszukiwania i instalowania nowych addonów",
"FIELD_LABEL": "Włączone addony dostawców",
@@ -524,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Pozwól WowUp na skanowanie folderów z symlinkami w folderze addonów. Ostrzeżenie: zostaną one zastąpione podczas aktualizacji/instalacji."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "Zrzut danych debugowania",
"DEBUG_DATA_DESCRIPTION": "Rejestruj dane debugowania, aby pomóc w diagnozowaniu potencjalnych problemów. Można je znaleźć w najnowszym pliku dziennika dla ciekawskich.",
"DEBUG_DATA_LABEL": "Dane debugowania",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Permitir ao WowUp escanear pastas symlink na sua pasta de Addons. Aviso: elas serão substituidas quando atualizar/instalar."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "Esvaziar log de depuração de dados",
"DEBUG_DATA_DESCRIPTION": "Registra os dados de depuração e ajuda a diagnosticar problemas potenciais. Apenas por o curiosidade, isso pode ser encontrado em seu último arquivo de registro.",
"DEBUG_DATA_LABEL": "Depurar Dados",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "Разрешает WowUp сканировать папки символических ссылок в папке вашей модификации. Предупреждение: они будут заменены при обновлении/установке."
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "Дамп отладочных данных",
"DEBUG_DATA_DESCRIPTION": "Записывать отладочные данные, чтобы помочь в диагностике потенциальных проблем. Его можно найти в последнем лог-файле, если необходимо.",
"DEBUG_DATA_LABEL": "Отладка данных",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "允許 WowUp 掃描插件所在路徑下的符號連結。警告:符號連結在安裝或更新插件時會被替換。"
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "轉儲除錯資料",
"DEBUG_DATA_DESCRIPTION": "記錄除錯資料以幫助診斷潛在的問題。除錯資料可以在最新的日誌檔案中找到。",
"DEBUG_DATA_LABEL": "除錯資料",

View File

@@ -531,6 +531,9 @@
"USE_SYMLINK_SUPPORT_DESCRIPTION": "允许 WowUp 扫描插件所在路径下的符号链接。警告:符号链接在安装或更新插件时会被替换。"
},
"DEBUG": {
"CONFIG_FILES_BUTTON": "Show Config Files",
"CONFIG_FILES_DESCRIPTION": "Open the folder where for example your addons.json and preferences.json are stored.",
"CONFIG_FILES_LABEL": "Config Files",
"DEBUG_DATA_BUTTON": "转储调试数据",
"DEBUG_DATA_DESCRIPTION": "记录调试数据以帮助诊断潜在的问题。调试数据可以在最新的日志文件中找到。",
"DEBUG_DATA_LABEL": "调试数据",

View File

@@ -109,6 +109,7 @@ export const IPC_STORE_REMOVE_OBJECT = "store-remove-object";
// STORES
export const ADDON_STORE_NAME = "addons";
export const PREFERENCE_STORE_NAME = "preferences";
export const SENSITIVE_STORE_NAME = "sensitive";
export const STORAGE_WOWUP_AUTH_TOKEN = "wowup-auth-token";
// PREFERENCES