Skip to content

Commit

Permalink
Version 2.0.0 - Secret Key encryption logic (#14)
Browse files Browse the repository at this point in the history
* Account encryption logic
* Clean-up and code organization
* Create script to check if all translation files has all the keys present in en.json
* Fix crypto api check
* Migration infrastructure
* Batch update accounts logic
* Update version in package.json
* firstRun flag
  • Loading branch information
jlcvp authored Oct 8, 2024
1 parent 16cfcdf commit 3d15e8b
Show file tree
Hide file tree
Showing 31 changed files with 1,741 additions and 318 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"root": true,
"ignorePatterns": ["projects/**/*"],
"env": {
"es6": true
},
"overrides": [
{
"files": ["*.ts"],
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/check-translations-pull-request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Check Translations on Pull Request
on:
pull_request:
branches:
- main
jobs:
check-translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run translations check
run: npm run translations:check
34 changes: 33 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
{
"typescript.preferences.autoImportFileExcludePatterns": ["@ionic/angular/common", "@ionic/angular/standalone"]
"typescript.preferences.autoImportFileExcludePatterns": [
"@ionic/angular/common",
"@ionic/angular/standalone"
],
"i18n-ally.localesPaths": [
"src/assets/i18n",
],
"i18n-ally.keystyle": "nested",
"i18n-ally.keysInUse": [
"CRYPTO_API_NOT_SUPPORTED",
"ACCOUNT_SELECT_MODAL.DESELECT_ALL",
"ACCOUNT_SELECT_MODAL.SELECT_ALL",
"ADD_ACCOUNT_MODAL.ERROR_MSGS.INVALID_SESSION",
"ACCOUNT_SYNC.ERROR.CORRUPT_BACKUP_FILE",
"ACCOUNT_SYNC.ERROR.EMPTY_FILE",
"ACCOUNT_SYNC.ERROR.GENERIC_IMPORT_ERROR",
"ACCOUNT_SYNC.ERROR.NO_ACCOUNTS_SELECTED_TO_IMPORT",
"CONFIG_MENU.ENCRYPTION_ACTIVE",
"CONFIG_MENU.ENCRYPTION_INACTIVE",
"CRYPTO.ALREADY_DECRYPTED",
"CRYPTO.ALREADY_ENCRYPTED",
"CRYPTO.MISSING_ENCRYPTED_DATA",
"LOGIN.VALIDATION_MSGS.EMAIL_PATTERN",
"LOGIN.VALIDATION_MSGS.REQUIRED_EMAIL",
"LOGIN.VALIDATION_MSGS.REQUIRED_PASSWORD",
"LOGIN.ERROR_MSGS.DEFAULT_ERROR",
"LOGIN.ERROR_MSGS.INVALID_PASSWORD",
"LOGIN.ERROR_MSGS.TOO_MANY_ATTEMPTS_TRY_LATER",
"LOGIN.ERROR_MSGS.USER_NOT_FOUND",
"ACCOUNT_SERVICE.ERROR.ACCOUNT_NOT_FOUND",
"UTILS.ERROR_INVALID_SEMVER_FORMAT"
],
"i18n-ally.sourceLanguage": "en"
}
92 changes: 90 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
{
"name": "authleu",
"version": "1.0.1",
"version": "2.0.0",
"author": "Leonardo 'Leu' Pereira <[email protected]>",
"homepage": "https://github.com/jlcvp/AuthLeu",
"description": "Open source authenticator and 2fa code generator to use across multiple devices and platforms",
"scripts": {
"ng": "ng",
"start": "ng serve",
"prebuild": "npm run version:config",
"build": "ng build",
"build:githubpages": "ng build --configuration githubpages --base-href ./",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"lint": "ng lint",
"translations:check": "node ./resources/scripts/translations_complete_check.js",
"firebase:deploy:firestore:indexes": "firebase deploy --only firestore:indexes",
"firebase:deploy:hosting": "ng build --prod && firebase deploy --only hosting",
"firebase:deploy:all": "ng build --prod && firebase deploy"
"firebase:deploy:all": "ng build --prod && firebase deploy",
"version:config": "node ./resources/scripts/version-config.js"
},
"private": true,
"dependencies": {
Expand Down Expand Up @@ -70,7 +74,7 @@
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"replace-in-file": "^6.3.5",
"typescript": "~5.4.0"
},
"description": "An Ionic project"
}
}
62 changes: 62 additions & 0 deletions resources/scripts/translations_complete_check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const { exit } = require('process');

const directoryPath = path.join(__dirname, '../../src/assets/i18n');
const baseFileName = 'en.json';
const baseFilePath = path.join(directoryPath, baseFileName);

function loadJson(filePath) {
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
}

function compareKeys(baseKeys, targetKeys, prefix = '') {
let success = true;
for (const key of baseKeys) {
if (!targetKeys.includes(key)) {
console.error(`Missing key in target file: ${prefix}${key}`);
success = false
}
}
return success
}

function getAllKeys(obj, prefix = '') {
return Object.keys(obj).reduce((keys, key) => {
const fullKey = prefix ? `${prefix}.${key}` : key;
if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
keys.push(...getAllKeys(obj[key], fullKey));
} else {
keys.push(fullKey);
}
return keys;
}, []);
}

const baseFile = loadJson(baseFilePath);
const baseKeys = getAllKeys(baseFile);

fs.readdir(directoryPath, (err, files) => {
if (err) {
console.log('Unable to scan directory: ' + err);
exit(1);
}

files.forEach(file => {
if (file !== baseFileName && file.endsWith('.json')) {
const targetFilePath = path.join(directoryPath, file);
const targetFile = loadJson(targetFilePath);
const targetKeys = getAllKeys(targetFile);

process.stdout.write(`Comparing translation keys in ${baseFileName} with ${file}...`);
const success = compareKeys(baseKeys, targetKeys);
if (!success) {
exit(1);
}
console.log(' OK');
}
});
exit(0);
});
21 changes: 21 additions & 0 deletions resources/scripts/version-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env node

const replacer = require('replace-in-file')
const package = require('../../package.json')

const buildDate = new Date().toISOString()
// get git commit hash from GITHUB_SHA environment variable
const commitHash = process.env.GITHUB_SHA || 'unknown'

const options = {
files: 'src/environments/environment*.ts',
from: [/%VERSION%/g, /%BUILD_DATE%/g, /%COMMIT_HASH%/g],
to: [package.version, buildDate, commitHash],
}

try {
const changes = replacer.sync(options)
console.log('Modified files:', JSON.stringify(changes, null, 2))
} catch (error) {
console.error('Error replacing version strings occurred:', error)
}
19 changes: 15 additions & 4 deletions src/app/components/account-list/account-list.component.html
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
<div class="account-list-container">
<!-- CARD GRID -->
<ion-grid *ngIf="isGridType; else listView">
<ion-row>
<ion-col *ngFor="let account of accounts; trackBy:itemTrackBy" size-xs="4" size-sm="3" size-md="2">
<ion-card (click)="selectAccount(account)" class="ion-no-padding ion-no-margin square fill-parent ion-activatable ripple-parent">
<ion-ripple-effect></ion-ripple-effect>
<ion-card-content class="ion-no-padding ion-padding-start ion-padding-end">
<ion-card button [disabled]="account.isLocked" (click)="selectAccount(account)" class="ion-no-padding ion-no-margin square fill-parent ion-activatable clickable">
<!-- <ion-ripple-effect></ion-ripple-effect> -->
<ion-card-content class="ion-no-padding ion-padding-start ion-padding-end ">
<ion-thumbnail class="thumb ion-no-padding ion-padding-top">
<img class="thumb-img" [src]="account.getLogo()">
</ion-thumbnail>
<p class="small-text ion-text-center ion-no-padding ion-padding-top">{{account.label}}</p>
</ion-card-content>
<div class="float-bottom" *ngIf="account.isLocked">
<div class="lock-overlay">
<ion-icon slot="end" color="light" name="lock-closed-outline"></ion-icon>
</div>
</div>
</ion-card>
</ion-col>
</ion-row>
</ion-grid>
<!-- LIST VIEW -->
<ng-template #listView>
<ion-list>
<ion-item button *ngFor="let account of accounts; trackBy:itemTrackBy" (click)="selectAccount(account)">
<ion-item button *ngFor="let account of accounts; trackBy:itemTrackBy" [disabled]="account.isLocked" (click)="selectAccount(account)">
<ion-thumbnail slot="start">
<img class="thumb-img" [src]="account.getLogo()">
</ion-thumbnail>
<ion-label>
<h2>{{account.label}}</h2>
<p *ngIf="account.isLocked">({{ 'ACCOUNT_LIST.LOCKED' | translate }})</p>
</ion-label>
<ion-badge color="danger" slot="end">
<ion-icon *ngIf="account.isLocked" name="lock-closed-outline"></ion-icon>
</ion-badge>
</ion-item>
</ion-list>
</ng-template>
Expand Down
23 changes: 22 additions & 1 deletion src/app/components/account-list/account-list.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

.thumb {
width: 100%;
max-height: 20%;
max-height: 35%;
display: flex;
justify-content: center;
align-items: center;
Expand All @@ -13,9 +13,30 @@
.fill-parent {
width: 100%;
height: 100%;
}

.square {
aspect-ratio: 1;
}

.small-text {
font-size: 0.8em;
}

.float-bottom {
position: absolute;
bottom: 0;
width: 100%;
}

.lock-overlay {
display: flex;
justify-content: center;
align-items: center;
background-color: var(--ion-color-danger);
padding: 2px;
}

.clickable {
cursor: pointer;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<ion-title>{{ title || ("ACCOUNT_SELECT_MODAL.DEFAULT_TITLE" | translate) }}</ion-title>
<ion-buttons slot="end">
<ion-button (click)="onConfirm()" [disabled]="selectedAccountsCount<1">
<ion-label>{{ confirmText || ("CONFIRM_SELECTION.EXPORT" | translate) }}</ion-label>
<ion-label>{{ confirmText || ("ACCOUNT_SELECT_MODAL.CONFIRM_SELECTION" | translate) }}</ion-label>
</ion-button>
</ion-buttons>
</ion-toolbar>
Expand Down
Loading

0 comments on commit 3d15e8b

Please sign in to comment.