Compare commits

...

397 Commits

Author SHA1 Message Date
Leendert de Borst
581d1dac5a Merge pull request #558 from lanedirt/557-prepare-0111-release
Bump version to 0.11.1
2025-01-22 12:18:20 +01:00
Leendert de Borst
50b3872ae0 Bump version to 0.11.1 (#557) 2025-01-22 12:17:29 +01:00
Leendert de Borst
2ea2526858 Merge pull request #554 from lanedirt/553-bug-menu-dropdown-does-not-align-correctly-on-very-wide-screens
Update mobile menu position in client and admin
2025-01-22 12:13:28 +01:00
Leendert de Borst
2d9b6f38b0 Merge pull request #556 from lanedirt/555-use-relative-url-to-access-api-instead-of-requiring-hostname-in-env
Simplify installation by using relative url for API instead of requiring hostname in env file
2025-01-22 12:13:11 +01:00
Leendert de Borst
a941ffa837 Update install.sh (#555) 2025-01-22 12:06:15 +01:00
Leendert de Borst
e2da05ac2c Update manual setup docs (#555) 2025-01-22 11:26:03 +01:00
Leendert de Borst
dd8108c974 Update install to only require hostname for SSL configuration (#555) 2025-01-22 11:19:09 +01:00
Leendert de Borst
206f8fc2b1 Remove explicit API URL for Docker environments (#555) 2025-01-22 11:01:54 +01:00
Leendert de Borst
5a432e4ab5 Update client to make API URL optional (#555) 2025-01-22 11:01:27 +01:00
Leendert de Borst
83ba9222bd Update mobile menu position in client and admin (#553) 2025-01-21 11:09:53 +01:00
Leendert de Borst
7e7a8b04ef Update README.md 2025-01-20 18:30:23 +01:00
dependabot[bot]
a28b5012d6 Bump Microsoft.AspNetCore.Components.WebAssembly.DevServer
Bumps [Microsoft.AspNetCore.Components.WebAssembly.DevServer](https://github.com/dotnet/aspnetcore) from 9.0.0 to 9.0.1.
- [Release notes](https://github.com/dotnet/aspnetcore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](https://github.com/dotnet/aspnetcore/compare/v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Components.WebAssembly.DevServer
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 12:14:17 +01:00
dependabot[bot]
85218a8fd1 Bump Microsoft.IdentityModel.JsonWebTokens and Microsoft.IdentityModel.Tokens
Bumps [Microsoft.IdentityModel.JsonWebTokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) and [Microsoft.IdentityModel.Tokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet). These dependencies needed to be updated together.

Updates `Microsoft.IdentityModel.JsonWebTokens` from 8.3.0 to 8.3.1
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/8.3.1/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.3.0...8.3.1)

Updates `Microsoft.IdentityModel.Tokens` from 8.3.0 to 8.3.1
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/8.3.1/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.3.0...8.3.1)

---
updated-dependencies:
- dependency-name: Microsoft.IdentityModel.JsonWebTokens
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: Microsoft.IdentityModel.Tokens
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 12:14:09 +01:00
dependabot[bot]
590454b69e Bump Microsoft.AspNetCore.Mvc.Testing from 9.0.0 to 9.0.1
Bumps [Microsoft.AspNetCore.Mvc.Testing](https://github.com/dotnet/aspnetcore) from 9.0.0 to 9.0.1.
- [Release notes](https://github.com/dotnet/aspnetcore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](https://github.com/dotnet/aspnetcore/compare/v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Mvc.Testing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 11:49:43 +01:00
dependabot[bot]
d81d48ee16 Bump Microsoft.Extensions.Configuration and Microsoft.Extensions.Configuration.FileExtensions
Bumps [Microsoft.Extensions.Configuration](https://github.com/dotnet/runtime) and [Microsoft.Extensions.Configuration.FileExtensions](https://github.com/dotnet/runtime). These dependencies needed to be updated together.

Updates `Microsoft.Extensions.Configuration` from 9.0.0 to 9.0.1
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v9.0.0...v9.0.1)

Updates `Microsoft.Extensions.Configuration.FileExtensions` from 9.0.0 to 9.0.1
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.Configuration
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: Microsoft.Extensions.Configuration.FileExtensions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 11:40:02 +01:00
dependabot[bot]
b72217eb04 Bump coverlet.collector from 6.0.3 to 6.0.4
Bumps [coverlet.collector](https://github.com/coverlet-coverage/coverlet) from 6.0.3 to 6.0.4.
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/compare/v6.0.3...v6.0.4)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 11:39:53 +01:00
dependabot[bot]
8942795e76 Bump Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Bumps [Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore](https://github.com/dotnet/aspnetcore) from 9.0.0 to 9.0.1.
- [Release notes](https://github.com/dotnet/aspnetcore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](https://github.com/dotnet/aspnetcore/compare/v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 11:39:46 +01:00
dependabot[bot]
08290e1fa5 Bump Microsoft.AspNetCore.Authorization and Microsoft.AspNetCore.Components.WebAssembly.Authentication
Bumps [Microsoft.AspNetCore.Authorization](https://github.com/dotnet/aspnetcore) and [Microsoft.AspNetCore.Components.WebAssembly.Authentication](https://github.com/dotnet/aspnetcore). These dependencies needed to be updated together.

Updates `Microsoft.AspNetCore.Authorization` from 9.0.0 to 9.0.1
- [Release notes](https://github.com/dotnet/aspnetcore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](https://github.com/dotnet/aspnetcore/compare/v9.0.0...v9.0.1)

Updates `Microsoft.AspNetCore.Components.WebAssembly.Authentication` from 9.0.0 to 9.0.1
- [Release notes](https://github.com/dotnet/aspnetcore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](https://github.com/dotnet/aspnetcore/compare/v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Authorization
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: Microsoft.AspNetCore.Components.WebAssembly.Authentication
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 11:39:38 +01:00
dependabot[bot]
7b45b44735 Bump Microsoft.AspNetCore.DataProtection from 9.0.0 to 9.0.1
Bumps [Microsoft.AspNetCore.DataProtection](https://github.com/dotnet/aspnetcore) from 9.0.0 to 9.0.1.
- [Release notes](https://github.com/dotnet/aspnetcore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](https://github.com/dotnet/aspnetcore/compare/v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.DataProtection
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 11:39:30 +01:00
dependabot[bot]
ae6913a8e0 Bump Microsoft.AspNetCore.Authentication.JwtBearer, Microsoft.IdentityModel.JsonWebTokens and Microsoft.IdentityModel.Tokens
Bumps [Microsoft.AspNetCore.Authentication.JwtBearer](https://github.com/dotnet/aspnetcore), [Microsoft.IdentityModel.JsonWebTokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) and [Microsoft.IdentityModel.Tokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet). These dependencies needed to be updated together.

Updates `Microsoft.AspNetCore.Authentication.JwtBearer` from 9.0.0 to 9.0.1
- [Release notes](https://github.com/dotnet/aspnetcore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](https://github.com/dotnet/aspnetcore/compare/v9.0.0...v9.0.1)

Updates `Microsoft.IdentityModel.JsonWebTokens` from 8.3.0 to 8.0.1
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.3.0...8.0.1)

Updates `Microsoft.IdentityModel.Tokens` from 8.3.0 to 8.0.1
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.3.0...8.0.1)

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: Microsoft.IdentityModel.JsonWebTokens
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: Microsoft.IdentityModel.Tokens
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 11:39:24 +01:00
Leendert de Borst
7470ac9e16 Update README.md tech stack 2025-01-16 13:45:54 +01:00
Leendert de Borst
521d10da19 Update roadmap 2025-01-15 18:40:15 +01:00
Leendert de Borst
98aee7bb35 Delete .github/ISSUE_TEMPLATE/security_issue.md 2025-01-15 18:28:53 +01:00
Leendert de Borst
d62f2c4450 Merge pull request #540 from lanedirt/539-add-github-issue-templates
Add GitHub issue templates
2025-01-15 17:27:50 +00:00
Leendert de Borst
95edcc3042 Add GitHub issue templates (#539) 2025-01-15 18:27:14 +01:00
Leendert de Borst
1bce686121 Create CODE_OF_CONDUCT.md 2025-01-15 18:19:18 +01:00
Leendert de Borst
742417d405 Update README.md 2025-01-15 18:00:22 +01:00
Leendert de Borst
2cfc8d528d Merge pull request #538 from lanedirt/537-prepare-0110-release
Bump version to 0.11.0
2025-01-14 13:51:15 +00:00
Leendert de Borst
7a4e1721c8 Bump version to 0.11.0 (#537) 2025-01-14 14:42:56 +01:00
Leendert de Borst
11d79c4874 Merge pull request #536 from lanedirt/535-make-application-warning-logs-more-readable
Make duplicate email warning log more readable
2025-01-14 13:32:16 +00:00
Leendert de Borst
7cd35b0a92 Make duplicate email warning log more readable (#535) 2025-01-14 12:30:36 +01:00
Leendert de Borst
d0f62a26c0 Merge pull request #534 from lanedirt/530-update-sonarcloud-github-action-to-work-with-pr-from-forks
Update sonarcloud-code-analysis so it works for main and PRs (#530)
2025-01-14 11:20:41 +00:00
Leendert de Borst
01198502a3 Update sonarcloud-code-analysis so it works for main and PRs (#530) 2025-01-14 12:20:14 +01:00
Leendert de Borst
229ad109a7 Merge pull request #533 from lanedirt/530-update-sonarcloud-github-action-to-work-with-pr-from-forks
Add pullrequest key to sonarcloud analysis
2025-01-14 10:49:48 +00:00
Leendert de Borst
837b16d971 Add pullrequest key to sonarcloud analysis (#530) 2025-01-14 11:49:04 +01:00
Leendert de Borst
4010d1b93f Merge pull request #531 from lanedirt/530-update-sonarcloud-github-action-to-work-with-pr-from-forks
Update sonarcloud-code-analysis.yml to work with PR's from forks
2025-01-14 10:28:48 +00:00
Leendert de Borst
f7ce60ae68 Update sonarcloud-code-analysis.yml to work with PR's from forks (#530) 2025-01-14 11:26:37 +01:00
Leendert de Borst
5e61bd5db2 Merge pull request #527 from lanedirt/525-prevent-email-address-collision-from-occuring
Prevent email address collision from occurring during identity generation
2025-01-13 14:09:54 +00:00
dependabot[bot]
a2e8a438de Bump NUnit.Analyzers from 4.5.0 to 4.6.0
Bumps [NUnit.Analyzers](https://github.com/nunit/nunit.analyzers) from 4.5.0 to 4.6.0.
- [Release notes](https://github.com/nunit/nunit.analyzers/releases)
- [Changelog](https://github.com/nunit/nunit.analyzers/blob/master/CHANGES.md)
- [Commits](https://github.com/nunit/nunit.analyzers/compare/4.5.0...4.6.0)

---
updated-dependencies:
- dependency-name: NUnit.Analyzers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-13 14:09:38 +00:00
Leendert de Borst
92904dcf55 Refactor email prefix exists check (#525) 2025-01-12 15:29:15 +00:00
Leendert de Borst
e4f2ca630b Add server side email prefix generation method (#525) 2025-01-12 14:01:48 +00:00
Leendert de Borst
ed80ad24c1 Add more names to identity generator dictionary to prevent collisions (#525) 2025-01-12 13:02:22 +00:00
Leendert de Borst
0c368ab84b Merge pull request #524 from lanedirt/151-make-email-attachments-visible-in-ui-and-allow-for-downloading-attachments-through-client
Add email attachment support
2025-01-11 16:15:49 +00:00
Leendert de Borst
dee2044ed6 Refactor (#151) 2025-01-11 16:05:32 +00:00
dependabot[bot]
f6f6072b3f Bump coverlet.msbuild from 6.0.2 to 6.0.3
Bumps [coverlet.msbuild](https://github.com/coverlet-coverage/coverlet) from 6.0.2 to 6.0.3.
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/compare/v6.0.2...v6.0.3)

---
updated-dependencies:
- dependency-name: coverlet.msbuild
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-11 15:57:26 +00:00
dependabot[bot]
4bfe72d750 Bump coverlet.collector from 6.0.2 to 6.0.3
Bumps [coverlet.collector](https://github.com/coverlet-coverage/coverlet) from 6.0.2 to 6.0.3.
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/compare/v6.0.2...v6.0.3)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-11 15:56:56 +00:00
Leendert de Borst
330f59dc10 Add email decryption test with and without attachments (#151) 2025-01-11 15:45:54 +00:00
Leendert de Borst
a20d981427 Add full attachment download flow to email decryption test (#151) 2025-01-11 13:10:26 +00:00
Leendert de Borst
bd2274db75 Add support for download attachments from SpamOK (#151) 2025-01-11 12:58:40 +00:00
Leendert de Borst
6cfa6f4ef5 Add email attachment retrieval and decryption to client (#151) 2025-01-11 12:49:35 +00:00
Leendert de Borst
8a40d2b1b9 Add attachment encryption assert to test (#151) 2025-01-10 21:35:22 +00:00
Leendert de Borst
237958ba0f Show attachment metadata in email modal popup (#151) 2025-01-10 19:13:18 +00:00
Leendert de Borst
79db3a54c7 Tweak client z-index to show emailmodal on top (#151) 2025-01-10 19:12:45 +00:00
Leendert de Borst
2029745f8b Fix tablet view for credential view page width (#151) 2025-01-10 18:54:51 +00:00
Leendert de Borst
ea4d498502 Update sendEmailCLI.sh to support sending attachments (#151) 2025-01-10 15:05:17 +00:00
Leendert de Borst
05838f5dca Add attachment indicator E2E test on email page (#151) 2025-01-10 14:55:45 +00:00
Leendert de Borst
79872163e2 Add attachment indicator to email page (#151) 2025-01-10 14:55:27 +00:00
Leendert de Borst
35d0f77dd6 Add HasAttachments to mailbox api model (#151) 2025-01-10 14:29:17 +00:00
Leendert de Borst
6660cd20bd Update docker-compose-pull.yml (#522) 2025-01-08 14:28:34 +00:00
Ikko Eltociear Ashimine
e236ba454f chore: update UserEmailClaim.cs (#521)
adress -> address
2025-01-08 14:13:14 +00:00
Leendert de Borst
6ec66e4d64 Merge pull request #517 from lanedirt/516-optimize-local-build-for-arm-devices
Add support for arm64 to docker images and install.sh local build
2025-01-04 09:37:00 +01:00
Leendert de Borst
14898c0c83 Refactor Dockerfile for readability (#516) 2025-01-04 09:24:05 +01:00
Leendert de Borst
d08bec9df7 Bump version to 0.10.3 (#516) 2025-01-04 01:31:07 +01:00
Leendert de Borst
9107dfa789 Update Docker images to also build for linux/arm64 (#516) 2025-01-04 01:04:57 +01:00
Leendert de Borst
351f6f4d16 Update install.sh (#516) 2025-01-03 23:55:51 +01:00
Leendert de Borst
aca607e579 Merge pull request #515 from lanedirt/514-prepare-0102-release
Bump version to 0.10.2
2025-01-03 22:30:47 +01:00
Leendert de Borst
ed053422ba Update StatusHostedService.cs (#512) 2025-01-03 22:15:27 +01:00
Leendert de Borst
955b8638ce Bump version (#514) 2025-01-03 21:50:14 +01:00
Leendert de Borst
1d8883cc94 Merge pull request #513 from lanedirt/512-task-runner-cleanup-jobs-do-not-run
Maintenance tasks do not run after migration to PostgreSQL
2025-01-03 21:45:04 +01:00
Leendert de Borst
48281f92e6 Refactor to reduce complexity (#512) 2025-01-03 21:29:42 +01:00
Leendert de Borst
f19db2c010 Refactor StatusWorker to prevent race conditions and improve stability (#512) 2025-01-03 20:38:13 +01:00
Leendert de Borst
f0d397c8af Add cancellation token check to worker start and stop wait (#512) 2025-01-03 16:18:37 +01:00
Leendert de Borst
fafa51d787 Update integration tests (#512) 2025-01-03 16:08:09 +01:00
Leendert de Borst
202151e4f1 Update SmtpServer TestHostBuilder to be compatible with integration and E2E tests (#512) 2025-01-03 15:36:09 +01:00
Leendert de Borst
c123edccd4 Refactor integration test TestHostBuilder setup to shared abstract class (#512) 2025-01-03 15:22:47 +01:00
Leendert de Borst
50cab3a2f3 Show full error when maintenance task fails to start (#512) 2025-01-03 12:44:55 +01:00
Leendert de Borst
0184e32e6d Update migration to reset task runner job sequence (#512) 2025-01-03 12:44:40 +01:00
Leendert de Borst
d73d4e90e0 Make admin password for dev always override existing password (#512) 2025-01-03 11:58:33 +01:00
Leendert de Borst
06d38842f5 Add dev database import/export support (#512) 2025-01-03 11:56:55 +01:00
Leendert de Borst
b0748316ff Merge pull request #511 from lanedirt/510-admin-password-hash-method-in-installcli-does-not-pass-required-arguments
Admin password hash method in installcli does not pass required arguments
2025-01-01 16:18:36 +01:00
Leendert de Borst
8f8b4af3c9 Update install.sh (#510) 2025-01-01 16:18:15 +01:00
Leendert de Borst
11bf183cbb Update install.sh (#510) 2025-01-01 16:17:41 +01:00
Leendert de Borst
ac64dba715 Merge pull request #509 from lanedirt/508-prepare-0100-release
Prepare 0.10.0 release
2025-01-01 15:43:28 +01:00
Leendert de Borst
d2f9b225d0 Start services again after db migration (#508) 2025-01-01 15:01:13 +01:00
Leendert de Borst
d7f1df3252 Update AppInfo bump version (#508) 2025-01-01 14:56:28 +01:00
Leendert de Borst
fdce8bddd1 Bump install.sh version (#508) 2025-01-01 14:56:15 +01:00
Leendert de Borst
be4a105709 Update docs (#508) 2025-01-01 14:56:02 +01:00
Leendert de Borst
dfa2f84570 Merge pull request #507 from lanedirt/506-add-postgresql-database-import-and-export-commands-to-installsh
Add postgresql database import and export commands to install.sh
2024-12-31 21:40:49 +01:00
Leendert de Borst
450ca6a6f4 Update db-import command (#506) 2024-12-31 21:34:23 +01:00
Leendert de Borst
4c31912d73 Add db import and export commands to install.sh (#506) 2024-12-31 21:18:44 +01:00
dependabot[bot]
367be5a409 Bump NUnit from 4.3.1 to 4.3.2
Bumps [NUnit](https://github.com/nunit/nunit) from 4.3.1 to 4.3.2.
- [Release notes](https://github.com/nunit/nunit/releases)
- [Changelog](https://github.com/nunit/nunit/blob/main/CHANGES.md)
- [Commits](https://github.com/nunit/nunit/compare/4.3.1...4.3.2)

---
updated-dependencies:
- dependency-name: NUnit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-31 17:57:22 +01:00
dependabot[bot]
b6cf46ab91 Bump HtmlAgilityPack from 1.11.71 to 1.11.72
Bumps [HtmlAgilityPack](https://github.com/zzzprojects/html-agility-pack) from 1.11.71 to 1.11.72.
- [Release notes](https://github.com/zzzprojects/html-agility-pack/releases)
- [Commits](https://github.com/zzzprojects/html-agility-pack/compare/v1.11.71...v1.11.72)

---
updated-dependencies:
- dependency-name: HtmlAgilityPack
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-31 17:57:14 +01:00
Leendert de Borst
0da0bd0b17 Merge pull request #505 from lanedirt/503-searching-in-admin-table-pages-defocuses-search-field-after-every-character-typed
Do not show loading indicator when refreshing in admin
2024-12-31 17:56:01 +01:00
Leendert de Borst
d8ccaad806 Merge pull request #504 from lanedirt/493-fix-dataprotection-api-errors-when-running-a-clean-docker-install
Do not log dataprotection warnings to database log
2024-12-31 17:50:07 +01:00
Leendert de Borst
656210e4f6 Do not show loading indicator when refreshing in admin (#503) 2024-12-31 17:48:29 +01:00
Leendert de Borst
c3c85bc10e Do not log dataprotection warnings to database log but keep for filelog (#493) 2024-12-31 17:37:17 +01:00
Leendert de Borst
693ad0b581 Update CONTRIBUTING.md 2024-12-31 15:29:32 +01:00
Leendert de Borst
94ad51059e Merge pull request #500 from lanedirt/491-link-from-contributindmd-to-the-official-docs-page
Update contributing documentation
2024-12-30 11:51:12 +01:00
Leendert de Borst
9374780a5b Update CONTRIBUTING.md (#491) 2024-12-29 12:30:34 +01:00
Leendert de Borst
3263360be5 Merge pull request #492 from lanedirt/190-add-postgresql-as-database-option-to-prevent-concurrency-locking-due-to-sqlite-limitations
Switch SQLite to PostgreSQL database engine
2024-12-29 12:15:32 +01:00
Leendert de Borst
1151089d59 Fix merge conflict (#190) 2024-12-28 17:06:50 +01:00
Leendert de Borst
d39ecf69e8 Merge pull request #499 from lanedirt/498-make-user-refreshtoken-lifetime-configurable-via-server-settings
Make UserRefreshToken lifetime configurable via admin
2024-12-28 16:58:29 +01:00
Leendert de Borst
9caea03460 Update AuthTests.cs (#498) 2024-12-28 16:45:06 +01:00
Leendert de Borst
32879e09a8 Make UserRefreshToken lifetime configurable via admin (#498) 2024-12-28 16:35:21 +01:00
Leendert de Borst
d3518eca6c Update install.sh add install.sh version check to install command itself (#190) 2024-12-28 15:52:33 +01:00
Leendert de Borst
329ae185ad Update docs (#190) 2024-12-28 14:28:09 +01:00
dependabot[bot]
888054e8ed Bump NUnit.Analyzers from 4.4.0 to 4.5.0
Bumps [NUnit.Analyzers](https://github.com/nunit/nunit.analyzers) from 4.4.0 to 4.5.0.
- [Release notes](https://github.com/nunit/nunit.analyzers/releases)
- [Changelog](https://github.com/nunit/nunit.analyzers/blob/master/CHANGES.md)
- [Commits](https://github.com/nunit/nunit.analyzers/compare/4.4.0...4.5.0)

---
updated-dependencies:
- dependency-name: NUnit.Analyzers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-27 17:46:07 +01:00
dependabot[bot]
0d141e2c7c Bump NUnit from 4.3.0 to 4.3.1
Bumps [NUnit](https://github.com/nunit/nunit) from 4.3.0 to 4.3.1.
- [Release notes](https://github.com/nunit/nunit/releases)
- [Changelog](https://github.com/nunit/nunit/blob/main/CHANGES.md)
- [Commits](https://github.com/nunit/nunit/compare/4.3.0...4.3.1)

---
updated-dependencies:
- dependency-name: NUnit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-27 17:29:08 +01:00
Leendert de Borst
33b930b58a Merge pull request #497 from lanedirt/495-improve-2fa-login-flow-to-automatically-submit-when-6-digits-have-been-entered
Auto submit login form when 2fa code is entered
2024-12-27 17:26:39 +01:00
Leendert de Borst
ad9eb79e9e Update CodeLockoutTests.cs (#495) 2024-12-27 16:56:20 +01:00
Leendert de Borst
cd46578576 Auto submit login form when 2fa code is entered (#495) 2024-12-27 10:43:04 +01:00
Leendert de Borst
e577d6fee4 Print warnring but do not exit on image pull fail (#190) 2024-12-26 01:30:32 +01:00
Leendert de Borst
9d1923d3ea Refactor dev db start (#190) 2024-12-26 01:26:43 +01:00
Leendert de Borst
d77c28184c Refactor (#190) 2024-12-26 01:13:40 +01:00
Leendert de Borst
180de219c8 Update installer to look at latest release instead of main (#190) 2024-12-26 00:41:58 +01:00
Leendert de Borst
17e4f614d8 Refactor postgres docker setup and update docs (#190) 2024-12-26 00:39:19 +01:00
Leendert de Borst
747e0910cb Update SQLite ef model (#190) 2024-12-25 23:10:24 +01:00
Leendert de Borst
fc85f34218 Update useremailclaims setnull to be compatible with PostgreSQL (#190) 2024-12-25 23:01:54 +01:00
Leendert de Borst
f0e0e9c03e Add TaskRunnerJobs to migration (#190) 2024-12-25 22:55:10 +01:00
Leendert de Borst
2631a1f0b1 Update migration (#190) 2024-12-25 22:47:44 +01:00
Leendert de Borst
254104e12d Update migration logging (#190) 2024-12-25 22:46:08 +01:00
Leendert de Borst
a75d5c7a34 Update migration add data truncation if source data exceeds length (#190) 2024-12-25 22:41:56 +01:00
Leendert de Borst
bf40539e92 Update dockerignore to ignore data directories during build (#190) 2024-12-25 22:41:40 +01:00
Leendert de Borst
cb330219ab Refactor postgres db folder creation (#190) 2024-12-25 22:26:58 +01:00
Leendert de Borst
4f5e822722 Include postgres empty dir in git to ensure correct permissions (#190) 2024-12-25 22:23:43 +01:00
Leendert de Borst
96997c7d8d Update docs (#190) 2024-12-25 22:21:19 +01:00
Leendert de Borst
f959b7dc91 Update install.sh (#190) 2024-12-25 22:21:13 +01:00
Leendert de Borst
59599f43a3 Update docs (#190) 2024-12-25 16:53:30 +01:00
Leendert de Borst
b5e575051c Update migration logic to reset auto increment id (#190) 2024-12-25 16:45:17 +01:00
Leendert de Borst
433664d85d Fix admin redirect absolute URL bug (#190) 2024-12-25 14:40:44 +01:00
Leendert de Borst
82b2b75127 Update docs with new update instructions (#190) 2024-12-25 14:24:31 +01:00
Leendert de Borst
577e02d761 Update install script (#190) 2024-12-25 14:24:16 +01:00
Leendert de Borst
26b1c4e044 Load security page components async (#190) 2024-12-25 12:11:17 +01:00
Leendert de Borst
3872678039 Sanitize email when retrieving emails for emailbox (#190) 2024-12-24 22:20:44 +01:00
Leendert de Borst
80cc72eb22 Fix RecentEmails.razor dispose bug (#190) 2024-12-24 22:20:12 +01:00
Leendert de Borst
141a291ace Fix bug in db sync tests (#190) 2024-12-24 20:49:38 +01:00
Leendert de Borst
3b5e944417 Refactor (#190) 2024-12-24 15:48:34 +01:00
Leendert de Borst
65553e0918 Update postgresql date column types to improve compatiblity (#190) 2024-12-24 15:27:04 +01:00
Leendert de Borst
a7502d42e4 Fix migration tool params called from install.sh (#190) 2024-12-24 14:56:37 +01:00
Leendert de Borst
4d43acb53f Add build container start/stop/restart commands (#190) 2024-12-24 13:50:49 +01:00
Leendert de Borst
14ac94b78a Add migrate-db command to install.sh (#190) 2024-12-24 13:08:48 +01:00
Leendert de Borst
361f4b8817 Added migration logic from sqlite to postgresql (#190) 2024-12-24 12:53:22 +01:00
Leendert de Borst
7a62ddcf6a Enable postgresql legacy timestamp behavior (#190) 2024-12-24 12:39:57 +01:00
Leendert de Borst
6b59200df2 Fix migrations (#190) 2024-12-24 11:59:37 +01:00
Leendert de Borst
6a0699318c Add sqlite migrations to be in sync with postgresql model (#190) 2024-12-23 21:41:25 +01:00
Leendert de Borst
f6e2648a53 Update GitHub actions for postgresql (#190) 2024-12-23 20:52:39 +01:00
Leendert de Borst
4b8e4c907e Refactor WebApplicationFactoryFixture (#190) 2024-12-23 20:10:47 +01:00
Leendert de Borst
30804cc973 Update DataProtectionExtensions.cs (#190) 2024-12-23 18:00:47 +01:00
Leendert de Borst
8edfc3d0d6 Update Logout.razor (#190) 2024-12-23 17:11:30 +01:00
Leendert de Borst
4fb5087c82 Add local postgresql dev database (#190) 2024-12-23 16:31:02 +01:00
Leendert de Borst
cf454d2bb8 Add postgres healthcheck to docker-compose.yml (#190) 2024-12-23 16:03:59 +01:00
Leendert de Borst
0a577873ee Update install.sh to create postgres credentials (#190) 2024-12-23 15:40:00 +01:00
Leendert de Borst
32c8e48d45 Update Dockerfile (#190) 2024-12-23 15:25:18 +01:00
Leendert de Borst
564ae54de8 Update postgresql factory to support env vars if available (#190) 2024-12-23 15:11:34 +01:00
Leendert de Borst
d9f4f8d121 Update Dockerfile (#190) 2024-12-23 14:38:07 +01:00
Leendert de Borst
728b20b489 Update install.sh (#190) 2024-12-23 14:18:47 +01:00
Leendert de Borst
219f0bc9cc Update db configuration (#190) 2024-12-23 14:17:17 +01:00
Leendert de Borst
9735df0436 Update install.sh to generate postgresql credentials (#190) 2024-12-23 13:57:01 +01:00
Leendert de Borst
78a872a67d Refactor smtpserver and taskrunner so all tests pass (#190) 2024-12-23 12:58:07 +01:00
Leendert de Borst
77a48ea4e9 Refactor admin so all tests pass (#190) 2024-12-23 12:16:05 +01:00
Leendert de Borst
22538ae000 Refactor datetime to always use UTC (#190) 2024-12-22 21:36:01 +01:00
Leendert de Borst
db632c3edb Refactor SmtpService to use new dbcontextfactory (#190) 2024-12-22 20:05:05 +01:00
Leendert de Borst
1c53addcaa Refactor WebApi to use new dbcontextfactory (#190) 2024-12-22 18:58:24 +01:00
Leendert de Borst
817404cd08 Refactor UserService delete unused methods causing concurrency issues (#190) 2024-12-22 14:10:30 +01:00
Leendert de Borst
9062cdc701 Refactor admin project to use dbcontextfactory (#190) 2024-12-22 11:53:22 +01:00
Leendert de Borst
e45866fa67 Update EF models to not use driver specific fields (#190) 2024-12-22 11:26:16 +01:00
Leendert de Borst
8fbd10caaa Update admin project to use new IAliasServerDbContextFactory (#190) 2024-12-22 00:37:13 +01:00
Leendert de Borst
54d54f28b4 Move migrations for db engines to their respective folders (#190) 2024-12-22 00:07:31 +01:00
Leendert de Borst
3116aa5a1f Update postgresql.conf (#190) 2024-12-21 12:17:17 +01:00
Leendert de Borst
eb45358532 Update gitignore for db files (#190) 2024-12-21 12:09:43 +01:00
Leendert de Borst
03fd047cb4 Add postgresql docker container scaffolding (#190) 2024-12-21 11:56:08 +01:00
Leendert de Borst
6a7fc9c5ba Merge pull request #488 from lanedirt/343-add-option-to-disable-new-user-registration-via-installsh
Update install.sh
2024-12-20 20:23:06 +01:00
Leendert de Borst
62700de9ad Update install.sh (#343) 2024-12-20 20:22:43 +01:00
Leendert de Borst
edeaa77299 Merge pull request #487 from lanedirt/342-add-option-to-block-existing-user-in-admin
Add option to block existing user in admin
2024-12-20 19:57:39 +01:00
Leendert de Borst
84b93924f5 Add user block checks to api and add tests (#342) 2024-12-20 19:47:12 +01:00
Leendert de Borst
400e702753 Add user blocked status toggle to admin (#342) 2024-12-20 18:53:28 +01:00
Leendert de Borst
147f8db5d1 Add Blocked column to users table (#342) 2024-12-20 18:53:01 +01:00
Leendert de Borst
8e1470bc1b Merge pull request #486 from lanedirt/343-add-option-to-disable-new-user-registration-via-installsh
Add option to disable new user registration via install.sh
2024-12-20 18:24:50 +01:00
Leendert de Borst
50853bf011 Update tests (#343) 2024-12-20 17:30:28 +01:00
Leendert de Borst
07dd90a705 Add public registration enabled check to client (#343) 2024-12-20 16:52:05 +01:00
Leendert de Borst
a7a7d6d82b Rename public registration enabled flag (#343) 2024-12-20 16:51:51 +01:00
Leendert de Borst
249efe54b0 Add public registration env flag check to api (#343) 2024-12-20 16:06:15 +01:00
Leendert de Borst
20eb3e5ff4 Add public registration setting to install.sh (#343) 2024-12-20 15:56:30 +01:00
Leendert de Borst
ba15c446d9 Merge pull request #484 from lanedirt/483-dark-mode-text-readability-tweaks
Dark mode text readability tweaks
2024-12-19 15:54:55 +01:00
Leendert de Borst
5ea9f4ee08 Merge pull request #482 from lanedirt/481-add-username-sanity-check-on-vault-save-to-prevent-db-corruption-between-user-sessions
Add username sanity check to vault save to prevent potential vault collision/corruption
2024-12-19 15:54:47 +01:00
Leendert de Borst
1e7b7b172a Update tests to work with changed notifications (#481) 2024-12-19 15:39:22 +01:00
Leendert de Borst
35f6565c8b Update DbService.cs to fix merge return status (#481) 2024-12-19 15:16:28 +01:00
Leendert de Borst
8cb99c997d Update Logo.razor (#483) 2024-12-19 15:03:48 +01:00
Leendert de Borst
16cf528b7f Add dark mode tweaks to admin error page (#483) 2024-12-19 14:55:25 +01:00
Leendert de Borst
8ad3eb9bd5 Add dark mode tweaks to client two factor code page (#483) 2024-12-19 14:55:14 +01:00
Leendert de Borst
2d59c40e24 Refactor username sanity check to associate with vault load instead of login (#481) 2024-12-19 14:39:05 +01:00
Leendert de Borst
33283e07be Set username on unlock (#481) 2024-12-19 13:34:14 +01:00
Leendert de Borst
fbf5880370 Add username sanity check to vault save (#481) 2024-12-19 12:14:06 +01:00
Leendert de Borst
be4a74ef3c Update README.md 2024-12-18 10:54:09 +01:00
Leendert de Borst
a759091755 Update AppInfo.cs (#479) 2024-12-16 16:55:58 +01:00
dependabot[bot]
8dc99c09a8 Bump Swashbuckle.AspNetCore from 7.1.0 to 7.2.0
Bumps [Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) from 7.1.0 to 7.2.0.
- [Release notes](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/releases)
- [Commits](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/compare/v7.1.0...v7.2.0)

---
updated-dependencies:
- dependency-name: Swashbuckle.AspNetCore
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 12:19:17 +01:00
dependabot[bot]
b9ec4baf66 Bump NUglify from 1.21.10 to 1.21.11
Bumps [NUglify](https://github.com/trullock/NUglify) from 1.21.10 to 1.21.11.
- [Release notes](https://github.com/trullock/NUglify/releases)
- [Changelog](https://github.com/trullock/NUglify/blob/master/changelog.md)
- [Commits](https://github.com/trullock/NUglify/compare/v1.21.10...v1.21.11)

---
updated-dependencies:
- dependency-name: NUglify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 12:19:10 +01:00
Leendert de Borst
71ed62cdcb Merge pull request #478 from lanedirt/469-webassembly-required-error-not-visible-in-client-app
Add E2E test for browser with WASM disabled
2024-12-16 12:19:00 +01:00
dependabot[bot]
2bbad8c75c Bump NUnit from 4.2.2 to 4.3.0
Bumps [NUnit](https://github.com/nunit/nunit) from 4.2.2 to 4.3.0.
- [Release notes](https://github.com/nunit/nunit/releases)
- [Changelog](https://github.com/nunit/nunit/blob/main/CHANGES.md)
- [Commits](https://github.com/nunit/nunit/compare/4.2.2...4.3.0)

---
updated-dependencies:
- dependency-name: NUnit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 11:24:59 +01:00
dependabot[bot]
f02b841eea Bump Serilog and Serilog.Settings.Configuration
Bumps [Serilog](https://github.com/serilog/serilog) and [Serilog.Settings.Configuration](https://github.com/serilog/serilog-settings-configuration). These dependencies needed to be updated together.

Updates `Serilog` from 4.2.0 to 4.2.0
- [Release notes](https://github.com/serilog/serilog/releases)
- [Commits](https://github.com/serilog/serilog/compare/v4.2.0...v4.2.0)

Updates `Serilog.Settings.Configuration` from 8.0.4 to 9.0.0
- [Release notes](https://github.com/serilog/serilog-settings-configuration/releases)
- [Changelog](https://github.com/serilog/serilog-settings-configuration/blob/dev/CHANGES.md)
- [Commits](https://github.com/serilog/serilog-settings-configuration/compare/v8.0.4...v9.0.0)

---
updated-dependencies:
- dependency-name: Serilog
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: Serilog.Settings.Configuration
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 11:24:36 +01:00
dependabot[bot]
f6fc5af8ac Bump MailKit from 4.8.0 to 4.9.0
Bumps [MailKit](https://github.com/jstedfast/MailKit) from 4.8.0 to 4.9.0.
- [Changelog](https://github.com/jstedfast/MailKit/blob/master/ReleaseNotes.md)
- [Commits](https://github.com/jstedfast/MailKit/compare/4.8.0...4.9.0)

---
updated-dependencies:
- dependency-name: MailKit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 11:24:30 +01:00
dependabot[bot]
1d1155bf0e Bump MimeKit from 4.8.0 to 4.9.0
Bumps [MimeKit](https://github.com/jstedfast/MimeKit) from 4.8.0 to 4.9.0.
- [Changelog](https://github.com/jstedfast/MimeKit/blob/master/ReleaseNotes.md)
- [Commits](https://github.com/jstedfast/MimeKit/compare/4.8.0...4.9.0)

---
updated-dependencies:
- dependency-name: MimeKit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 11:24:24 +01:00
Leendert de Borst
2632211af6 Merge pull request #470 from lanedirt/469-webassembly-required-error-not-visible-in-client-app
Show error if client does not support WebAssembly
2024-12-16 10:34:20 +01:00
Leendert de Borst
05cca6998e Merge pull request #468 from lanedirt/467-task-runner-jobs-do-not-always-run-at-configured-time
Add task runner job table for tracking task runner historic runs
2024-12-16 10:18:13 +01:00
Leendert de Borst
c4a8a20a62 Add E2E test for browser with WASM disabled (#469) 2024-12-15 17:05:31 +01:00
Leendert de Borst
f2c6af9ccb Update install.sh URL comment (#469) 2024-12-15 16:43:48 +01:00
Leendert de Borst
e94201acda Tweak logo on mobile view auth area (#469) 2024-12-15 16:28:57 +01:00
Leendert de Borst
9e03473208 Show error message when client does not support WebAssembly (#469) 2024-12-15 16:28:41 +01:00
Leendert de Borst
0c5b2fb1da Add task runner job table and manual start button (#467) 2024-12-15 15:59:51 +01:00
Leendert de Borst
a5c4a7618d Update AliasServerDbContext.cs so pragma settings are applied correctly (#467) 2024-12-15 14:53:33 +01:00
Leendert de Borst
70220cecbb Merge pull request #466 from lanedirt/465-prepare-093-release
Update version to 0.9.3
2024-12-13 13:09:33 +01:00
Leendert de Borst
c63faa352f Update version to 0.9.3 (#465) 2024-12-13 13:09:14 +01:00
Leendert de Borst
7e261a05c9 Merge pull request #464 from lanedirt/463-bump-spamokpasswordgenerator-library-to-110
Bump SpamOK.PasswordGenerator version to 1.1.0
2024-12-13 13:01:45 +01:00
Leendert de Borst
545ec5576e Bump SpamOK.PasswordGenerator version to 1.1.0 (#463) 2024-12-13 12:45:05 +01:00
dependabot[bot]
73dcbe5860 Bump the npm_and_yarn group across 2 directories with 1 update
Bumps the npm_and_yarn group with 1 update in the /src/AliasVault.Admin directory: [nanoid](https://github.com/ai/nanoid).
Bumps the npm_and_yarn group with 1 update in the /src/AliasVault.Client directory: [nanoid](https://github.com/ai/nanoid).


Updates `nanoid` from 3.3.7 to 3.3.8
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8)

Updates `nanoid` from 3.3.7 to 3.3.8
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: nanoid
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-13 12:15:20 +01:00
Leendert de Borst
13917444b9 Merge pull request #461 from lanedirt/460-password-not-correct
Fix account registration username capitalization login bug
2024-12-13 12:15:08 +01:00
dependabot[bot]
119e13a9dd Bump Serilog from 4.1.0 to 4.2.0
Bumps [Serilog](https://github.com/serilog/serilog) from 4.1.0 to 4.2.0.
- [Release notes](https://github.com/serilog/serilog/releases)
- [Commits](https://github.com/serilog/serilog/compare/v4.1.0...v4.2.0)

---
updated-dependencies:
- dependency-name: Serilog
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-13 11:50:58 +01:00
dependabot[bot]
7d656e9a9a Bump Microsoft.IdentityModel.JsonWebTokens and Microsoft.IdentityModel.Tokens
Bumps [Microsoft.IdentityModel.JsonWebTokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) and [Microsoft.IdentityModel.Tokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet). These dependencies needed to be updated together.

Updates `Microsoft.IdentityModel.JsonWebTokens` from 8.2.1 to 8.3.0
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.2.1...8.3.0)

Updates `Microsoft.IdentityModel.Tokens` from 8.2.1 to 8.3.0
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.2.1...8.3.0)

---
updated-dependencies:
- dependency-name: Microsoft.IdentityModel.JsonWebTokens
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: Microsoft.IdentityModel.Tokens
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-13 11:50:50 +01:00
Leendert de Borst
8bd05b5c2e Fix account registration username capitalization login bug (#460) 2024-12-13 11:50:18 +01:00
Leendert de Borst
1e65f14323 Update README.md 2024-12-11 23:30:41 +01:00
Leendert de Borst
2c7543889d Update README.md 2024-12-11 18:24:10 +01:00
Leendert de Borst
63c5483208 Merge pull request #455 from lanedirt/454-update-default-server-settings
Update default server settings
2024-12-05 10:07:07 +01:00
Leendert de Borst
2586d61651 Merge pull request #457 from lanedirt/456-add-task-runner-to-installsh-pull-list
Update install.sh to include task runner to image pull list
2024-12-05 10:07:00 +01:00
Leendert de Borst
c7a32cf0e9 Update install.sh (#456) 2024-12-04 21:32:13 +01:00
Leendert de Borst
46cc6527aa Update default server settings (#454) 2024-12-04 19:17:56 +01:00
Leendert de Borst
ef291bffc1 Merge pull request #452 from lanedirt/451-task-runner-cannot-access-database
Task runner cannot access database
2024-12-04 18:55:42 +01:00
Leendert de Borst
94f6199e27 Update AppInfo.cs (#451) 2024-12-04 18:55:05 +01:00
Leendert de Borst
5ababf3bf3 Update docker-compose.yml (#451) 2024-12-04 18:54:23 +01:00
Leendert de Borst
b47e735e8f Merge pull request #450 from lanedirt/449-publish-new-task-runner-image-to-ghcrio
Publish task runner docker container image
2024-12-04 18:39:34 +01:00
Leendert de Borst
de17303085 Publish task runner docker container image (#449) 2024-12-04 18:39:15 +01:00
Leendert de Borst
635136d257 Merge pull request #448 from lanedirt/447-prepare-090-release
Update version to 0.9.0
2024-12-04 18:31:13 +01:00
Leendert de Borst
832e340b1b Update version to 0.9.0 (#447) 2024-12-04 18:30:48 +01:00
Leendert de Borst
4e0b6b5adf Merge pull request #444 from lanedirt/221-add-aliasvaulttaskservice-for-running-scheduled-background-tasks-such-as-log-cleanups
Add TaskRunner for running scheduled background tasks such as log cleanups
2024-12-04 18:28:26 +01:00
Leendert de Borst
18be105350 Merge pull request #446 from lanedirt/442-update-docker-composeyml-when-running-installsh-update
Always download latest docker compose files on install or update
2024-12-04 18:28:16 +01:00
Leendert de Borst
9bea01fbf8 Update install.sh to always download latest docker compose files on install (#442) 2024-12-04 18:18:28 +01:00
Leendert de Borst
a33fd08cb4 Add TaskRunner to docker compose stack (#221) 2024-12-04 17:57:46 +01:00
Leendert de Borst
25f5660f81 Refactor (#221) 2024-12-04 17:57:46 +01:00
Leendert de Borst
0923936f7c Add TaskRunner maintenance time tests (#221) 2024-12-04 17:57:46 +01:00
Leendert de Borst
3c0905d0b0 Add integration tests for TaskRunner (#221) 2024-12-04 17:57:46 +01:00
Leendert de Borst
97fd3beeaa Add E2E test for server settings admin page (#221) 2024-12-04 17:57:45 +01:00
Leendert de Borst
3195ad86ce Add email cleanup tasks (#221) 2024-12-04 17:57:45 +01:00
Leendert de Borst
d147639a83 Add task runner implementation (#221) 2024-12-04 17:57:45 +01:00
Leendert de Borst
9e0716d32e Add using to db connections (#221) 2024-12-04 17:57:45 +01:00
Leendert de Borst
3a05b1e5c3 Refactor admin to use shared server project (#221) 2024-12-04 17:57:45 +01:00
Leendert de Borst
9628861186 Add AliasVault.Shared.Server project (#221) 2024-12-04 17:57:45 +01:00
Leendert de Borst
2b541dc28d Make TaskRunner compile (#221) 2024-12-04 17:57:45 +01:00
Leendert de Borst
e655dcedb0 Refactor service control in admin, add TaskRunner (#221) 2024-12-04 17:57:45 +01:00
Leendert de Borst
9b8bbebb44 Add server settings page to admin (#221) 2024-12-04 17:57:45 +01:00
Leendert de Borst
bbc99ebf16 Add AliasVault.TaskRunner boilerplate (#221) 2024-12-04 17:57:45 +01:00
Leendert de Borst
23690f4e9b Merge pull request #445 from lanedirt/441-move-custom-port-config-from-docker-composeyml-to-env
Move custom port settings to .env file
2024-12-04 17:57:04 +01:00
Leendert de Borst
6286034a9d Move custom ports to .env (#441) 2024-12-04 17:56:44 +01:00
Leendert de Borst
2ea684061e Merge pull request #440 from lanedirt/349-add-statistics-to-admin
Add statistics to admin
2024-12-04 10:53:23 +01:00
Leendert de Borst
973abc8917 Update sqlite connection string to include WAL mode directly (#349) 2024-12-04 10:00:49 +01:00
Leendert de Borst
65304b0f84 Refactor admin dashboard into separate components (#349) 2024-12-03 22:56:22 +01:00
Leendert de Borst
ca4dd89e89 Update AdminPlaywrightTest.cs (#349) 2024-12-02 17:10:15 +01:00
Leendert de Borst
fccf10dc82 Tweak UI of admin account settings (#349) 2024-12-02 17:08:09 +01:00
Leendert de Borst
b845245728 Show amount of emails received in user email claim page (#349) 2024-12-02 16:59:21 +01:00
Leendert de Borst
e46357d603 Add statistics to admin home dashboard page (#349) 2024-12-02 16:54:07 +01:00
Leendert de Borst
6568ed8059 Merge pull request #439 from lanedirt/438-prepare-083-release
Prepare 0.8.3 release
2024-12-02 14:43:15 +01:00
Leendert de Borst
236718c76e Update version to 0.8.3 (#438) 2024-12-02 14:42:54 +01:00
Leendert de Borst
17ef816fa3 Update install docs (#438) 2024-12-02 14:42:45 +01:00
Leendert de Borst
db33a0a1da Merge pull request #437 from lanedirt/436-make-miscrelease-articles-show-up-in-docs
Add gitignore for /docs to include misc/release articles
2024-12-02 14:36:39 +01:00
Leendert de Borst
7a97bbf716 Add gitignore for /docs to include misc/release articles (#436) 2024-12-02 14:36:20 +01:00
Leendert de Borst
0c4ab8c1b6 Merge pull request #435 from lanedirt/434-update-installsh-to-pull-correct-docker-image-version
Update install.sh to pull correct docker image version
2024-12-02 14:32:08 +01:00
Leendert de Borst
6ee19d57bf Merge pull request #433 from lanedirt/dependabot/nuget/main/Swashbuckle.AspNetCore-7.1.0
Bump Swashbuckle.AspNetCore from 7.0.0 to 7.1.0
2024-12-02 13:51:51 +01:00
Leendert de Borst
dcb92c8dad Add update-installer command to install.sh for CI/CD (#434) 2024-12-02 13:41:09 +01:00
Leendert de Borst
968d3cfcf1 Update install.sh to write version to docker-compose to ensure we pull and run the right containers (#434) 2024-12-02 13:32:19 +01:00
Leendert de Borst
8e9c12f6e7 Wait 15 seconds for containers to start during test (#434) 2024-12-02 13:30:15 +01:00
dependabot[bot]
3c8f32e67a Bump Swashbuckle.AspNetCore from 7.0.0 to 7.1.0
Bumps [Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) from 7.0.0 to 7.1.0.
- [Release notes](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/releases)
- [Commits](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/compare/v7.0.0...v7.1.0)

---
updated-dependencies:
- dependency-name: Swashbuckle.AspNetCore
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-02 10:52:44 +00:00
Leendert de Borst
86d7ee3e9b Merge pull request #431 from lanedirt/430-prepare-082-hotfix-release
Update version to 0.8.2
2024-11-27 16:31:44 +01:00
Leendert de Borst
a39ed8c0a7 Update version to 0.8.2 (#430) 2024-11-27 16:31:28 +01:00
Leendert de Borst
e772e722b5 Merge pull request #429 from lanedirt/428-update-email-installation-documentation
Update email installation documentation
2024-11-27 13:22:11 +01:00
Leendert de Borst
b6bf431062 Only test favicon extraction for known stable website (#428) 2024-11-27 12:55:28 +01:00
Leendert de Borst
aa41cceff3 Update email installation documentation (#428) 2024-11-27 12:51:25 +01:00
Leendert de Borst
1baea180aa Merge pull request #427 from lanedirt/426-client-logs-out-unexpectedly-when-kept-open-in-background-tab 2024-11-26 20:32:12 +01:00
Leendert de Borst
0d8143c62e Fix refresh token expired check (#426) 2024-11-26 19:08:41 +01:00
Leendert de Borst
4ae84052e8 Refactor RecentEmails.razor (#426) 2024-11-26 19:03:03 +01:00
Leendert de Borst
c73c41ca06 Refactor RecentEmails component to only load emails when app is visible (#426) 2024-11-26 18:33:35 +01:00
Leendert de Borst
5b58418e57 Fix refresh token grace period check (#426) 2024-11-26 18:24:33 +01:00
Leendert de Borst
7c7f7549c5 Merge pull request #423 from lanedirt/422-add-email-server-documentation
Add email server documentation
2024-11-25 23:26:26 +01:00
Leendert de Borst
38203fd767 Merge pull request #425 from lanedirt/424-make-installsh-be-able-to-update-itself
Update install.sh with self-update support
2024-11-25 23:18:42 +01:00
Leendert de Borst
a7b8484a84 Set email server to disabled by default (#422) 2024-11-25 23:18:27 +01:00
Leendert de Borst
a091a94737 Update docker-compose-build.yml for better resilience (#422) 2024-11-25 23:07:43 +01:00
Leendert de Borst
2c299a82b8 Update install.sh with self-update support (#424) 2024-11-25 23:03:13 +01:00
Leendert de Borst
5ee710750e Merge pull request #421 from lanedirt/420-limit-max-username-length
Add max username length restriction of 40 chars
2024-11-25 22:49:58 +01:00
Leendert de Borst
ed5ea31ca8 Add email server docs (#422) 2024-11-25 22:49:38 +01:00
Leendert de Borst
ffdb427184 Add email server setup command (#422) 2024-11-25 22:49:24 +01:00
Leendert de Borst
4cef3efa1f Refactor all tests to use shorter username (#420) 2024-11-25 21:40:15 +01:00
Leendert de Borst
a5c8908c6b Add max username length restriction of 40 chars (#420) 2024-11-25 19:40:27 +01:00
Leendert de Borst
88c10b5a9c Merge pull request #419 from lanedirt/418-improve-docker-compose-build-test-workflow
Update workflow test to show error if HTTP check fails
2024-11-25 15:50:59 +01:00
Leendert de Borst
48d3d26be5 Merge pull request #416 from lanedirt/414-grep-env-no-such-file-or-directory-on-clean-install
Fix bug in install.sh
2024-11-25 15:41:43 +01:00
Leendert de Borst
5caa583240 Update workflow test to show error if HTTP check fails (#418) 2024-11-25 15:41:21 +01:00
Leendert de Borst
79f4749869 Add extra .env exist check to install.sh (#414) 2024-11-25 15:35:42 +01:00
Leendert de Borst
4de42e4a33 Merge pull request #417 from lanedirt/415-update-version-number-to-081
Prepare 0.8.1 version
2024-11-25 15:31:46 +01:00
Leendert de Borst
af9fba39f3 Update AppInfo.cs (#415) 2024-11-25 15:30:59 +01:00
Leendert de Borst
91b27c1bec Update install.sh (#414) 2024-11-25 15:29:22 +01:00
Leendert de Borst
0fb5327f04 Merge pull request #413 from lanedirt/412-add-update-option-to-install-script
Add update option to install script
2024-11-25 14:41:17 +01:00
Leendert de Borst
57f6b0961c Update docs (#412) 2024-11-25 14:40:38 +01:00
Leendert de Borst
c1d70fe504 Add support for installing specific version (#412) 2024-11-25 14:39:04 +01:00
Leendert de Borst
4c379802fc Update docker compose build workflow (#412) 2024-11-25 14:38:45 +01:00
dependabot[bot]
6a9a98b7bf Bump Microsoft.IdentityModel.JsonWebTokens and Microsoft.IdentityModel.Tokens
Bumps [Microsoft.IdentityModel.JsonWebTokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) and [Microsoft.IdentityModel.Tokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet). These dependencies needed to be updated together.

Updates `Microsoft.IdentityModel.JsonWebTokens` from 8.2.0 to 8.2.1
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.2.0...8.2.1)

Updates `Microsoft.IdentityModel.Tokens` from 8.2.1 to 8.2.1
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.2.1...8.2.1)

---
updated-dependencies:
- dependency-name: Microsoft.IdentityModel.JsonWebTokens
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: Microsoft.IdentityModel.Tokens
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-25 14:27:22 +01:00
dependabot[bot]
d2705d0b92 Bump Microsoft.NET.Test.Sdk from 17.11.1 to 17.12.0
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.11.1 to 17.12.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.11.1...v17.12.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-25 14:27:09 +01:00
dependabot[bot]
fcd0397184 Bump Microsoft.Playwright.NUnit and NUnit
Bumps [Microsoft.Playwright.NUnit](https://github.com/microsoft/playwright-dotnet) and [NUnit](https://github.com/nunit/nunit). These dependencies needed to be updated together.

Updates `Microsoft.Playwright.NUnit` from 1.48.0 to 1.49.0
- [Release notes](https://github.com/microsoft/playwright-dotnet/releases)
- [Commits](https://github.com/microsoft/playwright-dotnet/compare/v1.48.0...v1.49.0)

Updates `NUnit` from 4.2.2 to 3.13.2
- [Release notes](https://github.com/nunit/nunit/releases)
- [Changelog](https://github.com/nunit/nunit/blob/main/CHANGES.md)
- [Commits](https://github.com/nunit/nunit/compare/4.2.2...v3.13.2)

---
updated-dependencies:
- dependency-name: Microsoft.Playwright.NUnit
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: NUnit
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-25 14:27:02 +01:00
Leendert de Borst
a8e35d5e1d Update install script with explicit update option (#412) 2024-11-25 14:26:25 +01:00
Leendert de Borst
cf459f748f Merge pull request #411 from lanedirt/407-reduce-unnecessary-warnings-in-logs
Fix various warnings in logs
2024-11-25 13:48:33 +01:00
Leendert de Borst
65a2bebd51 Update SQLite connection config (#407) 2024-11-25 13:34:28 +01:00
Leendert de Borst
22e29c6cf5 Move DataProtection to top of program.cs to prevent decryption errors (#407) 2024-11-25 13:34:13 +01:00
Leendert de Borst
6fd4f7d607 Log Smtp messages to information instead of warning (#407) 2024-11-25 11:30:10 +01:00
Leendert de Borst
dab4762e94 Always force recreate docker containers after install (#407) 2024-11-25 11:29:44 +01:00
Leendert de Borst
bb3d38f50e Consolidate docker build/publish (#407) 2024-11-25 11:29:28 +01:00
Leendert de Borst
c7f6375fbb Return bad request if no refresh token is provided (#407) 2024-11-22 23:01:36 +01:00
Leendert de Borst
197248a6ea Merge pull request #406 from lanedirt/323-customize-error-when-unhandled-error-occurs-in-webapp
Style blazor wasm exception message
2024-11-22 12:15:35 +01:00
Leendert de Borst
5de9a0b8d8 Style blazor wasm exception message (#323) 2024-11-22 10:48:43 +01:00
Leendert de Borst
8a99dbf705 Merge pull request #394 from lanedirt/359-back-button-should-not-be-visible-at-terms-and-conditions-step-during-user-create
Do not show back button on first step of user creation
2024-11-22 10:03:45 +01:00
Leendert de Borst
b6b3b88b1d Merge pull request #395 from lanedirt/358-do-not-show-expired-access-tokens-on-security-page-on-client
Only show non-expired refresh tokens on client
2024-11-22 10:03:39 +01:00
Leendert de Borst
0dc699ea54 Merge pull request #396 from lanedirt/371-tweak-client-body-and-footer-z-index
Fix body and footer overlap issue
2024-11-22 10:03:33 +01:00
Leendert de Borst
a228ccb904 Merge pull request #397 from lanedirt/363-client-logout-action-registers-as-failed-in-auth-log
Fix refresh token revoke bug
2024-11-22 10:03:28 +01:00
Leendert de Borst
398e4016dc Merge pull request #399 from lanedirt/398-only-use-installsh-for-testing-pull-deploy-in-github-actions
Download fresh install.sh to test pull deploy in GitHub Actions
2024-11-22 10:03:22 +01:00
Leendert de Borst
fd1e0c5d15 Merge pull request #404 from lanedirt/402-add-github-pages-documentation-website
Update README with new docs website
2024-11-22 01:21:27 +01:00
Leendert de Borst
e6ea0c51c8 Update README with new docs website (#402) 2024-11-22 01:21:11 +01:00
Leendert de Borst
38eef67207 Merge pull request #403 from lanedirt/402-add-github-pages-documentation-website
Update documentation
2024-11-22 00:41:03 +01:00
Leendert de Borst
7ce253e93d Update docs (#402) 2024-11-22 00:40:41 +01:00
Leendert de Borst
c519b80159 Merge pull request #401 from lanedirt/400-tweak-docker-compose-setup-to-not-use-static-network-name-to-prevent-conflicts
Remove static docker network name to prevent conflicts as its not needed
2024-11-21 22:37:16 +01:00
Leendert de Borst
e128bbf091 Remove static docker network name to prevent conflicts as its not needed (#400) 2024-11-21 22:36:15 +01:00
Leendert de Borst
04315b38ba Create CNAME 2024-11-21 20:41:12 +01:00
Leendert de Borst
0ee1b5e992 Download fresh install.sh to test pull deploy instead of checking out full repo (#398) 2024-11-21 19:53:04 +01:00
Leendert de Borst
b4b2dc3fe7 Fix refresh token revoke bug (#363) 2024-11-21 19:26:16 +01:00
Leendert de Borst
7ac9cdc9e7 Tweak body so it fully overlaps over absolutely positioned footer while scrolling (#371) 2024-11-21 18:14:14 +01:00
Leendert de Borst
9ba8bb183a Only show non-expired refresh tokens on client (#358) 2024-11-21 18:12:42 +01:00
Leendert de Borst
7ef8a12fb2 Do not show back button on first step of user creation (#359) 2024-11-21 17:33:19 +01:00
Leendert de Borst
ea7aba4ff4 Merge pull request #393 from lanedirt/391-download-letsencrypt-docker-compose-yml-file-for-quick-install
Add static docker compose network name
2024-11-20 17:52:37 +01:00
Leendert de Borst
aac9694d5d Add static network name (#391) 2024-11-20 17:52:11 +01:00
Leendert de Borst
06d7666265 Merge pull request #392 from lanedirt/391-download-letsencrypt-docker-compose-yml-file-for-quick-install
Update install.sh
2024-11-20 17:23:56 +01:00
Leendert de Borst
ca17759727 Update install.sh (#391) 2024-11-20 17:23:36 +01:00
Leendert de Borst
48b96b4151 Merge pull request #390 from lanedirt/389-prepare-070-release
Update documentation for 0.7.0 release
2024-11-20 17:01:20 +01:00
Leendert de Borst
e9064643a6 Add busy timeout to SQLite connections to prevent errors (#389) 2024-11-20 16:52:20 +01:00
Leendert de Borst
667592411f Update for 0.7.0 release (#389) 2024-11-20 16:51:48 +01:00
Leendert de Borst
dfdf4981cb Add LetsEncrypt ssl certificate generation to docker setup (#388)
* Add LetsEncrypt scaffolding to docker compose setup (#367)

* Update install.sh (#367)

* Add certificate request logic (#367)

* Update domain validation regex (#367)

* Update install.sh (#367)

* Update install.sh (#367)

* Update nginx.conf for LetsEncrypt validation (#367)

* Update nginx.conf (#367)

* Add certbot volume mapping to nginx (#367)

* Update nginx conf to template to use env vars (#367)

* Update nginx certbot root (#367)

* Update install.sh (#367)

* Update nginx ssl letsencrypt paths (#367)

* Update install.sh (#367)

* Use conditional nginx.conf include instead of vars (#367)

* Update install.sh so it doesn't restart docker stack but expects it to be running already (#367)

* Update permissions (#367)

* Update install.sh (#367)

* Refactor and cleanup (#367)
2024-11-20 16:25:35 +01:00
Leendert de Borst
0f377bdec6 Merge pull request #384 from lanedirt/383-add-try-catch-around-favicon-extractor-to-prevent-hostname-could-not-be-parsed-exceptions
Log failed favicon extraction as information instead of warning
2024-11-20 10:13:30 +01:00
Leendert de Borst
ba17474e62 Merge pull request #385 from lanedirt/370-from-is-always-empty-in-email-popup-in-client
Fix email from value which was empty
2024-11-20 10:13:22 +01:00
Leendert de Borst
c09ad99739 Merge pull request #387 from lanedirt/386-admin-menu-absolute-urls-do-not-work-when-ran-from-subdirectory
Update absolute urls to relative URLs in admin
2024-11-20 10:13:16 +01:00
Leendert de Borst
799efe1772 Update absolute urls to relative URLs in admin (#386) 2024-11-19 21:51:37 +01:00
Leendert de Borst
1d79400df5 Fix email from value which didn't show (#370) 2024-11-19 21:42:50 +01:00
Leendert de Borst
cc4a2e087f Update FaviconController to log failed favicon extraction as information instead of warning (#383) 2024-11-19 21:30:57 +01:00
Leendert de Borst
64a76f3b9f Merge pull request #381 from lanedirt/372-installsh-reset-password-throws-sed-notice-error
Fix bug in reset-password regex check
2024-11-18 20:28:28 +01:00
Leendert de Borst
7c1aaab291 Fix bug in reset-password regex check (#372) 2024-11-18 20:21:55 +01:00
Leendert de Borst
63556d163a Merge pull request #380 from lanedirt/374-publish-docker-images-on-release
Add -y flag to install.sh for uninstall action
2024-11-18 20:13:13 +01:00
Leendert de Borst
c49c0e4ad5 Update install.sh (#374) 2024-11-18 19:51:05 +01:00
Leendert de Borst
3f2121f272 Merge pull request #379 from lanedirt/374-publish-docker-images-on-release
Publish docker images on release
2024-11-18 19:42:55 +01:00
Leendert de Borst
ebdcf778be Update README.md (#374) 2024-11-18 19:00:10 +01:00
Leendert de Borst
fb669df9cf Update docs (#374) 2024-11-18 17:18:28 +01:00
Leendert de Borst
cedf7d0733 Update README.md (#374) 2024-11-18 17:13:17 +01:00
Leendert de Borst
00db83f478 Update github actions to use new install.sh (#374) 2024-11-18 16:39:09 +01:00
Leendert de Borst
03b7f92a44 Fix admin absolute redirect issues (#374) 2024-11-18 16:32:20 +01:00
Leendert de Borst
d542a4273d Fix DataProtection issues (#374) 2024-11-18 16:32:06 +01:00
Leendert de Borst
dcb27ca543 Update install.sh to generate/download external dependencies (#374) 2024-11-18 16:31:11 +01:00
Leendert de Borst
78635b8ba1 Combine all CLI actions to a single file (#374) 2024-11-18 13:06:10 +01:00
Leendert de Borst
e18d31ee9b Fix 404 dark mode text (#374) 2024-11-18 12:56:31 +01:00
Leendert de Borst
0db5fb64a8 Run install and build in verbose mode in workflows (#374) 2024-11-18 11:33:41 +01:00
Leendert de Borst
e36d28eb99 Update README (#374) 2024-11-18 11:33:18 +01:00
Leendert de Borst
dd331f75c9 Fix regex (#374) 2024-11-18 11:15:10 +01:00
dependabot[bot]
aa11697ee2 Bump NUnit.Analyzers from 4.3.0 to 4.4.0
Bumps [NUnit.Analyzers](https://github.com/nunit/nunit.analyzers) from 4.3.0 to 4.4.0.
- [Release notes](https://github.com/nunit/nunit.analyzers/releases)
- [Changelog](https://github.com/nunit/nunit.analyzers/blob/master/CHANGES.md)
- [Commits](https://github.com/nunit/nunit.analyzers/compare/4.3.0...4.4.0)

---
updated-dependencies:
- dependency-name: NUnit.Analyzers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-18 11:05:37 +01:00
dependabot[bot]
fdd698dd0a Bump Microsoft.IdentityModel.Tokens from 8.2.0 to 8.2.1
Bumps [Microsoft.IdentityModel.Tokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.2.0...8.2.1)

---
updated-dependencies:
- dependency-name: Microsoft.IdentityModel.Tokens
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-18 11:05:29 +01:00
Leendert de Borst
c8df588401 Fix admin password check (#374) 2024-11-18 11:05:07 +01:00
dependabot[bot]
a8373338c2 Bump the npm_and_yarn group across 2 directories with 1 update
Bumps the npm_and_yarn group with 1 update in the /src/AliasVault.Admin directory: [cross-spawn](https://github.com/moxystudio/node-cross-spawn).
Bumps the npm_and_yarn group with 1 update in the /src/AliasVault.Client directory: [cross-spawn](https://github.com/moxystudio/node-cross-spawn).


Updates `cross-spawn` from 7.0.3 to 7.0.5
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.5)

Updates `cross-spawn` from 7.0.3 to 7.0.5
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.5)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: cross-spawn
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-18 10:47:17 +01:00
Leendert de Borst
15abd1f51b Update workflows (#374) 2024-11-18 10:46:22 +01:00
Leendert de Borst
71407cc86d Publish InstallCli image used for resetting admin password (#374) 2024-11-18 10:46:00 +01:00
Leendert de Borst
85a3fed127 Create docker-compose-pull.yml (#374) 2024-11-18 10:44:05 +01:00
Leendert de Borst
6b8f0d6cdf Add separate install/build.sh files (#374) 2024-11-18 10:43:50 +01:00
Leendert de Borst
43441831d4 Convert repository name to lowercase (#374) 2024-11-18 09:41:39 +01:00
Leendert de Borst
319cff8fe1 Merge pull request #375 from lanedirt/374-publish-docker-images-on-release
Publish docker images on release
2024-11-18 09:38:47 +01:00
Leendert de Borst
5904204465 Add docker image publish workflow (#374) 2024-11-18 09:33:52 +01:00
Leendert de Borst
6c8cc92a67 Merge pull request #365 from lanedirt/364-update-docker-setup-to-run-https-by-default
Update docker setup to run https by default
2024-11-15 18:56:34 +01:00
Leendert de Borst
693860acef Update Dockerfile (#364) 2024-11-15 18:48:50 +01:00
Leendert de Borst
f7626ec15b Update ApiLoggingTests to set correct base url (#364) 2024-11-15 18:40:09 +01:00
Leendert de Borst
03c6bbc81f Update README.md (#364) 2024-11-15 17:27:57 +01:00
Leendert de Borst
bbe7ef1b2b Update install.sh (#364) 2024-11-15 17:25:59 +01:00
Leendert de Borst
027b95da15 Fix dataprotection certificate errors (#364) 2024-11-15 17:20:57 +01:00
Leendert de Borst
e9c33a808f Make apps work when run in local debug mode (#364) 2024-11-15 16:58:20 +01:00
Leendert de Borst
2545e1204f Update API and admin apps to be able to run under subdirectories (#364) 2024-11-15 16:58:20 +01:00
Leendert de Borst
970d334b59 Make all apps available through single container and HTTPS port (#364) 2024-11-15 16:58:20 +01:00
Leendert de Borst
50a18dc461 Add -k flag to ignore self-signed certs, refactor (#364) 2024-11-15 16:58:20 +01:00
Leendert de Borst
0dcc77eb0d Update docker-compose-build.yml (#364) 2024-11-15 16:58:20 +01:00
Leendert de Borst
cd84592be1 Fix AliasVault.InstallCli dockerfile names (#364) 2024-11-15 16:58:20 +01:00
Leendert de Borst
df6de32a4a Update docker setup to run under HTTPS by default (#364) 2024-11-15 16:58:20 +01:00
Leendert de Borst
3d24772caa Merge pull request #366 from lanedirt/362-tweak-dataprotection-certificate-tweaks-so-its-not-dependent-on-local-machine-keystore
Change DataProtection certificate generation so its not dependent on local machine keystore
2024-11-15 16:56:00 +01:00
Leendert de Borst
1a106e59fc Update CertificateGenerator.cs (#362) 2024-11-13 21:20:02 +01:00
Leendert de Borst
290460c095 Merge pull request #361 from lanedirt/360-upgrade-all-projects-to-net-9
Upgrade all projects to .NET 9
2024-11-13 17:55:55 +01:00
Leendert de Borst
17802dc216 Fix dataprotection, refactor (#360) 2024-11-13 17:24:03 +01:00
Leendert de Borst
0de52a396a Add .NET 9 to sonarcloud workflow explicitly (#360) 2024-11-13 17:06:15 +01:00
Leendert de Borst
64705e582d Update E2E github workflow to use new .NET 9 (#360) 2024-11-13 16:50:37 +01:00
Leendert de Borst
b09cdcec1e Fix E2E tests by switching to new KestrelTestServer (#360) 2024-11-13 16:44:44 +01:00
Leendert de Borst
87bb34f3ba Update dotnet version in github workflows (#360) 2024-11-13 14:27:50 +01:00
Leendert de Borst
5b53208a3e Update .gitignore to also ignore sqlite bak files (#360) 2024-11-13 14:25:57 +01:00
Leendert de Borst
7a687bba43 Update dockerfiles to use .NET9 (#360) 2024-11-13 14:16:16 +01:00
Leendert de Borst
aafac49bcb Disable DataProtection temporary (#360) 2024-11-13 12:48:11 +01:00
Leendert de Borst
201af7b88a Upgrade all projects to .NET 9 (#360) 2024-11-13 11:47:05 +01:00
383 changed files with 18735 additions and 2977 deletions

View File

@@ -22,4 +22,17 @@
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
README.md
# Exclude AliasVault data directories
database/
logs/
certificates/
# Exclude git directory
.git/
# Exclude development files
*.log
*.env
*.env.*

View File

@@ -1,7 +1,10 @@
API_URL=
HOSTNAME=
JWT_KEY=
DATA_PROTECTION_CERT_PASS=
ADMIN_PASSWORD_HASH=
ADMIN_PASSWORD_GENERATED=2024-01-01T00:00:00Z
PRIVATE_EMAIL_DOMAINS=
SMTP_TLS_ENABLED=false
LETSENCRYPT_ENABLED=false
POSTGRES_PASSWORD=
SUPPORT_EMAIL=

27
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,27 @@
---
name: Bug report
about: Report a bug or unexpected behavior.
title: "[BUG] "
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for AliasVault
title: '[Feature Request] '
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

21
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,21 @@
## Description
Please include a summary of the changes and the related issue(s).
- [ ] Bug fix
- [ ] Feature enhancement
- [ ] Documentation update
- [ ] Other (please describe):
## Related Issues
Link to any issues that this PR addresses:
Fixes #[issue-number]
## Checklist
- [ ] Code adheres to project standards and guidelines.
- [ ] Documentation has been updated where applicable.
## Additional Information
Add any additional context, screenshots, or explanations here.

View File

@@ -17,72 +17,87 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Create .env file with custom SMTP port as port 25 is not allowed in GitHub Actions
run: |
echo "SMTP_PORT=2525" > .env
- name: Set permissions and run install.sh
run: |
chmod +x install.sh
./install.sh
./install.sh build --verbose
- name: Set up Docker Compose
- name: Test if services are responding
uses: nick-fields/retry@v3
with:
timeout_minutes: 5
max_attempts: 5
command: |
sleep 15
# Array of endpoints to test
declare -A endpoints=(
["WASM"]="https://localhost:443"
["WebApi"]="https://localhost:443/api"
["Admin"]="https://localhost:443/admin/user/login"
)
failed=false
# Test HTTP endpoints
for name in "${!endpoints[@]}"; do
url="${endpoints[$name]}"
echo "Testing $name at $url"
# Store both response body and HTTP code
response=$(curl -k -s -w "\nHTTP_CODE=%{http_code}" "$url")
http_code=$(echo "$response" | grep "HTTP_CODE=" | cut -d= -f2)
body=$(echo "$response" | sed '$d') # Remove the last line (HTTP_CODE)
if [ "$http_code" -ne 200 ]; then
echo "❌ $name failed with HTTP $http_code at $url"
echo "Response body:"
echo "$body"
failed=true
else
echo "✅ $name responded with HTTP 200"
fi
done
# Test SMTP
echo "Testing SmtpService at localhost:2525"
if ! nc -zv localhost 2525 2>&1 | grep -q 'succeeded'; then
echo "❌ SmtpService failed to respond on port 2525"
failed=true
else
echo "✅ SmtpService responded successfully"
fi
# Exit with error if any service failed
if [ "$failed" = true ]; then
# Get container logs
echo "Container Logs admin:"
docker compose logs admin
echo "Container Logs api:"
docker compose logs api
echo "Container Logs client:"
docker compose logs client
echo "Container Logs smtp:"
docker compose logs smtp
echo "Container Logs reverse-proxy:"
docker compose logs reverse-proxy
# Restart containers for next test in case of failure
docker compose restart
exit 1
fi
- name: Test install.sh reset-password output
run: |
# Change the exposed host port of the SmtpService from 25 to 2525 because port 25 is not allowed in GitHub Actions
sed -i 's/25\:25/2525\:25/g' docker-compose.yml
docker compose -f docker-compose.yml up -d
- name: Wait for services to be up
run: |
# Wait for a few seconds
sleep 10
- name: Test if localhost:80 (WASM app) responds
uses: nick-fields/retry@v3
with:
timeout_minutes: 2
max_attempts: 3
command: |
http_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:80)
if [ "$http_code" -ne 200 ]; then
echo "Service did not respond with 200 OK. Check if client app is configured correctly."
exit 1
else
echo "Service responded with 200 OK"
fi
- name: Test if localhost:81 (WebApi) responds
uses: nick-fields/retry@v3
with:
timeout_minutes: 2
max_attempts: 3
command: |
http_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:81)
if [ "$http_code" -ne 200 ]; then
echo "Service did not respond with expected 200 OK. Check if WebApi is configured correctly."
exit 1
else
echo "Service responded with $http_code"
fi
- name: Test if localhost:2525 (SmtpService) responds
uses: nick-fields/retry@v3
with:
timeout_minutes: 2
max_attempts: 3
command: |
if ! nc -zv localhost 2525 2>&1 | grep -q 'succeeded'; then
echo "SmtpService did not respond on port 2525. Check if the SmtpService service is running."
exit 1
else
echo "SmtpService responded on port 2525"
fi
- name: Test if localhost:8080 (Admin) responds
uses: nick-fields/retry@v3
with:
timeout_minutes: 2
max_attempts: 3
command: |
http_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/user/login)
if [ "$http_code" -ne 200 ]; then
echo "Service did not respond with expected 200 OK. Check if admin app is configured correctly."
exit 1
else
echo "Service responded with $http_code"
fi
output=$(./install.sh reset-password)
if ! echo "$output" | grep -E '.*New admin password: [A-Za-z0-9+/=]{8,}.*'; then
echo "Password reset output format is incorrect"
echo "Expected: 'New admin password: <at least 8 base64 chars>'"
echo "Actual: $output"
exit 1
fi

View File

@@ -0,0 +1,133 @@
# This workflow will test if pulling the latest Docker Compose containers from the registry works.
name: Docker Compose Pull
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test-docker:
runs-on: ubuntu-latest
services:
docker:
image: docker:26.0.0
options: --privileged
steps:
- name: Get repository and branch information
id: repo-info
run: |
# Check if this is a PR from a fork
if [ "${{ github.event_name }}" = "pull_request" ] && [ "${{ github.event.pull_request.head.repo.fork }}" = "true" ]; then
# If PR is from a fork, use main branch from lanedirt/AliasVault
echo "REPO_FULL_NAME=lanedirt/AliasVault" >> $GITHUB_ENV
echo "BRANCH_NAME=main" >> $GITHUB_ENV
else
# Otherwise use the current repository and branch
echo "REPO_FULL_NAME=${GITHUB_REPOSITORY}" >> $GITHUB_ENV
echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_ENV
fi
- name: Download install script from current branch
run: |
INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/$REPO_FULL_NAME/$BRANCH_NAME/install.sh"
echo "Downloading install script from: $INSTALL_SCRIPT_URL"
curl -f -o install.sh "$INSTALL_SCRIPT_URL"
- name: Create .env file with custom SMTP port as port 25 is not allowed in GitHub Actions
run: |
echo "SMTP_PORT=2525" > .env
- name: Set permissions and run install.sh
id: install_script
continue-on-error: true
run: |
chmod +x install.sh
./install.sh install --verbose
- name: Check if failure was due to version mismatch
if: steps.install_script.outcome == 'failure'
run: |
if grep -q "Install script needs updating to match version" <<< "$(./install.sh install --verbose 2>&1)"; then
echo "Test skipped: Install script version is newer than latest release version. This is expected behavior if the install script is run on a branch that is ahead of the latest release."
exit 0
else
echo "Test failed due to an unexpected error"
exit 1
fi
- name: Set up Docker Compose
run: docker compose -f docker-compose.yml up -d
- name: Wait for services to be up
run: |
# Wait for a few seconds
sleep 10
- name: Test if localhost:443 (WASM app) responds
uses: nick-fields/retry@v3
with:
timeout_minutes: 2
max_attempts: 3
command: |
http_code=$(curl -k -s -o /dev/null -w "%{http_code}" https://localhost:443)
if [ "$http_code" -ne 200 ]; then
echo "Service did not respond with 200 OK. Check if client app and/or nginx is configured correctly."
exit 1
else
echo "Service responded with 200 OK"
fi
- name: Test if localhost:443/api (WebApi) responds
uses: nick-fields/retry@v3
with:
timeout_minutes: 2
max_attempts: 3
command: |
http_code=$(curl -k -s -o /dev/null -w "%{http_code}" https://localhost:443/api)
if [ "$http_code" -ne 200 ]; then
echo "Service did not respond with expected 200 OK. Check if WebApi and/or nginx is configured correctly."
exit 1
else
echo "Service responded with $http_code"
fi
- name: Test if localhost:443/admin (Admin) responds
uses: nick-fields/retry@v3
with:
timeout_minutes: 2
max_attempts: 3
command: |
http_code=$(curl -k -s -o /dev/null -w "%{http_code}" https://localhost:443/admin/user/login)
if [ "$http_code" -ne 200 ]; then
echo "Service did not respond with expected 200 OK. Check if admin app and/or nginx is configured correctly."
exit 1
else
echo "Service responded with $http_code"
fi
- name: Test if localhost:2525 (SmtpService) responds
uses: nick-fields/retry@v3
with:
timeout_minutes: 2
max_attempts: 3
command: |
if ! nc -zv localhost 2525 2>&1 | grep -q 'succeeded'; then
echo "SmtpService did not respond on port 2525. Check if the SmtpService service is running."
exit 1
else
echo "SmtpService responded on port 2525"
fi
- name: Test install.sh reset-password output
run: |
output=$(./install.sh reset-password)
if ! echo "$output" | grep -E '.*New admin password: [A-Za-z0-9+/=]{8,}.*'; then
echo "Password reset output format is incorrect. Expected format: 'New admin password: <at least 8 base64 chars>'"
echo "Actual output: $output"
exit 1
else
echo "Password reset output format is correct"
fi

View File

@@ -1,3 +1,4 @@
# This workflow will test if running the E2E Admin tests via Playwright CLI works.
name: .NET E2E Admin Tests (Playwright)
on:
@@ -16,7 +17,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.304
dotnet-version: 9.0.x
- name: Install dependencies
run: dotnet workload install wasm-tools
@@ -24,8 +25,11 @@ jobs:
- name: Build
run: dotnet build
- name: Start dev database
run: ./install.sh configure-dev-db start
- name: Ensure browsers are installed
run: pwsh src/Tests/AliasVault.E2ETests/bin/Debug/net8.0/playwright.ps1 install --with-deps
run: pwsh src/Tests/AliasVault.E2ETests/bin/Debug/net9.0/playwright.ps1 install --with-deps
- name: Run AdminTests with retry
uses: nick-fields/retry@v3

View File

@@ -1,3 +1,4 @@
# This workflow will test if running the E2E Client tests via Playwright CLI works.
name: .NET E2E Client Tests (Playwright with Sharding)
on:
@@ -20,7 +21,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.304
dotnet-version: 9.0.x
- name: Install dependencies
run: dotnet workload install wasm-tools
@@ -28,8 +29,11 @@ jobs:
- name: Build
run: dotnet build
- name: Start dev database
run: ./install.sh configure-dev-db start
- name: Ensure browsers are installed
run: pwsh src/Tests/AliasVault.E2ETests/bin/Debug/net8.0/playwright.ps1 install --with-deps
run: pwsh src/Tests/AliasVault.E2ETests/bin/Debug/net9.0/playwright.ps1 install --with-deps
- name: Run ClientTests with retry (Shard ${{ matrix.shard }})
uses: nick-fields/retry@v3

View File

@@ -1,3 +1,4 @@
# This workflow will test if running the E2E Misc tests via Playwright CLI works.
name: .NET E2E Misc Tests (Playwright)
on:
@@ -16,7 +17,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.304
dotnet-version: 9.0.x
- name: Install dependencies
run: dotnet workload install wasm-tools
@@ -24,8 +25,11 @@ jobs:
- name: Build
run: dotnet build
- name: Start dev database
run: ./install.sh configure-dev-db start
- name: Ensure browsers are installed
run: pwsh src/Tests/AliasVault.E2ETests/bin/Debug/net8.0/playwright.ps1 install --with-deps
run: pwsh src/Tests/AliasVault.E2ETests/bin/Debug/net9.0/playwright.ps1 install --with-deps
- name: Run remaining tests with retry
uses: nick-fields/retry@v3

View File

@@ -1,6 +1,4 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
# This workflow will test if running the integration tests works.
name: .NET Integration Tests
on:
@@ -19,7 +17,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.304
dotnet-version: 9.0.x
- name: Install dependencies
run: dotnet workload install wasm-tools
@@ -27,5 +25,8 @@ jobs:
- name: Build
run: dotnet build
- name: Start dev database
run: ./install.sh configure-dev-db start
- name: Run integration tests
run: dotnet test src/Tests/AliasVault.IntegrationTests --no-build --verbosity normal

View File

@@ -1,6 +1,4 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
# This workflow will test if running the unit tests works.
name: .NET Unit Tests
on:
@@ -18,7 +16,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.304
dotnet-version: 9.0.x
- name: Install dependencies
run: dotnet workload install wasm-tools

View File

@@ -0,0 +1,117 @@
# This workflow will publish new Docker images to the GitHub Container Registry when a new release is published.
name: Publish Docker Images
on:
release:
types: [published]
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Convert repository name to lowercase
run: |
echo "REPO_LOWER=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV}
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}
- name: Build and push Postgres image
uses: docker/build-push-action@v5
with:
context: .
file: src/Databases/AliasServerDb/Dockerfile
platforms: linux/amd64,linux/arm64/v8
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-postgres:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-postgres:${{ github.ref_name }}
- name: Build and push API image
uses: docker/build-push-action@v5
with:
context: .
file: src/AliasVault.Api/Dockerfile
platforms: linux/amd64,linux/arm64/v8
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-api:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-api:${{ github.ref_name }}
- name: Build and push Client image
uses: docker/build-push-action@v5
with:
context: .
file: src/AliasVault.Client/Dockerfile
platforms: linux/amd64,linux/arm64/v8
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-client:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-client:${{ github.ref_name }}
- name: Build and push Admin image
uses: docker/build-push-action@v5
with:
context: .
file: src/AliasVault.Admin/Dockerfile
platforms: linux/amd64,linux/arm64/v8
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-admin:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-admin:${{ github.ref_name }}
- name: Build and push Reverse Proxy image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
platforms: linux/amd64,linux/arm64/v8
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-reverse-proxy:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-reverse-proxy:${{ github.ref_name }}
- name: Build and push SMTP image
uses: docker/build-push-action@v5
with:
context: .
file: src/Services/AliasVault.SmtpService/Dockerfile
platforms: linux/amd64,linux/arm64/v8
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-smtp:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-smtp:${{ github.ref_name }}
- name: Build and push TaskRunner image
uses: docker/build-push-action@v5
with:
context: .
file: src/Services/AliasVault.TaskRunner/Dockerfile
platforms: linux/amd64,linux/arm64/v8
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-task-runner:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-task-runner:${{ github.ref_name }}
- name: Build and push InstallCli image
uses: docker/build-push-action@v5
with:
context: .
file: src/Utilities/AliasVault.InstallCli/Dockerfile
platforms: linux/amd64,linux/arm64/v8
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-installcli:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-installcli:${{ github.ref_name }}

View File

@@ -1,24 +1,38 @@
# This workflow will perform a SonarCloud code analysis on every push to the main branch or
# when a pull request is opened, synchronized, or reopened. The "pull_request_target" event is
# used to ensure that the analysis is done on the source branch of the pull request which has
# access to the SonarCloud token secret.
name: SonarCloud code analysis
on:
push:
branches:
- main
pull_request:
pull_request_target:
types: [opened, synchronize, reopened]
jobs:
build:
name: Build and analyze
runs-on: windows-latest
steps:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '9.0.x'
- name: Install WASM workload
run: dotnet workload install wasm-tools
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: 17
distribution: 'zulu' # Alternative distribution options are available.
distribution: 'zulu'
- uses: actions/checkout@v3
- name: Checkout code of PR branch
uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Cache SonarCloud packages
uses: actions/cache@v3
@@ -48,7 +62,11 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
shell: powershell
run: |
.\.sonar\scanner\dotnet-sonarscanner begin /k:"lanedirt_AliasVault" /o:"lanedirt" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" /d:sonar.coverage.exclusions="**Tests*.cs"
if ('${{ github.event_name }}' -eq 'pull_request_target') {
.\.sonar\scanner\dotnet-sonarscanner begin /k:"lanedirt_AliasVault" /o:"lanedirt" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.pullrequest.key=${{ github.event.pull_request.number }} /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" /d:sonar.coverage.exclusions="**Tests*.cs"
} else {
.\.sonar\scanner\dotnet-sonarscanner begin /k:"lanedirt_AliasVault" /o:"lanedirt" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" /d:sonar.coverage.exclusions="**Tests*.cs"
}
dotnet build
dotnet test -c Release /p:CollectCoverage=true /p:CoverletOutput=coverage /p:CoverletOutputFormat=opencover --filter 'FullyQualifiedName!~AliasVault.E2ETests'
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"

26
.gitignore vendored
View File

@@ -268,9 +268,14 @@ ServiceFabricBackup/
# SQLite files
*.sqlite
*.sqlite.*
*.sqlite-shm
*.sqlite-wal
# SQL files
*.sql
*.sql.gz
# Business Intelligence projects
*.rdl.data
*.bim.layout
@@ -389,6 +394,27 @@ src/Tests/AliasVault.E2ETests/appsettings.Development.json
# .env is generated by install.sh and therefore should be ignored
.env
# install.sh backup files are generated by install.sh self-update and therefore should be ignored
install.sh.backup
# Draw.io diagram temp files
*.drawio.*
# Certificates
certificates/**/*.crt
certificates/**/*.key
certificates/**/*.pfx
certificates/**/*.pem
certificates/letsencrypt/**
# Docs
docs/_site
docs/vendor
docs/.bundle
# Database files
database/postgres
database/postgres-dev
# Temp files
temp

128
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
contact@support.aliasvault.net.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -1,101 +1,14 @@
# Contributing
This document is a work-in-progress and will be expanded as time goes on. If you have any questions feel free to open a issue on GitHub.
# Contributing to the source code
We welcome contributions to AliasVault. Please read the guidelines on the official AliasVault docs website on how to get your local development environment setup and the general contribution guidelines:
Note: all instructions below are based on MacOS. If you are using a different operating system, you may need to adjust the commands accordingly.
https://docs.aliasvault.net/misc/dev/contributing.html
## Getting Started
In order to contribute to this project follow these instructions to setup your local environment:
> Tip: if the URL above is not available, the raw doc pages can also be found in the `docs` folder in this repository.
### 1. Clone the repository
## Contributing to the documentation
The docs are built using Jekyll and automatically deploy to GitHub Pages via GitHub Actions. You can build the docs locally by running `docker compose up` in in the `./docs` folder.
```bash
git clone https://github.com/lanedirt/AliasVault.git
cd AliasVault
```
### 2. Copy pre-commit hook script to .git/hooks directory
**Important**: All commits in this repo are required to contain a reference to a GitHub issue in the format of "your commit message (#123)" where "123" references the GitHub issue number.
The pre-commit hook script below will check the commit message before allowing the commit to proceed. If the commit message is invalid, the commit will be aborted.
```bash
# Copy the commit-msg hook script to the .git/hooks directory
cp .github/hooks/commit-msg .git/hooks/commit-msg
# Make the script executable
chmod +x .git/hooks/commit-msg
```
### 3. Install the latest version of .NET SDK 8
```bash
# Install .NET SDK 8
# On MacOS via brew:
brew install --cask dotnet-sdk
# On Windows via winget
winget install Microsoft.DotNet.SDK.8
```
### 4. Install dotnet CLI EF Tools
```bash
# Install dotnet EF tools globally
dotnet tool install --global dotnet-ef
# Include dotnet tools in your PATH
nano ~/.zshrc
# Add the following line to your .zshrc file
export PATH="$PATH:$HOME/.dotnet/tools"
# Start a new terminal and test that this command works:
dotnet ef
```
### 5. Run Tailwind CSS compiler while changing HTML files to update compiled CSS
```bash
npm run build:css
```
### 6. Install Playwright in order to locally run NUnit E2E (end-to-end) tests
```bash
# First install PowerShell for Mac (if you don't have it already)
brew install powershell/tap/powershell
# Install Playwright
dotnet tool install --global Microsoft.Playwright.CLI
# Run Playwright install script to download local browsers
# Note: make sure the E2E test project has been built at least once so the bin dir exists.
pwsh src/Tests/AliasVault.E2ETests/bin/Debug/net8.0/playwright.ps1 install
```
### 7. Create AliasVault.Client appsettings.Development.json
The WASM client app supports a development specific appsettings.json file. This appsettings file is optional but can override various options to make debugging easier.
The docs site is based on the open-source template called Just The Docs. Find more information about how this template works in the [official docs](https://just-the-docs.github.io/just-the-docs/).
1. Copy `wwwroot/appsettings.json` to `wwwroot/appsettings.Development.json`
Here is an example file with the various options explained:
```
{
"ApiUrl": "http://localhost:5092",
"PrivateEmailDomains": ["example.tld"],
"SupportEmail": "support@example.tld",
"UseDebugEncryptionKey": "true",
"CryptographyOverrideType" : "Argon2Id",
"CryptographyOverrideSettings" : "{\"DegreeOfParallelism\":1,\"MemorySize\":1024,\"Iterations\":1}"
}
```
- UseDebugEncryptionKey
- This setting will use a static encryption key so that if you login as a user you can refresh the page without needing to unlock the database again. This speeds up development when changing things in the WebApp WASM project. Note: the project needs to be run in "Development" mode for this setting to be used.
- CryptographyOverrideType
- This setting allows overriding the default encryption type (Argon2id) with a different encryption type. This is useful for testing different encryption types without having to change code.
- CryptographyOverrideSettings
- This setting allows overriding the default encryption settings (Argon2id) with different settings. This is useful for testing different encryption settings without having to change code. The default Argon2id settings
are defined in the project as `Utilities/Cryptography/Cryptography.Client/Defaults.cs`. These default settings
are focused on security but NOT performance. Normally for key derivation purposes the slower/heavier the algorithm
the better protection against attackers. For production builds this is what we want, however in case of automated testing or debugging extra performance can be gained by tweaking (lowering) these settings.
To make changes to the AliasVault documentation please make a PR that directly edits the `docs` markdown files in this repository.

15
Dockerfile Normal file
View File

@@ -0,0 +1,15 @@
FROM nginx:alpine
# Install OpenSSL
RUN apk add --no-cache openssl
# Copy configuration and entrypoint script
COPY nginx.conf /etc/nginx/nginx.conf
COPY entrypoint.sh /docker-entrypoint.sh
# Create SSL directory
RUN mkdir -p /etc/nginx/ssl && chmod 755 /etc/nginx/ssl \
&& chmod +x /docker-entrypoint.sh
EXPOSE 80 443
ENTRYPOINT ["/docker-entrypoint.sh"]

115
README.md
View File

@@ -1,16 +1,18 @@
<div align="center">
🌟 **If you find this project useful, please consider giving it a star!** 🌟
<h1><img src="https://github.com/user-attachments/assets/933c8b45-a190-4df6-913e-b7c64ad9938b" width="40" /> AliasVault</h1>
<p align="center">
<a href="https://app.aliasvault.net">Live demo 🚀</a> • <a href="https://aliasvault.net?utm_source=gh-readme">Website 🏠</a> • <a href="#installation">Installation 📦</a>
<a href="https://app.aliasvault.net">Try cloud version 🔥</a> • <a href="https://aliasvault.net?utm_source=gh-readme">Website 🌐</a> • <a href="https://docs.aliasvault.net?utm_source=gh-readme">Documentation 📚</a> • <a href="#self-host">Self-host instructions ⚙️</a>
</p>
<h3 align="center">
Open-source password and alias manager
</h3>
<p align="center">
<strong>Open-source password and (email) alias manager</strong>
</p>
[<img src="https://img.shields.io/github/v/release/lanedirt/AliasVault?include_prereleases&logo=github">](https://github.com/lanedirt/OGameX/releases)
[<img src="https://img.shields.io/github/v/release/lanedirt/AliasVault?include_prereleases&logo=github">](https://github.com/lanedirt/AliasVault/releases)
[<img src="https://img.shields.io/github/actions/workflow/status/lanedirt/AliasVault/docker-compose-build.yml?label=docker-compose%20build">](https://github.com/lanedirt/AliasVault/actions/workflows/docker-compose-build.yml)
[<img src="https://img.shields.io/github/actions/workflow/status/lanedirt/AliasVault/dotnet-unit-tests.yml?label=unit tests">](https://github.com/lanedirt/AliasVault/actions/workflows/dotnet-build-run-tests.yml)
[<img src="https://img.shields.io/github/actions/workflow/status/lanedirt/AliasVault/dotnet-integration-tests.yml?label=integration tests">](https://github.com/lanedirt/AliasVault/actions/workflows/dotnet-build-run-tests.yml)
@@ -19,7 +21,13 @@ Open-source password and alias manager
[<img src="https://img.shields.io/sonar/quality_gate/lanedirt_AliasVault?server=https%3A%2F%2Fsonarcloud.io&label=sonarcloud&logo=sonarcloud">](https://sonarcloud.io/summary/new_code?id=lanedirt_AliasVault)
</div>
AliasVault is an open-source password and alias manager built with C# ASP.NET technology. AliasVault can be self-hosted on your own server with Docker, providing a secure and private solution for managing your online identities and passwords.
<div align="center">
[<img alt="Discord" src="https://img.shields.io/discord/1309300619026235422?logo=discord&logoColor=%237289da&label=join%20discord%20chat&color=%237289da">](https://discord.gg/DsaXMTEtpF)
</div>
AliasVault is an end-to-end encrypted password and (email) alias manager that protects your privacy by creating alternative identities, passwords and email addresses for every website you use. The core of AliasVault is built with C# ASP.NET Blazor WASM technology. AliasVault can be self-hosted on your own server with Docker.
### What makes AliasVault unique:
- **Zero-knowledge architecture**: All data is end-to-end encrypted on the client and stored in encrypted state on the server. Your master password never leaves your device and the server never has access to your data.
@@ -29,50 +37,49 @@ AliasVault is an open-source password and alias manager built with C# ASP.NET te
> Note: AliasVault is currently in active development and some features may not yet have been (fully) implemented. If you run into any issues, please create an issue on GitHub.
## Live demo
A live demo of the app is available at the official website at [app.aliasvault.net](https://app.aliasvault.net) (up-to-date with `main` branch). You can create a free account to try it out yourself.
## Official Cloud Version
The official cloud version of AliasVault is freely available at [app.aliasvault.net](https://app.aliasvault.net). This fully supported platform is always up to date with our latest release. Create an account to protect your privacy today.
<img width="700" alt="Screenshot of AliasVault" src="docs/img/screenshot.png">
[<img width="700" alt="Screenshot of AliasVault" src="docs/assets/img/screenshot.png">](https://app.aliasvault.net)
## Installation
To install AliasVault on your local machine, follow the steps below. Note: the install process is tested on MacOS and Linux. It should work on Windows too, but you might need to adjust some commands.
## Self-host
### Requirements:
- Access to a terminal
- Docker
- Git
To self-host and install AliasVault on your own server, the easiest method is to use the provided install script. This will download the pre-built Docker images and start the containers.
### 1. Clone and run install script
AliasVault comes with a install script that prepares the .env file, builds the Docker image, and starts the AliasVault containers.
### Install using install script
This method uses pre-built Docker images and works on minimal hardware specifications:
- Linux VM with root access (Ubuntu/AlmaLinux recommended) or Raspberry Pi
- 1 vCPU
- 1GB RAM
- 16GB disk space
- Docker installed
```bash
# Clone this Git repository to "AliasVault" directory
$ git clone https://github.com/lanedirt/AliasVault.git
# Download install script from latest stable release
curl -o install.sh https://raw.githubusercontent.com/lanedirt/AliasVault/0.11.1/install.sh
# Go to the project directory
$ cd AliasVault
# Make install script executable and run it.
$ chmod +x install.sh && ./install.sh
# Make install script executable and run it. This will create the .env file, pull the Docker images, and start the AliasVault containers.
chmod +x install.sh
./install.sh install
```
Note: if you do not wish to run the script, you can set up the environment variables and build the Docker image and containers manually instead. See the [manual setup instructions](docs/install/1-manually-setup-docker.md) for more information.
The install script will output the URL where the app is available. By default this is:
- Client: https://localhost
- Admin portal: https://localhost/admin
### 2. Ready to use
The install script executed in step #1 will output the URL where the app is available. By default this is http://localhost:80 for the client and http://localhost:8080 for the admin.
> Note: If you want to change the default AliasVault ports you can do so in the `.env` file.
> Note: If you want to change the default AliasVault ports you can do so in the `docker-compose.yml` file.
## Documentation
For more detailed information about the installation process and other topics, please see the official documentation website:
- [Documentation website (docs.aliasvault.net) 📚](https://docs.aliasvault.net)
#### Note for first time build:
- When running the init script for the first time, it may take a few minutes for Docker to download all dependencies. Subsequent builds will be faster.
- A SQLite database file will be created in `./database/AliasServerDb.sqlite`. This file will store all (encrypted) password vaults. It should be kept secure and not shared.
Here you can also find step-by-step instructions on how to install AliasVault to e.g. Azure, AWS and other popular cloud providers.
#### Other useful commands:
- To reset the admin password, run the install.sh script with the `--reset-admin-password` flag.
- To uninstall AliasVault, make the uninstall script executable with `chmod +x uninstall.sh` first, then run the script: `./uninstall.sh`.
This will remove all containers, images, and volumes related to AliasVault. It will keep all files and configuration intact however, so you can easily reinstall AliasVault later.
## Security Architecture
<a href="https://docs.aliasvault.net/architecture"><img alt="AliasVault Security Architecture Diagram" src="docs/assets/diagrams/security-architecture/aliasvault-security-architecture-thumb.jpg" width="343"></a>
## Security & Architecture
AliasVault takes security seriously and implements various measures to protect your data:
- All sensitive user data is encrypted end-to-end using industry-standard encryption algorithms. This includes the complete vault contents and all received emails.
@@ -81,21 +88,43 @@ AliasVault takes security seriously and implements various measures to protect y
For detailed information about our encryption implementation and security architecture, see the following documents:
- [SECURITY.md](SECURITY.md)
- [Security Architecture (Diagram)](docs/security-architecture.md)
- [Security Architecture Diagram](https://docs.aliasvault.net/architecture)
## Roadmap
AliasVault is under active development with new features being added regularly. We believe in transparency and want to share our vision for the future of the platform. Here's what we've accomplished and what we're working on next:
- [x] Core password & alias management
- [x] End-to-end encryption
- [x] Built-in email server for aliases
- [x] Single-command Docker-based installation
- [ ] Add support for connecting custom user domains to cloud hosted version (https://github.com/lanedirt/AliasVault/issues/485)
- [ ] Add and associate TOTP MFA tokens to credentials (https://github.com/lanedirt/AliasVault/issues/181)
- [ ] Browser extensions Chrome + Firefox (https://github.com/lanedirt/AliasVault/issues/541)
- [ ] Import passwords from existing password managers (https://github.com/lanedirt/AliasVault/issues/542)
### Future Plans
- [ ] Mobile apps (iOS, Android)
- [ ] Team / organization features (sharing passwords/aliases)
- [ ] Disposable phone number service
Want to suggest a feature? Join our [Discord](https://discord.gg/DsaXMTEtpF) or create an issue on GitHub.
## Tech stack / credits
The following technologies, frameworks and libraries are used in this project:
- [C#](https://docs.microsoft.com/en-us/dotnet/csharp/) - A simple, modern, object-oriented, and type-safe programming language.
- [ASP.NET Core](https://dotnet.microsoft.com/apps/aspnet) - An open-source framework for building modern, cloud-based, internet-connected applications.
- [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) - A lightweight, extensible, open-source and cross-platform version of the popular Entity Framework data access technology.
- [ASP.NET Core](https://dotnet.microsoft.com/apps/aspnet) - An open-source framework for building modern multi-platform web applications.
- [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) - Object-relational mapping framework for .NET.
- [Blazor WASM](https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor) - A framework for building interactive web UIs using C# instead of JavaScript. It's a single-page app framework that runs in the browser via WebAssembly.
- [Playwright](https://playwright.dev/) - A Node.js library to automate Chromium, Firefox and WebKit with a single API. Used for end-to-end testing.
- [Docker](https://www.docker.com/) - A platform for building, sharing, and running containerized applications.
- [SQLite](https://www.sqlite.org/index.html) - A C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine.
- [PostgreSQL](https://www.postgresql.org/) - An open-source object-relational database system used as the database for the server.
- [Docker](https://www.docker.com/) - Used for containerizing the server and client apps.
- [SQLite](https://www.sqlite.org/index.html) - A C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine. Used as database engine for the encrypted user's vault.
- [Tailwind CSS](https://tailwindcss.com/) - A utility-first CSS framework for rapidly building custom designs.
- [Flowbite](https://flowbite.com/) - A free and open-source UI component library based on Tailwind CSS.
- [Konscious.Security.Cryptography](https://github.com/kmaragon/Konscious.Security.Cryptography) - A .NET library that implements Argon2id, a memory-hard password hashing algorithm.
- [SRP.net](https://github.com/secure-remote-password/srp.net) - SRP6a Secure Remote Password protocol for secure password authentication.
- [SRP.net](https://github.com/secure-remote-password/srp.net) - SRP6a Secure Remote Password protocol for secure password authentication without sending plaintext passwords over the network.
- [Playwright](https://playwright.dev/) - A Node.js library to automate Chromium, Firefox and WebKit with a single API. Used for end-to-end testing.
- [SmtpServer](https://github.com/cosullivan/SmtpServer) - A SMTP server library for .NET that is used for the virtual email address feature.
- [MimeKit](https://github.com/jstedfast/MimeKit) - A .NET MIME creation and parser library used for the virtual email address feature.
- [StyleCop.Analyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) - Static code analysis tool that enforces style and consistency rules for C# code.
- [SonarQube Cloud](https://www.sonarqube.org/) - A platform for continuous code quality management.

View File

@@ -19,7 +19,7 @@ The following encryption algorithms are used by AliasVault:
Below is a detailed explanation of each encryption algorithm.
For more information about how these algorithms are specifically used in AliasVault, see the [Security Architecture](docs/security-architecture.md) document.
For more information about how these algorithms are specifically used in AliasVault, see the [Architecture Documentation](https://docs.aliasvault.net/architecture) section on the documentation site.
### Argon2id
To derive a key from the master password, AliasVault uses the Argon2id key derivation function. Argon2id is a memory-hard

View File

@@ -67,6 +67,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{DD359F
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AliasVault.Shared.Core", "src\Shared\AliasVault.Shared.Core\AliasVault.Shared.Core.csproj", "{40CA41BF-9E67-4D0A-A3F8-38B94992E4CA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AliasVault.TaskRunner", "src\Services\AliasVault.TaskRunner\AliasVault.TaskRunner.csproj", "{D631A936-DD1C-40CC-B735-BD0A5D4F46A1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AliasVault.Shared.Server", "src\Shared\AliasVault.Shared.Server\AliasVault.Shared.Server.csproj", "{34FADEB6-4B56-463B-B359-F844B43D76D9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -169,6 +173,14 @@ Global
{40CA41BF-9E67-4D0A-A3F8-38B94992E4CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40CA41BF-9E67-4D0A-A3F8-38B94992E4CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40CA41BF-9E67-4D0A-A3F8-38B94992E4CA}.Release|Any CPU.Build.0 = Release|Any CPU
{D631A936-DD1C-40CC-B735-BD0A5D4F46A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D631A936-DD1C-40CC-B735-BD0A5D4F46A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D631A936-DD1C-40CC-B735-BD0A5D4F46A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D631A936-DD1C-40CC-B735-BD0A5D4F46A1}.Release|Any CPU.Build.0 = Release|Any CPU
{34FADEB6-4B56-463B-B359-F844B43D76D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34FADEB6-4B56-463B-B359-F844B43D76D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34FADEB6-4B56-463B-B359-F844B43D76D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34FADEB6-4B56-463B-B359-F844B43D76D9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -197,6 +209,8 @@ Global
{59642CEF-D90A-4A6B-AD3F-9C6300D1E3FC} = {DD359F0A-0180-4F8F-9E48-46213386BA4D}
{15EFE0D0-F41B-47D7-86B7-8F840335CB82} = {DD359F0A-0180-4F8F-9E48-46213386BA4D}
{40CA41BF-9E67-4D0A-A3F8-38B94992E4CA} = {DD359F0A-0180-4F8F-9E48-46213386BA4D}
{D631A936-DD1C-40CC-B735-BD0A5D4F46A1} = {8A477241-B96C-4174-968D-D40CB77F1ECD}
{34FADEB6-4B56-463B-B359-F844B43D76D9} = {DD359F0A-0180-4F8F-9E48-46213386BA4D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FEE82475-C009-4762-8113-A6563D9DC49E}

View File

@@ -1,4 +1,6 @@
This is the default location where (self-generated) certificates are stored.
# Certificates directory structure
For example, the API and Admin projects make use of the .NET DataProtection API that depends on
certificates for encrypting various types of application data such as authentication cookies, anti-forgery tokens etc.
This directory contains certificates for AliasVault.
- `app`: Certificates that AliasVault uses to protect application data at rest (e.g. .NET DataProtection keys)
- `ssl`: SSL/TLS certificates for AliasVault hosted services

View File

@@ -0,0 +1,7 @@
# SSL certificates directory structure
This directory contains SSL/TLS certificates for various AliasVault services:
- `admin`: Certificate for the Admin UI.
- `api`: Certificate for the API service.
- `client`: Certificate for the Client UI.

42
docker-compose.build.yml Normal file
View File

@@ -0,0 +1,42 @@
services:
postgres:
image: aliasvault-postgres
build:
context: .
dockerfile: src/Databases/AliasServerDb/Dockerfile
client:
image: aliasvault-client
build:
context: .
dockerfile: src/AliasVault.Client/Dockerfile
api:
image: aliasvault-api
build:
context: .
dockerfile: src/AliasVault.Api/Dockerfile
admin:
image: aliasvault-admin
build:
context: .
dockerfile: src/AliasVault.Admin/Dockerfile
reverse-proxy:
image: aliasvault-reverse-proxy
build:
context: .
dockerfile: Dockerfile
smtp:
image: aliasvault-smtp
build:
context: .
dockerfile: src/Services/AliasVault.SmtpService/Dockerfile
task-runner:
image: aliasvault-task-runner
build:
context: .
dockerfile: src/Services/AliasVault.TaskRunner/Dockerfile

20
docker-compose.dev.yml Normal file
View File

@@ -0,0 +1,20 @@
services:
postgres-dev:
image: postgres:16-alpine
ports:
- "5433:5432"
volumes:
- ./database/postgres-dev:/var/lib/postgresql/data:rw
- ./src/Databases/AliasServerDb/postgresql.conf:/etc/postgresql/postgresql.conf
environment:
- POSTGRES_DB=aliasvault
- POSTGRES_USER=aliasvault
- POSTGRES_PASSWORD=password
restart: "no"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U aliasvault"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
command: ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]

View File

@@ -0,0 +1,7 @@
services:
certbot:
image: certbot/certbot
volumes:
- ./certificates/letsencrypt:/etc/letsencrypt:rw
- ./certificates/letsencrypt/www:/var/www/certbot:rw
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

View File

@@ -1,55 +1,107 @@
services:
admin:
image: aliasvault-admin
build:
context: .
dockerfile: src/AliasVault.Admin/Dockerfile
ports:
- "8080:8082"
postgres:
image: ghcr.io/lanedirt/aliasvault-postgres:latest
volumes:
- ./certificates:/certificates:rw
- ./database:/database:rw
- ./logs:/logs:rw
restart: always
- ./database/postgres:/var/lib/postgresql/data:rw
env_file:
- .env
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U aliasvault"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
client:
image: aliasvault-client
build:
context: .
dockerfile: src/AliasVault.Client/Dockerfile
ports:
- "80:8080"
image: ghcr.io/lanedirt/aliasvault-client:latest
volumes:
- ./logs/msbuild:/src/msbuild-logs:rw
expose:
- "3000"
restart: always
env_file:
- .env
api:
image: aliasvault-api
build:
context: .
dockerfile: src/AliasVault.Api/Dockerfile
ports:
- "81:8081"
image: ghcr.io/lanedirt/aliasvault-api:latest
expose:
- "3001"
volumes:
- ./certificates:/certificates:rw
- ./database:/database:rw
- ./certificates/app:/certificates/app:rw
- ./logs:/logs:rw
restart: always
env_file:
- .env
depends_on:
postgres:
condition: service_healthy
environment:
ConnectionStrings__AliasServerDbContext: "Host=postgres;Database=aliasvault;Username=aliasvault;Password=${POSTGRES_PASSWORD}"
admin:
image: ghcr.io/lanedirt/aliasvault-admin:latest
expose:
- "3002"
volumes:
- ./database:/database:rw
- ./certificates/app:/certificates/app:rw
- ./logs:/logs:rw
restart: always
env_file:
- .env
depends_on:
postgres:
condition: service_healthy
environment:
ConnectionStrings__AliasServerDbContext: "Host=postgres;Database=aliasvault;Username=aliasvault;Password=${POSTGRES_PASSWORD}"
reverse-proxy:
image: ghcr.io/lanedirt/aliasvault-reverse-proxy:latest
ports:
- "${HTTP_PORT:-80}:80"
- "${HTTPS_PORT:-443}:443"
volumes:
- ./certificates/ssl:/etc/nginx/ssl:rw
- ./certificates/letsencrypt:/etc/nginx/ssl-letsencrypt:rw
- ./certificates/letsencrypt/www:/var/www/certbot:rw
depends_on:
- admin
- client
- api
- smtp
restart: always
env_file:
- .env
smtp:
image: aliasvault-smtp
build:
context: .
dockerfile: src/Services/AliasVault.SmtpService/Dockerfile
image: ghcr.io/lanedirt/aliasvault-smtp:latest
ports:
- "25:25"
- "587:587"
- "${SMTP_PORT:-25}:25"
- "${SMTP_TLS_PORT:-587}:587"
volumes:
- ./database:/database:rw
- ./logs:/logs:rw
restart: always
env_file:
- .env
depends_on:
postgres:
condition: service_healthy
environment:
ConnectionStrings__AliasServerDbContext: "Host=postgres;Database=aliasvault;Username=aliasvault;Password=${POSTGRES_PASSWORD}"
task-runner:
image: ghcr.io/lanedirt/aliasvault-task-runner:latest
volumes:
- ./database:/database:rw
- ./logs:/logs:rw
restart: always
env_file:
- .env
depends_on:
postgres:
condition: service_healthy
environment:
ConnectionStrings__AliasServerDbContext: "Host=postgres;Database=aliasvault;Username=aliasvault;Password=${POSTGRES_PASSWORD}"

1
docs/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
!release

1
docs/CNAME Normal file
View File

@@ -0,0 +1 @@
docs.aliasvault.net

8
docs/Dockerfile Normal file
View File

@@ -0,0 +1,8 @@
FROM jekyll/jekyll:4.2.2
WORKDIR /srv/jekyll
COPY . .
RUN chown -R jekyll:jekyll /srv/jekyll
# Install the theme and dependencies
RUN bundle install

8
docs/Gemfile Normal file
View File

@@ -0,0 +1,8 @@
source 'https://rubygems.org'
# gem "jekyll", "~> 4.3.2"
gem "just-the-docs"
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
# uncomment the line below. To upgrade, run `bundle update github-pages`.
gem "github-pages", group: :jekyll_plugins

286
docs/Gemfile.lock Normal file
View File

@@ -0,0 +1,286 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (7.2.2)
base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
logger (>= 1.4.2)
minitest (>= 5.1)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
base64 (0.2.0)
benchmark (0.4.0)
bigdecimal (3.1.8)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
colorator (1.1.0)
commonmarker (0.23.11)
concurrent-ruby (1.3.4)
connection_pool (2.4.1)
csv (3.3.0)
dnsruby (1.72.3)
base64 (~> 0.2.0)
simpleidn (~> 0.2.1)
drb (2.2.1)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
ethon (0.16.0)
ffi (>= 1.15.0)
eventmachine (1.2.7)
execjs (2.10.0)
faraday (2.12.1)
faraday-net_http (>= 2.0, < 3.5)
json
logger
faraday-net_http (3.4.0)
net-http (>= 0.5.0)
ffi (1.17.0-x86_64-linux-musl)
forwardable-extended (2.6.0)
gemoji (4.1.0)
github-pages (232)
github-pages-health-check (= 1.18.2)
jekyll (= 3.10.0)
jekyll-avatar (= 0.8.0)
jekyll-coffeescript (= 1.2.2)
jekyll-commonmark-ghpages (= 0.5.1)
jekyll-default-layout (= 0.1.5)
jekyll-feed (= 0.17.0)
jekyll-gist (= 1.5.0)
jekyll-github-metadata (= 2.16.1)
jekyll-include-cache (= 0.2.1)
jekyll-mentions (= 1.6.0)
jekyll-optional-front-matter (= 0.3.2)
jekyll-paginate (= 1.1.0)
jekyll-readme-index (= 0.3.0)
jekyll-redirect-from (= 0.16.0)
jekyll-relative-links (= 0.6.1)
jekyll-remote-theme (= 0.4.3)
jekyll-sass-converter (= 1.5.2)
jekyll-seo-tag (= 2.8.0)
jekyll-sitemap (= 1.4.0)
jekyll-swiss (= 1.0.0)
jekyll-theme-architect (= 0.2.0)
jekyll-theme-cayman (= 0.2.0)
jekyll-theme-dinky (= 0.2.0)
jekyll-theme-hacker (= 0.2.0)
jekyll-theme-leap-day (= 0.2.0)
jekyll-theme-merlot (= 0.2.0)
jekyll-theme-midnight (= 0.2.0)
jekyll-theme-minimal (= 0.2.0)
jekyll-theme-modernist (= 0.2.0)
jekyll-theme-primer (= 0.6.0)
jekyll-theme-slate (= 0.2.0)
jekyll-theme-tactile (= 0.2.0)
jekyll-theme-time-machine (= 0.2.0)
jekyll-titles-from-headings (= 0.5.3)
jemoji (= 0.13.0)
kramdown (= 2.4.0)
kramdown-parser-gfm (= 1.1.0)
liquid (= 4.0.4)
mercenary (~> 0.3)
minima (= 2.5.1)
nokogiri (>= 1.16.2, < 2.0)
rouge (= 3.30.0)
terminal-table (~> 1.4)
webrick (~> 1.8)
github-pages-health-check (1.18.2)
addressable (~> 2.3)
dnsruby (~> 1.60)
octokit (>= 4, < 8)
public_suffix (>= 3.0, < 6.0)
typhoeus (~> 1.3)
html-pipeline (2.14.3)
activesupport (>= 2)
nokogiri (>= 1.4)
http_parser.rb (0.8.0)
i18n (1.14.6)
concurrent-ruby (~> 1.0)
jekyll (3.10.0)
addressable (~> 2.4)
colorator (~> 1.0)
csv (~> 3.0)
em-websocket (~> 0.5)
i18n (>= 0.7, < 2)
jekyll-sass-converter (~> 1.0)
jekyll-watch (~> 2.0)
kramdown (>= 1.17, < 3)
liquid (~> 4.0)
mercenary (~> 0.3.3)
pathutil (~> 0.9)
rouge (>= 1.7, < 4)
safe_yaml (~> 1.0)
webrick (>= 1.0)
jekyll-avatar (0.8.0)
jekyll (>= 3.0, < 5.0)
jekyll-coffeescript (1.2.2)
coffee-script (~> 2.2)
coffee-script-source (~> 1.12)
jekyll-commonmark (1.4.0)
commonmarker (~> 0.22)
jekyll-commonmark-ghpages (0.5.1)
commonmarker (>= 0.23.7, < 1.1.0)
jekyll (>= 3.9, < 4.0)
jekyll-commonmark (~> 1.4.0)
rouge (>= 2.0, < 5.0)
jekyll-default-layout (0.1.5)
jekyll (>= 3.0, < 5.0)
jekyll-feed (0.17.0)
jekyll (>= 3.7, < 5.0)
jekyll-gist (1.5.0)
octokit (~> 4.2)
jekyll-github-metadata (2.16.1)
jekyll (>= 3.4, < 5.0)
octokit (>= 4, < 7, != 4.4.0)
jekyll-include-cache (0.2.1)
jekyll (>= 3.7, < 5.0)
jekyll-mentions (1.6.0)
html-pipeline (~> 2.3)
jekyll (>= 3.7, < 5.0)
jekyll-optional-front-matter (0.3.2)
jekyll (>= 3.0, < 5.0)
jekyll-paginate (1.1.0)
jekyll-readme-index (0.3.0)
jekyll (>= 3.0, < 5.0)
jekyll-redirect-from (0.16.0)
jekyll (>= 3.3, < 5.0)
jekyll-relative-links (0.6.1)
jekyll (>= 3.3, < 5.0)
jekyll-remote-theme (0.4.3)
addressable (~> 2.0)
jekyll (>= 3.5, < 5.0)
jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
rubyzip (>= 1.3.0, < 3.0)
jekyll-sass-converter (1.5.2)
sass (~> 3.4)
jekyll-seo-tag (2.8.0)
jekyll (>= 3.8, < 5.0)
jekyll-sitemap (1.4.0)
jekyll (>= 3.7, < 5.0)
jekyll-swiss (1.0.0)
jekyll-theme-architect (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-cayman (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-dinky (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-hacker (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-leap-day (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-merlot (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-midnight (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-minimal (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-modernist (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-primer (0.6.0)
jekyll (> 3.5, < 5.0)
jekyll-github-metadata (~> 2.9)
jekyll-seo-tag (~> 2.0)
jekyll-theme-slate (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-tactile (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-time-machine (0.2.0)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-titles-from-headings (0.5.3)
jekyll (>= 3.3, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
jemoji (0.13.0)
gemoji (>= 3, < 5)
html-pipeline (~> 2.2)
jekyll (>= 3.0, < 5.0)
json (2.8.2)
just-the-docs (0.10.0)
jekyll (>= 3.8.5)
jekyll-include-cache
jekyll-seo-tag (>= 2.0)
rake (>= 12.3.1)
kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.4)
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.6.1)
mercenary (0.3.6)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.25.1)
net-http (0.5.0)
uri
nokogiri (1.16.7-x86_64-linux)
racc (~> 1.4)
octokit (4.25.1)
faraday (>= 1, < 3)
sawyer (~> 0.9)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (5.1.1)
racc (1.8.1)
rake (13.2.1)
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
rexml (3.3.9)
rouge (3.30.0)
rubyzip (2.3.2)
safe_yaml (1.0.5)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
securerandom (0.3.2)
simpleidn (0.2.3)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
typhoeus (1.4.1)
ethon (>= 0.9.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (1.8.0)
uri (1.0.2)
webrick (1.9.0)
PLATFORMS
x86_64-linux-musl
DEPENDENCIES
github-pages
just-the-docs
BUNDLED WITH
2.3.25

View File

@@ -1,5 +0,0 @@
# Documentation
This is the documentation for the AliasVault project.
## Description
TODO: Work in progress.

40
docs/_config.yml Normal file
View File

@@ -0,0 +1,40 @@
remote_theme: just-the-docs/just-the-docs
title: AliasVault
description: Documentation for the AliasVault password manager
logo: "/assets/img/logo.svg"
favicon_ico: "/assets/img/favicon.png"
# Navigation settings
aux_links:
"AliasVault on GitHub":
- "https://github.com/lanedirt/AliasVault"
"AliasVault Website":
- "https://aliasvault.net"
aux_links_new_tab: true
# Search settings
search_enabled: true
heading_anchors: true
# Theme settings
color_scheme: aliasvault
# Enable copy code button
enable_copy_code_button: true
# Footer "Edit this page on GitHub" link text
gh_edit_link: true # show or hide edit this page link
gh_edit_link_text: "Edit this page on GitHub."
gh_edit_repository: "https://github.com/lanedirt/AliasVault" # the github URL for your repo
gh_edit_branch: "main" # the branch that your docs is served from
gh_edit_source: docs # the source that your files originate from
gh_edit_view_mode: "tree" # "tree" or "edit" if you want the user to jump into the editor immediately
callouts:
warning:
title: Warning
color: red
note:
title: Note
color: purple

View File

View File

@@ -0,0 +1 @@
&nbsp;

View File

@@ -0,0 +1,42 @@
@import "./color_schemes/dark";
// Base theme colors
$link-color: #f49541;
$btn-primary-color: #d68338;
// Main colors
$body-background-color: #1f2937;
$sidebar-color: #111827;
$border-color: #374151;
$body-text-color: #f8f9fa;
// Navigation
$nav-child-link-color: #fdde85;
$search-result-preview-color: #e9ecef;
// Content elements
$feedback-color: #2d3748;
$table-background-color: #374151;
$search-background-color: #374151;
// Code blocks
$code-background-color: #2d3748;
$code-linenumber-color: #9ca3af;
// Tables
$table-border-color: #4b5563;
// Search
$search-result-preview-color: #d1d5db;
// Buttons
$btn-primary-color-dark: #d68338;
// Base Colors (kept for compatibility)
$purple-000: #f8b963;
$purple-100: #ffd5a8;
$purple-200: #f49541;
$purple-300: #d68338;
// Navigation additional
$nav-button-color: #f49541;

View File

@@ -1,4 +1,11 @@
# Security Architecture
---
layout: default
title: Architecture
has_children: true
nav_order: 3
---
# Architecture
AliasVault implements a zero-knowledge architecture where sensitive user data and passwords never leave the client device in unencrypted form. Below is a detailed explanation of how the system secures user data and communications.
@@ -6,12 +13,12 @@ AliasVault implements a zero-knowledge architecture where sensitive user data an
The security architecture diagram below illustrates all encryption and authentication processes used in AliasVault to secure user data and communications.
<picture>
<source media="(prefers-color-scheme: dark)" srcset="diagrams/security-architecture/aliasvault-security-architecture-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="diagrams/security-architecture/aliasvault-security-architecture-light.svg">
<img alt="AliasVault Security Architecture Diagram" src="diagrams/security-architecture/aliasvault-security-architecture-light.svg">
<source media="(prefers-color-scheme: dark)" srcset="../assets/diagrams/security-architecture/aliasvault-security-architecture-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="../assets/diagrams/security-architecture/aliasvault-security-architecture-light.svg">
<img alt="AliasVault Security Architecture Diagram" src="../assets/diagrams/security-architecture/aliasvault-security-architecture-light.svg">
</picture>
You can also view the diagram in a browser-friendly HTML format: [AliasVault Security Architecture](diagrams/security-architecture/aliasvault-security-architecture.html)
You can also view the diagram in a browser-friendly HTML format: [AliasVault Security Architecture](https://lanedirt.github.io/AliasVault/assets/diagrams/security-architecture/aliasvault-security-architecture.html)
## Key Components and Process Flow

View File

@@ -1,3 +1,5 @@
# Diagrams
This folder contains architecture and flow diagrams for AliasVault in various formats.

View File

Before

Width:  |  Height:  |  Size: 1024 KiB

After

Width:  |  Height:  |  Size: 1024 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
docs/assets/img/favicon.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 B

2
docs/assets/img/logo.svg Normal file
View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg enable-background="new 0 0 800 500" version="1.1" viewBox="-1.84 7.892 1822.253 474.315" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com" width="1822.253px" height="474.315px"><defs><bx:export><bx:file format="svg"/></bx:export></defs><path d="m459.87 294.95c0.016205 5.4005 0.03241 10.801-0.35022 16.873-1.111 6.3392-1.1941 12.173-2.6351 17.649-10.922 41.508-36.731 69.481-77.351 83.408-7.2157 2.4739-14.972 3.3702-22.479 4.995-23.629 0.042205-47.257 0.11453-70.886 0.12027-46.762 0.011322-93.523-0.01416-140.95-0.43411-8.59-2.0024-16.766-2.8352-24.398-5.3326-21.595-7.0666-39.523-19.656-53.708-37.552-10.227-12.903-17.579-27.17-21.28-43.221-1.475-6.3967-2.4711-12.904-3.6852-19.361-0.051849-5.747-0.1037-11.494 0.26915-17.886 4.159-42.973 27.68-71.638 63.562-92.153 0-0.70761-0.001961-1.6988 3.12e-4 -2.69 0.022484-9.8293-1.3071-19.894 0.35664-29.438 3.2391-18.579 11.08-35.272 23.763-49.773 12.098-13.832 26.457-23.989 43.609-30.029 7.813-2.7512 16.14-4.0417 24.234-5.9948 7.392-0.025734 14.784-0.05146 22.835 0.32253 4.1959 0.95392 7.7946 1.2538 11.258 2.1053 17.16 4.2192 32.287 12.176 45.469 24.104 2.2558 2.0411 4.372 6.6241 9.621 3.868 16.839-8.8419 34.718-11.597 53.603-8.594 16.791 2.6699 31.602 9.4308 44.236 20.636 11.531 10.227 19.84 22.841 25.393 37.236 6.3436 16.445 10.389 33.163 6.0798 49.389 7.9587 8.9321 15.807 16.704 22.421 25.414 9.162 12.065 15.33 25.746 18.144 40.776 0.97046 5.1848 1.9111 10.375 2.8654 15.563m-71.597 71.012c5.5615-5.2284 12.002-9.7986 16.508-15.817 10.474-13.992 14.333-29.916 11.288-47.446-2.2496-12.95-8.1973-24.076-17.243-33.063-12.746-12.663-28.865-18.614-46.786-18.569-69.912 0.17712-139.82 0.56831-209.74 0.96176-15.922 0.089599-29.168 7.4209-39.685 18.296-14.45 14.944-20.408 33.343-16.655 54.368 2.2763 12.754 8.2167 23.748 17.158 32.66 13.299 13.255 30.097 18.653 48.728 18.651 59.321-0.005188 118.64 0.042358 177.96-0.046601 9.5912-0.014374 19.181-0.86588 28.773-0.88855 10.649-0.025146 19.978-3.825 29.687-9.1074z" fill="#EEC170"/><path d="m162.77 293c15.654 4.3883 20.627 22.967 10.304 34.98-5.3104 6.1795-14.817 8.3208-24.278 5.0472-7.0723-2.4471-12.332-10.362-12.876-17.933-1.0451-14.542 11.089-23.176 21.705-23.046 1.5794 0.019287 3.1517 0.61566 5.1461 0.95184z" fill="#EEC170"/><path d="m227.18 293.64c7.8499 2.3973 11.938 8.2143 13.524 15.077 1.8591 8.0439-0.44817 15.706-7.1588 21.121-6.7633 5.4572-14.417 6.8794-22.578 3.1483-8.2972-3.7933-12.836-10.849-12.736-19.438 0.1687-14.497 14.13-25.368 28.948-19.908z" fill="#EEC170"/><path d="m261.57 319.07c-2.495-14.418 4.6853-22.603 14.596-26.108 9.8945-3.4995 23.181 3.4303 26.267 13.779 4.6504 15.591-7.1651 29.064-21.665 28.161-8.5254-0.53088-17.202-6.5094-19.198-15.831z" fill="#EEC170"/><path d="m336.91 333.41c-9.0175-4.2491-15.337-14.349-13.829-21.682 3.0825-14.989 13.341-20.304 23.018-19.585 10.653 0.79141 17.93 7.407 19.765 17.547 1.9588 10.824-4.1171 19.939-13.494 23.703-5.272 2.1162-10.091 1.5086-15.46 0.017883z" fill="#EEC170"/><text style="fill: rgb(255, 255, 255); font-family: Arial, sans-serif; font-size: 268.3px; font-weight: 700; white-space: pre;" x="531.151" y="358.747">AliasVault</text></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 188 KiB

14
docs/contact/index.md Normal file
View File

@@ -0,0 +1,14 @@
---
layout: default
title: Help and Support
has_children: true
nav_order: 100
---
# Help and Support
If you need help or have any questions about installing or using AliasVault, you can reach us on [AliasVault Discord](https://discord.gg/DsaXMTEtpF).
If you have found a bug or have a feature request, please open an issue on [AliasVault GitHub](https://github.com/lanedirt/AliasVault/issues).
If you have any other questions or feedback, please use the contact form on the [AliasVault website](https://aliasvault.net/contact).

View File

@@ -1,18 +0,0 @@
To configure SQLite for use with WebAssembly follow these steps:
1. Add NuGet package
```
dotnet add package SQLitePCLRaw.bundle_e_sqlite3
```
2. Modify .csproj and add the following:
```xml
<PropertyGroup>
<WasmBuildNative>true</WasmBuildNative>
</PropertyGroup>
```
3. Make sure the "wasm-tools" workload is installed on the local machine in order to build the project:
```
dotnet workload install wasm-tools
```

12
docs/docker-compose.yml Normal file
View File

@@ -0,0 +1,12 @@
services:
jekyll:
build: .
volumes:
- .:/srv/jekyll
ports:
- "4000:4000"
command: bundle exec jekyll serve --host 0.0.0.0 --watch --force_polling --livereload
environment:
- JEKYLL_ENV=development
- JEKYLL_NO_CACHE=true
- DISABLE_DISK_CACHE=true

45
docs/index.md Normal file
View File

@@ -0,0 +1,45 @@
---
layout: home
title: Home
nav_order: 1
description: "AliasVault Documentation - Open-source password and identity manager"
permalink: /
---
# AliasVault Documentation
{: .fs-9 }
Open-source password and identity manager with email alias generation and zero-knowledge architecture.
{: .fs-6 .fw-300 }
[Installation](./installation/install){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }
[View on GitHub](https://github.com/lanedirt/AliasVault){: .btn .fs-5 .mb-4 .mb-md-0 }
---
## What is AliasVault?
AliasVault is a self-hosted password and identity manager that helps you:
- 🔐 **Secure Passwords** - Store and manage passwords with zero-knowledge encryption
- 📧 **Email Aliases** - Generate unique email addresses for each service
- 🎭 **Identity Management** - Create and manage separate online identities
- 🏠 **Self-Hosted** - Run on your own infrastructure using Docker
- 🔓 **Open Source** - Transparent, auditable, and free to use
## Key Features
### Zero-Knowledge Architecture
All data is end-to-end encrypted on the client. Your master password never leaves your device, and the server never has access to your data.
### Built-in Email Server
Generate virtual email addresses for each identity. Emails sent to these addresses are instantly visible in the AliasVault app.
### Virtual Identities
Create separate identities for different purposes, each with its own email aliases and credentials.
---
## Getting Started
Ready to get started with AliasVault? Check out the [installation guide](./installation).

View File

@@ -1,110 +0,0 @@
# Manual Setup Instructions for AliasVault
This README provides step-by-step instructions for manually setting up AliasVault without using the `install.sh` script. Follow these steps if you prefer to execute all statements yourself.
## Prerequisites
- Docker and Docker Compose installed on your system
- OpenSSL for generating random passwords
## Steps
1. **Create .env file**
Copy the `.env.example` file to create a new `.env` file:
```
cp .env.example .env
```
2. **Generate and set JWT_KEY**
Update the .env file and set the JWT_KEY environment variable to a random 32-char string. This key is used for JWT token generation and should be kept secure.
Generate a random 32 char string for the JWT:
```
openssl rand -base64 32
```
Add the generated key to the .env file:
```
JWT_KEY=your_32_char_string_here
3. **Set PRIVATE_EMAIL_DOMAINS**
Update the .env file and set the PRIVATE_EMAIL_DOMAINS value the allowed domains that can be used for email addresses. Separate multiple domains with commas.
```
PRIVATE_EMAIL_DOMAINS=yourdomain.com,anotherdomain.com
```
Replace `yourdomain.com,anotherdomain.com` with your actual allowed domains.
4. **Set SMTP_TLS_ENABLED**
Decide whether to enable TLS for email and add it to the .env file:
```
SMTP_TLS_ENABLED=true
```
Or set it to `false` if you don't want to enable TLS.
5. **Generate admin password**
Set the admin password hash in the .env file. The password hash is generated using the `InitializationCLI` utility.
Build the Docker image for password hashing:
```
docker build -t initcli -f src/Utilities/InitializationCLI/Dockerfile .
```
Generate the password hash:
```
docker run --rm initcli "<your_prefered_admin_password_here>"
```
Add the password hash and generation timestamp to the .env file:
```
ADMIN_PASSWORD_HASH=<output_of_step_above>
ADMIN_PASSWORD_GENERATED=2024-01-01T00:00:00Z
```
6. **Build and start Docker containers**
Build the Docker Compose stack:
```
docker-compose build
```
Start the Docker Compose stack:
```
docker-compose up -d
```
7. **Access AliasVault**
AliasVault should now be running. You can access it as follows:
- Admin Panel: http://localhost:8080/
- Username: admin
- Password: [Use the ADMIN_PASSWORD generated in step 5]
- Client Website: http://localhost:80/
- Create your own account from here
## Important Notes
- Make sure to save the admin password (ADMIN_PASSWORD) generated in step 5 in a secure location. It won't be shown again.
- If you need to reset the admin password in the future, you'll need to generate a new hash and update the .env file manually.
Afterwards restart the docker containers which will update the admin password in the database.
- Always keep your .env file secure and do not share it, as it contains sensitive information.
## Troubleshooting
If you encounter any issues during the setup:
1. Check the Docker logs:
```
docker-compose logs
```
2. Ensure all required ports (8080 and 80) are available and not being used by other services.
3. Verify that all environment variables in the .env file are set correctly.
For further assistance, please refer to the project documentation or seek support through the appropriate channels.

View File

@@ -0,0 +1,33 @@
---
layout: default
title: Build from Source
parent: Advanced
nav_order: 1
---
# Build from Source
Instead of using the pre-built Docker images, you can also build the images from source yourself. This allows you to build a specific version of AliasVault and/or to make changes to the source code.
Building from source requires more resources:
- Minimum 4GB RAM (more RAM will speed up build time)
- At least 1 vCPU
- 40GB+ disk space (for dependencies and build artifacts)
- Docker installed
- Git installed
## Steps
1. Clone the repository
```bash
git clone https://github.com/lanedirt/AliasVault.git
cd AliasVault
```
2. Make the build script executable and run it. This will create the .env file, build the Docker images locally from source, and start the AliasVault containers. Follow the on-screen prompts to configure AliasVault.
```bash
chmod +x install.sh
./install.sh build
```
> **Note:** The build process can take a while depending on your hardware (5-15 minutes).
3. After the script completes, you can access AliasVault at:
- Client: `https://localhost`
- Admin: `https://localhost/admin`

View File

@@ -0,0 +1,22 @@
---
layout: default
title: Database Backup
parent: Advanced
nav_order: 2
---
# Database Backup
In order to backup the database, you can use the `install.sh` script. This script will stop all services, export the database to a file, and then restart the services.
```bash
./install.sh db-backup > backup.sql.gz
```
# Database Restore
To restore the database, you can use the `install.sh` script. This script will stop all services, drop the database, import the database from a file, and then restart the services.
```bash
./install.sh db-restore < backup.sql.gz
```

View File

@@ -0,0 +1,9 @@
---
layout: default
title: Advanced
parent: Installation Guide
nav_order: 2
---
# Advanced Installation
The following guides provide more advanced installation options for AliasVault. These options are not required for the basic installation, but may be useful for advanced users.

View File

@@ -0,0 +1,175 @@
---
layout: default
title: Manual Setup
parent: Advanced
nav_order: 3
---
# Manual Setup
If you prefer to manually set up AliasVault, this README provides step-by-step instructions. Follow these steps if you prefer to execute all statements yourself.
## Prerequisites
- Docker and Docker Compose installed on your system
- OpenSSL for generating random passwords
## Steps
1. **Create required directories**
Create the following directories in your project root:
```bash
mkdir -p certificates/ssl certificates/app database/postgres
```
2. **Create .env file**
Copy the `.env.example` file to create a new `.env` file:
```bash
cp .env.example .env
```
3. **Set HOSTNAME**
Update the .env file with your hostname (default is localhost):
```bash
HOSTNAME=localhost
```
4. **Set default ports**
Update the .env file with the ports you want to use for the AliasVault components. The values defined here are used by the docker-compose.yml file.
```bash
HTTP_PORT=80
HTTPS_PORT=443
SMTP_PORT=25
SMTP_TLS_PORT=587
```
5. **Generate and set JWT_KEY**
Generate a random 32-char string for JWT token generation:
```bash
openssl rand -base64 32
```
Add the generated key to the .env file:
```bash
JWT_KEY=your_generated_key_here
```
6. **Generate and set DATA_PROTECTION_CERT_PASS**
Generate a random password for the data protection certificate:
```bash
openssl rand -base64 32
```
Add it to the .env file:
```bash
DATA_PROTECTION_CERT_PASS=your_generated_password_here
```
7. **Configure PostgreSQL Settings**
Set the following PostgreSQL-related variables in your .env file:
```bash
# Database name (default: aliasvault)
POSTGRES_DB=aliasvault
# Database user (default: aliasvault)
POSTGRES_USER=aliasvault
# Generate a secure password for PostgreSQL
POSTGRES_PASSWORD=$(openssl rand -base64 32)
```
8. **Set PRIVATE_EMAIL_DOMAINS**
Update the .env file with allowed email domains. Use DISABLED.TLD to disable email support:
```bash
PRIVATE_EMAIL_DOMAINS=yourdomain.com,anotherdomain.com
```
Or to disable email:
```bash
PRIVATE_EMAIL_DOMAINS=DISABLED.TLD
```
9. **Set SUPPORT_EMAIL (Optional)**
Add a support email address if desired:
```bash
SUPPORT_EMAIL=support@yourdomain.com
```
10. **Generate admin password**
Build the Docker image for password hashing:
```bash
docker build -t installcli -f src/Utilities/AliasVault.InstallCli/Dockerfile .
```
Generate the password hash:
```bash
docker run --rm installcli "your_preferred_admin_password_here"
```
Add the password hash and generation timestamp to the .env file:
```bash
ADMIN_PASSWORD_HASH=<output_from_previous_command>
ADMIN_PASSWORD_GENERATED=2024-01-01T00:00:00Z
```
11. **Optional configuration**
Enable or disable public registration of new users:
```bash
PUBLIC_REGISTRATION_ENABLED=false
```
12. **Build and start Docker containers**
Build the Docker Compose stack:
```bash
docker compose -f docker-compose.yml -f docker-compose.build.yml build
```
Start the Docker Compose stack:
```bash
docker compose -f docker-compose.yml -f docker-compose.build.yml up -d
```
13. **Access AliasVault**
AliasVault should now be running. You can access it at:
- Admin Panel: https://localhost/admin
- Username: admin
- Password: [Use the password you set in step 9]
- Client Website: https://localhost/
- Create your own account from here
## Important Notes
- Make sure to save both the admin password and PostgreSQL password in a secure location.
- If you need to reset the admin password in the future, repeat step 9 and restart the Docker containers.
- Always keep your .env file secure and do not share it, as it contains sensitive information.
- The PostgreSQL data is persisted in the `database/postgres` directory.
## Troubleshooting
If you encounter any issues during the setup:
1. Check the Docker logs:
```bash
docker compose logs
```
2. Ensure all required ports (80, 443, and 5432) are available and not being used by other services.
3. Verify that all environment variables in the .env file are set correctly.
4. Check PostgreSQL container logs specifically:
```bash
docker compose logs postgres
```
For further assistance, please refer to the project documentation or seek support through the appropriate channels.

View File

@@ -0,0 +1,8 @@
---
layout: default
title: Installation Guide
nav_order: 2
---
# Installation Guide
The following guide will walk you through the steps to install AliasVault on your own server. Minimum experience with Docker and Linux is required.

View File

@@ -0,0 +1,164 @@
---
layout: default
title: Basic Install
parent: Installation Guide
nav_order: 1
---
# Basic Install
The following guide will walk you through the steps to install AliasVault on your own server. Minimum experience with Docker and Linux is required.
{: .toc }
* TOC
{:toc}
---
## 1. Basic Installation
To get AliasVault up and running quickly, run the install script to pull pre-built Docker images. The install script will also configure the .env file and start the AliasVault containers. You can get up and running in less than 5 minutes.
### Hardware requirements
- Linux VM with root access (Ubuntu or RHEL based distros recommended)
- 1 vCPU
- 1GB RAM
- 16GB disk space
- Docker installed
### Installation steps
1. Download the install script to a directory of your choice. All AliasVault files and directories will be created in this directory.
```bash
curl -o install.sh https://raw.githubusercontent.com/lanedirt/AliasVault/main/install.sh
```
2. Make the install script executable.
```bash
chmod +x install.sh
```
3. Run the install script. This will create the .env file, pull the Docker images, and start the AliasVault containers. Follow the on-screen prompts to configure AliasVault.
```bash
./install.sh install
```
> **Note**: AliasVault binds to ports 80 and 443 by default. If you want to change the default AliasVault ports you can do so in the `.env` file. Afterwards re-run the `./install.sh install` command to restart the containers with the new port settings.
3. After the script completes, you can access AliasVault at:
- Client: `https://localhost`
- Admin: `https://localhost/admin`
---
## 2. SSL configuration
The default installation will create a self-signed SSL certificate and configure Nginx to use it.
You can however also use Let's Encrypt to generate valid SSL certificates and configure Nginx to use it. In order to make this work you will need the following:
- A public IPv4 address assigned to your server
- Port 80 and 443 on your server must be open and accessible from the internet
- A registered domain name with an A record pointing to your server's public IP address (e.g. mydomain.com)
### Steps
1. Run the install script with the `configure-ssl` option
```bash
./install.sh configure-ssl
```
2. Follow the prompts to configure Let's Encrypt.
### Reverting to self-signed SSL
If at any point you would like to revert to the self-signed SSL certificate, run the install script again with the `configure-ssl` option
and then in the prompt choose option 2.
---
## 3. Email Server Setup
AliasVault includes a built-in email server that can handle multiple custom domains for your aliases.
To set up the email server, you need the following:
- Public IPv4 address
- Open ports (25 and 587) in server firewall for SMTP traffic
- Access to DNS record management for your domain
### a) DNS Configuration
Configure the following DNS records for your domain:
| Name | Type | Priority | Content | TTL |
|------|------|----------|---------------------------|-----|
| mail | A | | `<your-server-public-ip>` | 3600 |
| @ | MX | 10 | `mail.<your-domain>` | 3600 |
> Note: Replace `<your-server-public-ip>` and `<your-domain>` with your actual values.
### b) Port Configuration
The email server requires the following ports to be open:
- Port 25: Standard SMTP (unencrypted)
- Port 587: SMTP with STARTTLS (encrypted)
#### Verifying Port Access
You can test if the SMTP ports are correctly configured using telnet:
```bash
# Test standard SMTP port
telnet <your-server-public-ip> 25
# Test secure SMTP port
telnet <your-server-public-ip> 587
```
If successful, you'll see a connection establishment message. Press Ctrl+C to exit the telnet session.
### c) Setting Up Email Domains
1. Run the email configuration script:
```bash
./install.sh configure-email
````
2. Follow the interactive prompts to:
- Configure your domain(s)
- Restart required services
3. Once configured, you can:
- Create new aliases in the AliasVault client
- Use your custom domain(s) for email addresses
- Note: you can configure the default domain for new aliases in the AliasVault client in Menu > Settings > Email Settings > Default Email Domain
- Start receiving emails on your aliases
{: .note }
Important: DNS propagation can take up to 24-48 hours. During this time, email delivery might be inconsistent.
If you encounter any issues, feel free to open an issue on the [GitHub repository](https://github.com/lanedirt/AliasVault/issues).
---
## 4. Configure Account Registration
By default, AliasVault is configured to allow public registration of new accounts. This means that anyone can create a new account on your server.
If you want to disable public registration, you can do so by running the install script with the `configure-registration` option and then choosing option 2.
```bash
./install.sh configure-registration
```
> Note: disabling public registration means the ability to create new accounts in the AliasVault client is disabled for everyone, including administrators. Accounts cannot be created outside of the client because of the end-to-end encryption employed by AliasVault. So make sure you have created your own account(s) before disabling public registration.
---
## 5. Troubleshooting
### Resetting the admin password
If you have lost your admin password, you can reset it by running the install script with the `reset-password` option. This will generate a new random password and update the .env file with it. After that it will restart the AliasVault containers to apply the changes.
```bash
./install.sh reset-password
```
### Verbose output
If you need more detailed output from the install script, you can run it with the `--verbose` option. This will print more information to the console.
```bash
./install.sh install --verbose
```
### No emails being received
If you are not receiving emails on your aliases, check the following:
- Verify DNS records are correctly configured
- Ensure ports 25 and 587 are accessible
- Check your server's firewall settings
- Verify that your ISP/hosting provider allows SMTP traffic

View File

@@ -0,0 +1,30 @@
---
layout: default
title: Start/stop
parent: Installation Guide
nav_order: 2
---
# Starting and stopping AliasVault
You can start and stop AliasVault easily by using the install script.
## Stop
To stop AliasVault, run the install script with the `stop` option. This will stop all running AliasVault containers.
```bash
./install.sh stop
```
## Start
To start AliasVault, run the install script with the `start` option. This will start all AliasVault containers.
```bash
./install.sh start
```
## Restart
To restart AliasVault, run the install script with the `restart` option. This will restart all AliasVault containers.
```bash
./install.sh restart
```

View File

@@ -0,0 +1,19 @@
---
layout: default
title: Uninstall
parent: Installation Guide
nav_order: 4
---
# Uninstall
To uninstall AliasVault, run the install script with the `uninstall` option. This will stop and remove the AliasVault containers, remove the Docker images, and delete the .env file.
{: .note }
This will not delete any data stored in the database. If you wish to delete all data, you should manually delete the `database` directory and the other directories created by AliasVault.
### Steps
1. Run the install script with the `uninstall` option
```bash
./install.sh uninstall
```

View File

@@ -0,0 +1,60 @@
---
layout: default
title: Update
parent: Installation Guide
nav_order: 3
---
# Updating AliasVault
{: .no_toc }
<details open markdown="block">
<summary>
Table of contents
</summary>
{: .text-delta }
1. TOC
{:toc}
</details>
## Before You Begin
You can see the latest available version of AliasVault on [GitHub](https://github.com/lanedirt/AliasVault/releases).
{: .warning }
Before updating, it's recommended to backup your database and other important data. You can do this by making
a copy of the `database` and `certificates` directories.
## Standard Update Process
For most version updates, you can use the standard update process:
```bash
./install.sh update
```
> Tip: to skip the confirmation prompts and automatically proceed with the update, use the `-y` flag: `./install.sh update -y`
## Version-Specific Upgrade Guides
Some versions require additional steps during upgrade. If you are upgrading from an older version, please check the relevant upgrade guide below:
- [Updating to v0.10.0](v0-10-0.html) - SQLite to PostgreSQL migration
## Additional Update Options
### Updating the installer script
The installer script can check for and apply updates to itself. This is done as part of the `update` command. However you can also update the installer script separately with the `update-installer` command. This is useful if you want to update the installer script without updating AliasVault itself, e.g. as a separate step during CI/CD pipeline.
```bash
./install.sh update-installer
```
> Tip: to skip the confirmation prompts and automatically proceed with the update, use the `-y` flag: `./install.sh update-installer -y`
### Installing a specific version
To install a specific version and skip the automatic version checks, run the install script with the `install` option and specify the version you want to install. Note that downgrading is not supported officially and may lead to unexpected issues.
```bash
./install.sh install <version>
# Example:
./install.sh install 0.7.0
```

View File

@@ -0,0 +1,39 @@
---
layout: default
title: Update to v0.10.0
parent: Update
grand_parent: Installation Guide
nav_order: 1
---
# Upgrading to v0.10.0
{: .no_toc }
This guide covers the upgrade process from version < v0.10.0 to v0.10.0 or newer, which includes a one-time database migration from SQLite to PostgreSQL.
The v0.10.0 release introduces a new database backend, PostgreSQL, which replaces SQLite. This change is required because SQLite is not suitable for environments with concurrent writes that AliasVault requires.
A built-in database migration tool is included in the installer script to help you migrate your data from SQLite to PostgreSQL.
## Update Steps
1. First, backup your existing SQLite database:
```bash
cp database/AliasServerDb.sqlite database/AliasServerDb.sqlite.backup
```
2. Update AliasVault to the latest version:
```bash
./install.sh update
```
3. Run the database migration tool:
```bash
./install.sh migrate-db
```
4. After the migration has completed successfully, restart all AliasVault containers:
```bash
./install.sh restart
```
5. Test the upgrade by logging in to the admin panel and checking that your data is intact.
If you encounter any issues during the upgrade, please create an issue on the [GitHub repository](https://github.com/lanedirt/AliasVault/issues) or contact via Discord.

View File

@@ -0,0 +1,114 @@
---
layout: default
title: Contributing
parent: Development
grand_parent: Miscellaneous
nav_order: 1
---
# Contributing
This document is a work-in-progress and will be expanded as time goes on. If you have any questions feel free to open a issue on GitHub.
Note: all instructions below are based on MacOS. If you are using a different operating system, you may need to adjust the commands accordingly.
## Getting Started
In order to contribute to this project follow these instructions to setup your local environment:
### 1. Clone the repository
```bash
git clone https://github.com/lanedirt/AliasVault.git
cd AliasVault
```
### 2. Copy pre-commit hook script to .git/hooks directory
{: .note }
All commits in this repo are required to contain a reference to a GitHub issue in the format of "your commit message (#123)" where "123" references the GitHub issue number.
The pre-commit hook script below will check the commit message before allowing the commit to proceed. If the commit message is invalid, the commit will be aborted.
```bash
# Copy the commit-msg hook script to the .git/hooks directory
cp .github/hooks/commit-msg .git/hooks/commit-msg
# Make the script executable
chmod +x .git/hooks/commit-msg
```
### 3. Install the latest version of .NET SDK 9
```bash
# Install .NET SDK 9
# On MacOS via brew:
brew install --cask dotnet-sdk
# On Windows via winget
winget install Microsoft.DotNet.SDK.9
```
### 4. Install dotnet CLI EF Tools
```bash
# Install dotnet EF tools globally
dotnet tool install --global dotnet-ef
# Include dotnet tools in your PATH
nano ~/.zshrc
# Add the following line to your .zshrc file
export PATH="$PATH:$HOME/.dotnet/tools"
# Start a new terminal and test that this command works:
dotnet ef
```
### 5. Install dev database
AliasVault uses PostgreSQL as its database. In order to run the project locally from Visual Studio / Rider you will need to install the dev database. You can do this by running the following command. This will start a separate PostgreSQL instance on port 5433 accessible via the `localhost:5433` address.
```bash
./install.sh configure-dev-db
```
After the database is running you can start the project from Visual Studio / Rider in run or debug mode and it should be able to connect to the dev database.
### 6. Run Tailwind CSS compiler when changing HTML files to update compiled CSS
```bash
# For Admin project (in the admin project directory)
npm run build:admin-css
# For Client project (in the client project directory)
npm run build:client-css
```
### 7. Install Playwright in order to locally run NUnit E2E (end-to-end) tests
```bash
# First install PowerShell for Mac (if you don't have it already)
brew install powershell/tap/powershell
# Install Playwright
dotnet tool install --global Microsoft.Playwright.CLI
# Run Playwright install script to download local browsers
# Note: make sure the E2E test project has been built at least once so the bin dir exists.
pwsh src/Tests/AliasVault.E2ETests/bin/Debug/net9.0/playwright.ps1 install
```
### 8. Create AliasVault.Client appsettings.Development.json
The WASM client app supports a development specific appsettings.json file. This appsettings file is optional but can override various options to make debugging easier.
1. Copy `wwwroot/appsettings.json` to `wwwroot/appsettings.Development.json`
Here is an example file with the various options explained:
```json
{
"ApiUrl": "http://localhost:5092",
"PrivateEmailDomains": ["example.tld"],
"SupportEmail": "support@example.tld",
"UseDebugEncryptionKey": "true",
"CryptographyOverrideType" : "Argon2Id",
"CryptographyOverrideSettings" : "{\"DegreeOfParallelism\":1,\"MemorySize\":1024,\"Iterations\":1}"
}
```
- **UseDebugEncryptionKey**
- This setting will use a static encryption key so that if you login as a user you can refresh the page without needing to unlock the database again. This speeds up development when changing things in the WebApp WASM project. Note: the project needs to be run in "Development" mode for this setting to be used.
- **CryptographyOverrideType**
- This setting allows overriding the default encryption type (Argon2id) with a different encryption type. This is useful for testing different encryption types without having to change code.
- **CryptographyOverrideSettings**
- This setting allows overriding the default encryption settings (Argon2id) with different settings. This is useful for testing different encryption settings without having to change code. The default Argon2id settings are defined in the project as `Utilities/Cryptography/Cryptography.Client/Defaults.cs`. These default settings are focused on security but NOT performance. Normally for key derivation purposes the slower/heavier the algorithm the better protection against attackers. For production builds this is what we want, however in case of automated testing or debugging extra performance can be gained by tweaking (lowering) these settings.
```

View File

@@ -1,6 +1,13 @@
The webauthn implementation in order to quick unlock the vault requires the use of a FIDO2 authenticator.
---
layout: default
title: Enable WebAuthn
parent: Development
grand_parent: Miscellaneous
nav_order: 9
---
This can be either the built-in browser authenticator or an external authenticator like a Yubikey.
# WebAuthn
Webauthn allows to quick unlock the vault. This can be either the built-in browser authenticator or an external authenticator like a Yubikey.
At the time of writing (2024-10-04), only some browsers support the required PRF extension. In order to make it work in Chrome, you need to enable the PRF extension in the browser settings.
@@ -10,3 +17,4 @@ At the time of writing (2024-10-04), only some browsers support the required PRF
2. Enable the `Experimental Web Platform features` flag.
3. Restart the browser.
4. Now it should be possible to use the built-in chrome password manager to unlock the vault.
5. Go to Menu -> Security Settings -> Quick Vault Unlock and enable it.

6
docs/misc/dev/index.md Normal file
View File

@@ -0,0 +1,6 @@
---
layout: default
title: Development
parent: Miscellaneous
nav_order: 1
---

View File

@@ -0,0 +1,51 @@
---
layout: default
title: PostgreSQL Commands
parent: Development
grand_parent: Miscellaneous
nav_order: 2
---
# PostgreSQL Commands
## Backup database to file
To backup the database to a file, you can use the following command:
```bash
docker compose exec postgres pg_dump -U aliasvault aliasvault | gzip > aliasvault.sql.gz
```
## Import database from file
To drop the existing database and restore the database from a file, you can use the following command:
{: .warning }
Executing this command will drop the existing database and restore the database from the file. Make sure to have a backup of the existing database before running this command.
```bash
docker compose exec postgres psql -U aliasvault postgres -c "DROP DATABASE aliasvault;" && \
docker compose exec postgres psql -U aliasvault postgres -c "CREATE DATABASE aliasvault;" && \
gunzip < aliasvault.sql.gz | docker compose exec -iT postgres psql -U aliasvault aliasvault
```
## Change master password
By default during initial installation the PostgreSQL master password is set to a random string that is
stored in the `.env` file with the `POSTGRES_PASSWORD` variable.
If you wish to change the master password, you can do so by running the following command:
1. Open a terminal and navigate to the root of the AliasVault repository.
2. Run the following command to connect to the PostgreSQL container:
```bash
docker compose exec -it postgres psql -U aliasvault -d aliasvault
```
3. Once connected to the database, you can change the master password by running the following command:
```sql
ALTER USER aliasvault WITH PASSWORD 'new_password';
```
4. Press Enter to confirm the changes.
5. Exit the PostgreSQL shell by running `\q`.
6. Manually update the `.env` file variable `POSTGRES_PASSWORD` with the new password.
7. Restart the AliasVault containers by running the following command:
```bash
docker compose restart
```

View File

@@ -1,3 +1,11 @@
---
layout: default
title: Run GitHub Actions Locally
parent: Development
grand_parent: Miscellaneous
nav_order: 9
---
# Run GitHub Actions Locally
This guide will help you set up and run GitHub Actions locally on Linux, which can be useful for debugging and testing your workflows without pushing changes to the repository.

View File

@@ -1,3 +1,13 @@
---
layout: default
title: Upgrade the AliasClientDb EF model
parent: Development
grand_parent: Miscellaneous
nav_order: 3
---
# Upgrade the AliasClientDb EF model
To upgrade the AliasClientDb EF model, follow these steps:
1. Make changes to the AliasClientDb EF model in the `AliasClientDb` project.
@@ -9,4 +19,4 @@ To upgrade the AliasClientDb EF model, follow these steps:
dotnet ef migrations add "1.0.0-<migration-name>"
```
4. On the next login of a user, they will be prompted (required) to upgrade their database schema to the latest version.
Make sure to manually test this.
Make sure to manually test that the migration works as expected.

View File

@@ -0,0 +1,22 @@
---
layout: default
title: Upgrade the AliasServerDb EF model
parent: Development
grand_parent: Miscellaneous
nav_order: 3
---
# Upgrade the AliasServerDb EF model
The AliasServerDb EF model has migrations for both the SQLite and PostgreSQL databases. This means
that when you make changes to the EF model, you need to create migrations for both databases.
1. Make migration for PostgreSQL database:
```bash
dotnet ef migrations add InitialMigration --context AliasServerDbContextPostgresql --output-dir Migrations/PostgresqlMigrations
```
2. Make migration for SQLite database:
```bash
dotnet ef migrations add InitialMigration --context AliasServerDbContextSqlite --output-dir Migrations/SqliteMigrations
```

10
docs/misc/index.md Normal file
View File

@@ -0,0 +1,10 @@
---
layout: default
title: Miscellaneous
has_children: true
nav_order: 99
---
# Miscellaneous
Miscellaneous guides and documentation.

View File

@@ -0,0 +1,29 @@
---
layout: default
title: Create a new release
parent: Release
grand_parent: Miscellaneous
nav_order: 1
---
# Release Preparation Checklist
Follow the steps in the checklist below to prepare a new release.
## Versioning
- [ ] Update ./src/Shared/AliasVault.Shared.Core/AppInfo.cs and update major/minor/patch to the new version. This version will be shown in the client and admin app footer.
- [ ] Update ./install.sh `@version` in header if the install script has changed. This allows the install script to self-update when running the `./install.sh update` command on default installations.
- [ ] Update README.md install.sh download link to point to the new release version
## Docker Images
If docker containers have been added or removed:
- [ ] Verify that `.github/workflows/publish-docker-images.yml` contains references to all docker images that need to be published.
- [ ] Update `install.sh` and verify that the `images=()` array that takes care of pulling the images from the GitHub Container Registry is updated.
## Manual Testing (since v0.10.0+)
- [ ] Verify that the db migration from SQLite to PostgreSQL works. This needs to be tested manually until the SQLite support is removed. Test with: `./install.sh db-migrate` on an existing installation that has a SQLite database in `./database/AliasServerDb.sqlite`.
## Documentation
- [ ] Update /docs instructions if any changes have been made to the setup process
- [ ] Update README screenshots if applicable
- [ ] Update README current/upcoming features

View File

@@ -0,0 +1,6 @@
---
layout: default
title: Release
parent: Miscellaneous
nav_order: 1
---

33
entrypoint.sh Normal file
View File

@@ -0,0 +1,33 @@
#!/bin/sh
# Create SSL directory if it doesn't exist
mkdir -p /etc/nginx/ssl
# Generate self-signed SSL certificate if not exists
if [ ! -f /etc/nginx/ssl/cert.pem ] || [ ! -f /etc/nginx/ssl/key.pem ]; then
echo "Generating new SSL certificate..."
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/key.pem \
-out /etc/nginx/ssl/cert.pem \
-subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
# Set proper permissions
chmod 644 /etc/nginx/ssl/cert.pem
chmod 600 /etc/nginx/ssl/key.pem
fi
# Create the appropriate SSL configuration based on LETSENCRYPT_ENABLED
if [ "${LETSENCRYPT_ENABLED}" = "true" ]; then
cat > /etc/nginx/ssl.conf << EOF
ssl_certificate /etc/nginx/ssl-letsencrypt/live/${HOSTNAME}/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl-letsencrypt/live/${HOSTNAME}/privkey.pem;
EOF
else
cat > /etc/nginx/ssl.conf << EOF
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
EOF
fi
# Start nginx
nginx -g "daemon off;"

2382
install.sh
View File

File diff suppressed because it is too large Load Diff

100
nginx.conf Normal file
View File

@@ -0,0 +1,100 @@
events {
worker_connections 1024;
}
http {
upstream client {
server client:3000;
}
upstream api {
server api:3001;
}
upstream admin {
server admin:3002;
}
# Preserve any existing X-Forwarded-* headers, this is relevant if AliasVault
# is running behind another reverse proxy.
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Enable gzip compression, which reduces the amount of data that needs to be transferred
# to speed up WASM load times.
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
server {
listen 80;
server_name _;
# Handle ACME challenge for Let's Encrypt certificate validation
location /.well-known/acme-challenge/ {
allow all;
root /var/www/certbot;
try_files $uri =404;
default_type "text/plain";
add_header Cache-Control "no-cache";
break;
}
# Redirect all other HTTP traffic to HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name _;
# Include the appropriate SSL certificate configuration generated
# by the entrypoint script.
include /etc/nginx/ssl.conf;
# Admin interface
location /admin {
proxy_pass http://admin;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Add WebSocket support for Blazor server
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
# API endpoints
location /api {
proxy_pass http://api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Client app (root path)
location / {
proxy_pass http://client;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}

View File

@@ -1,27 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-AliasVault.Admin-1DAADE35-C01B-43BB-B440-AA5E1E0B672D</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<NoWarn>1701;1702;NU1900</NoWarn>
<LangVersion>13</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DocumentationFile>bin\Debug\net8.0\AliasVault.Admin.xml</DocumentationFile>
<DocumentationFile>bin\Debug\net9.0\AliasVault.Admin.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DocumentationFile>bin\Release\net8.0\AliasVault.Admin.xml</DocumentationFile>
<DocumentationFile>bin\Release\net9.0\AliasVault.Admin.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -45,6 +46,7 @@
<ProjectReference Include="..\Databases\AliasServerDb\AliasServerDb.csproj" />
<ProjectReference Include="..\Shared\AliasVault.RazorComponents\AliasVault.RazorComponents.csproj" />
<ProjectReference Include="..\Shared\AliasVault.Shared.Core\AliasVault.Shared.Core.csproj" />
<ProjectReference Include="..\Shared\AliasVault.Shared.Server\AliasVault.Shared.Server.csproj" />
<ProjectReference Include="..\Utilities\AliasVault.Auth\AliasVault.Auth.csproj" />
<ProjectReference Include="..\Utilities\AliasVault.Logging\AliasVault.Logging.csproj" />
<ProjectReference Include="..\Utilities\Cryptography\AliasVault.Cryptography.Server\AliasVault.Cryptography.Server.csproj" />

View File

@@ -1,9 +1,10 @@
<a href="/">
@using AliasVault.Admin.Services
@inject NavigationService NavigationService
<a href="@NavigationService.BaseUri">
<div class="text-5xl font-bold text-gray-900 dark:text-white mb-4 flex items-center">
<img src="img/logo.svg" alt="AliasVault" class="w-20 h-20 mr-2" />
<span>AliasVault</span>
<span class="ps-2 self-center hidden sm:flex text-lg font-bold whitespace-nowrap text-white bg-red-600 rounded-full px-2 py-1 ml-2">Admin</span>
</div>
</a>
</a>

View File

@@ -72,7 +72,7 @@ public class AuthBase : OwningComponentBase
// Redirect to home if the user is already authenticated
if (SignInManager.IsSignedIn(user))
{
NavigationService.RedirectTo("/");
NavigationService.RedirectTo("./");
}
}
}

View File

@@ -29,7 +29,7 @@
<div class="ml-3 text-sm">
<label for="remember" class="font-medium text-gray-900 dark:text-white">Remember me</label>
</div>
<a href="/user/forgot-password" class="ml-auto text-sm text-primary-700 hover:underline dark:text-primary-500">Lost Password?</a>
<a href="user/forgot-password" class="ml-auto text-sm text-primary-700 hover:underline dark:text-primary-500">Lost Password?</a>
</div>
<button type="submit" class="w-full px-5 py-3 text-base font-medium text-center text-white bg-primary-700 rounded-lg hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 sm:w-auto dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">Login to your account</button>
@@ -64,7 +64,6 @@
var user = await UserManager.FindByNameAsync(Input.UserName);
if (user == null)
{
await AuthLoggingService.LogAuthEventFailAsync(Input.UserName, AuthEventType.Login, AuthFailureReason.InvalidUsername);
ServerValidationErrors.AddError("Error: Invalid login attempt.");
return;
@@ -75,7 +74,7 @@
{
await AuthLoggingService.LogAuthEventSuccessAsync(Input.UserName, AuthEventType.Login);
Logger.LogInformation("User logged in.");
NavigationService.RedirectTo(ReturnUrl ?? "/");
NavigationService.RedirectTo(ReturnUrl ?? "./");
}
else if (result.RequiresTwoFactor)
{

View File

@@ -8,11 +8,13 @@
protected override async Task OnInitializedAsync()
{
// Sign out the user.
// NOTE: the try/catch below is a workaround for the issue that the sign out does not work when
// NOTE: the try/catch below is a workaround for the issue that the sign-out does not work when
// the server session is already started.
try
{
await UserService.LoadCurrentUserAsync();
var username = UserService.User().UserName;
try
{
await SignInManager.SignOutAsync();
@@ -20,12 +22,12 @@
await AuthLoggingService.LogAuthEventSuccessAsync(username!, AuthEventType.Logout);
// Redirect to the home page with hard refresh.
NavigationService.RedirectTo("/", true);
NavigationService.RedirectTo("./", true);
}
catch
{
// Hard refresh current page if sign out fails. When an interactive server session is already started
// the sign out will fail because it tries to mutate cookies which is only possible when the server
// the sign-out will fail because it tries to mutate cookies which is only possible when the server
// session is not started yet.
await AuthLoggingService.LogAuthEventSuccessAsync(username!, AuthEventType.Logout);
NavigationService.RedirectTo(NavigationService.Uri, true);
@@ -34,7 +36,7 @@
catch
{
// Redirect to the home page with hard refresh.
NavigationService.RedirectTo("/", true);
NavigationService.RedirectTo("./", true);
}
}
}

View File

@@ -16,7 +16,7 @@ public class Config
/// Gets or sets the admin password hash which is generated by install.sh and will be set
/// as the default password for the admin user.
/// </summary>
public string AdminPasswordHash { get; set; } = "false";
public string AdminPasswordHash { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the last time the password was changed. This is used to check if the

View File

@@ -1,29 +1,25 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
EXPOSE 8082
EXPOSE 3002
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG TARGETARCH
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
# Copy the project files and restore dependencies
COPY ["src/AliasVault.Admin/AliasVault.Admin.csproj", "src/AliasVault.Admin/"]
RUN dotnet restore "src/AliasVault.Admin/AliasVault.Admin.csproj"
RUN dotnet restore "src/AliasVault.Admin/AliasVault.Admin.csproj" -a "$TARGETARCH"
COPY . .
# Build the WebApi project
WORKDIR "/src/src/AliasVault.Admin"
RUN dotnet build "AliasVault.Admin.csproj" -c "$BUILD_CONFIGURATION" -o /app/build
# Publish the application to the /app/publish directory in the container
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "AliasVault.Admin.csproj" -c "$BUILD_CONFIGURATION" -o /app/publish /p:UseAppHost=false
RUN dotnet publish "AliasVault.Admin.csproj" -c "$BUILD_CONFIGURATION" \
-a "$TARGETARCH" \
-o /app/publish \
/p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
EXPOSE 8082
ENV ASPNETCORE_URLS=http://+:8082
COPY --from=build /app/publish .
ENV ASPNETCORE_URLS=http://+:3002
ENV ASPNETCORE_PATHBASE=/admin
ENTRYPOINT ["dotnet", "AliasVault.Admin.dll"]

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"/>
<base href="/"/>
<base href="@NavigationService.BaseUri"/>
<link rel="stylesheet" href="@VersionService.GetVersionedPath("css/tailwind.css")"/>
<link rel="stylesheet" href="@VersionService.GetVersionedPath("css/app.css")"/>
<link rel="stylesheet" href="AliasVault.Admin.styles.css"/>

View File

@@ -0,0 +1,268 @@
@using AliasVault.WorkerStatus.Database
@inherits MainBase
@foreach (var service in Services)
{
<button @onclick="() => ServiceClick(service.Name)"
class="@GetServiceButtonClasses(service) mx-3 inline-flex items-center justify-center rounded-xl px-8 py-2 text-white"
disabled="@(!service.IsHeartBeatValid)"
title="@GetButtonTooltip(service)">
<span>@service.DisplayName</span>
@if (service.IsHeartBeatValid && service.CurrentStatus != service.DesiredStatus && !string.IsNullOrEmpty(service.DesiredStatus))
{
<svg class="animate-spin ml-2 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
}
</button>
}
@code {
/// <summary>
/// The names of the services to display.
/// </summary>
[Parameter]
public List<string> ServiceNames { get; set; } = ["AliasVault.SmtpService", "AliasVault.TaskRunner"];
/// <summary>
/// The display names of the services to display.
/// </summary>
[Parameter]
public Dictionary<string, string> ServiceDisplayNames { get; set; } = new();
/// <summary>
/// The statuses of the services.
/// </summary>
private List<WorkerServiceStatus> ServiceStatus = [];
/// <summary>
/// Whether the page is initializing.
/// </summary>
private bool InitInProgress;
/// <summary>
/// The interval to refresh the page.
/// </summary>
private readonly int AutoRefreshInterval = 5000;
private CancellationTokenSource? _timerCancellationTokenSource;
/// <summary>
/// The state of a service.
/// </summary>
private sealed class ServiceState
{
public string Name { get; set; } = "";
public string DisplayName { get; set; } = "";
public string CurrentStatus { get; set; } = "";
public string DesiredStatus { get; set; } = "";
public bool IsHeartBeatValid { get; set; }
}
private List<ServiceState> Services { get; set; } = [];
/// <inheritdoc />
protected override async Task OnInitializedAsync()
{
Services = ServiceNames.Select(name => new ServiceState
{
Name = name,
DisplayName = ServiceDisplayNames.GetValueOrDefault(name, name)
}).ToList();
await base.OnInitializedAsync();
}
/// <inheritdoc />
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
_timerCancellationTokenSource = new CancellationTokenSource();
_ = RunPeriodicRefreshAsync(_timerCancellationTokenSource.Token);
}
}
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_timerCancellationTokenSource?.Cancel();
_timerCancellationTokenSource?.Dispose();
}
}
/// <summary>
/// Checks if the heartbeat is valid (within the last 5 minutes).
/// </summary>
private static bool IsHeartbeatValid(DateTime lastHeartbeat)
{
return DateTime.UtcNow <= lastHeartbeat.AddMinutes(5);
}
/// <summary>
/// Gets the CSS classes for a service button based on its current state.
/// </summary>
private static string GetServiceButtonClasses(ServiceState service)
{
string buttonClass = "cursor-pointer ";
if (!service.IsHeartBeatValid)
{
buttonClass += "bg-gray-600";
}
else if (service.CurrentStatus == "Started" && (service.DesiredStatus == string.Empty || service.DesiredStatus == "Started"))
{
buttonClass += "bg-green-600";
}
else if (service.CurrentStatus == "Stopping" || (service.DesiredStatus == "Stopped" && service.CurrentStatus != service.DesiredStatus))
{
buttonClass += "bg-red-500";
}
else if (service.CurrentStatus == "Starting" || (service.DesiredStatus == "Started" && service.CurrentStatus != service.DesiredStatus))
{
buttonClass += "bg-emerald-500";
}
else if (service.DesiredStatus == "Stopped" && (service.DesiredStatus == string.Empty || service.DesiredStatus == "Stopped"))
{
buttonClass += "bg-red-600";
}
return buttonClass;
}
/// <summary>
/// Gets the tooltip text for a service button based on its last heartbeat.
/// </summary>
private static string GetButtonTooltip(ServiceState service)
{
if (!service.IsHeartBeatValid)
{
return "Heartbeat offline";
}
var statusMessages = new Dictionary<string, string>
{
{ "Started", "Service is running" },
{ "Starting", "Service is starting..." },
{ "Stopped", "Service is stopped" },
{ "Stopping", "Service is stopping..." }
};
return statusMessages.GetValueOrDefault(service.CurrentStatus, string.Empty);
}
/// <summary>
/// Handles a click on a service button.
/// </summary>
private async Task ServiceClick(string serviceName)
{
var service = Services.First(s => s.Name == serviceName);
if (!service.IsHeartBeatValid)
{
return;
}
// If service not started and not starting, clicking should start it. Otherwise, stop it.
if (service.CurrentStatus == "Started" || service.DesiredStatus == "Started")
{
service.DesiredStatus = "Stopped";
}
else
{
service.DesiredStatus = "Started";
}
StateHasChanged();
await UpdateServiceStatus(serviceName, service.DesiredStatus);
service.CurrentStatus = service.DesiredStatus;
StateHasChanged();
}
/// <summary>
/// Initializes the page.
/// </summary>
private async Task InitPage()
{
if (InitInProgress)
{
return;
}
try
{
InitInProgress = true;
await using var dbContext = await DbContextFactory.CreateDbContextAsync();
ServiceStatus = await dbContext.WorkerServiceStatuses.ToListAsync();
foreach (var service in Services)
{
var entry = ServiceStatus.Find(x => x.ServiceName == service.Name);
if (entry != null)
{
service.IsHeartBeatValid = IsHeartbeatValid(entry.Heartbeat);
service.CurrentStatus = entry.CurrentStatus;
service.DesiredStatus = entry.DesiredStatus;
}
}
await InvokeAsync(StateHasChanged);
}
finally
{
InitInProgress = false;
}
}
/// <summary>
/// Updates the status of a service.
/// </summary>
private async Task<bool> UpdateServiceStatus(string serviceName, string desiredStatus)
{
await using var dbContext = await DbContextFactory.CreateDbContextAsync();
var entry = await dbContext.WorkerServiceStatuses.Where(x => x.ServiceName == serviceName).FirstOrDefaultAsync();
if (entry != null)
{
entry.DesiredStatus = desiredStatus;
await dbContext.SaveChangesAsync();
var timeout = DateTime.UtcNow.AddSeconds(30);
while (true)
{
if (DateTime.UtcNow > timeout)
{
return false;
}
await using var dbContextInner = await DbContextFactory.CreateDbContextAsync();
var check = await dbContextInner.WorkerServiceStatuses.Where(x => x.ServiceName == serviceName).FirstAsync();
if (check.CurrentStatus == entry.DesiredStatus)
{
return true;
}
await Task.Delay(1000);
}
}
return false;
}
/// <summary>
/// Refreshes the service status periodically.
/// </summary>
private async Task RunPeriodicRefreshAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await InitPage();
await Task.Delay(AutoRefreshInterval, cancellationToken);
}
}
}

View File

@@ -1,209 +0,0 @@
@using AliasVault.WorkerStatus.Database
@inherits MainBase
<button @onclick="SmtpClick"
class="@GetSmtpButtonClasses() mx-3 inline-flex items-center justify-center rounded-xl px-8 py-2 text-white"
disabled="@(!IsHeartbeatValid())"
title="@GetButtonTooltip()">
<span>SmtpService</span>
@if (SmtpPending)
{
<svg class="animate-spin ml-2 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
}
</button>
@code {
private List<WorkerServiceStatus> ServiceStatus = [];
private bool InitInProgress;
private bool SmtpStatus;
private bool SmtpPending;
private DateTime LastHeartbeat;
/// <summary>
/// The interval in milliseconds for refreshing the service status.
/// </summary>
private readonly int AutoRefreshInterval = 5000;
/// <summary>
/// CancellationTokenSource for the timer.
/// </summary>
private CancellationTokenSource? _timerCancellationTokenSource;
/// <inheritdoc />
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
_timerCancellationTokenSource = new CancellationTokenSource();
_ = RunPeriodicRefreshAsync(_timerCancellationTokenSource.Token);
}
}
/// <summary>
/// Refreshes the service status periodically while waiting for specified amount of ms in between.
/// </summary>
private async Task RunPeriodicRefreshAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await InitPage();
await Task.Delay(AutoRefreshInterval, cancellationToken);
}
}
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_timerCancellationTokenSource?.Cancel();
_timerCancellationTokenSource?.Dispose();
}
}
/// <summary>
/// Gets the CSS classes for the SMTP button based on its current state.
/// </summary>
/// <returns>A string containing the CSS classes for the button.</returns>
private string GetSmtpButtonClasses()
{
string buttonClass = "cursor-pointer ";
if (!IsHeartbeatValid())
{
buttonClass += "bg-gray-600";
}
else if (SmtpStatus)
{
buttonClass += "bg-green-600";
}
else
{
buttonClass += "bg-red-600";
}
return buttonClass;
}
/// <summary>
/// Gets the tooltip text for the SMTP button.
/// </summary>
/// <returns>A string containing the tooltip text.</returns>
private string GetButtonTooltip()
{
return IsHeartbeatValid() ? "" : "Heartbeat offline";
}
/// <summary>
/// Checks if the heartbeat is valid (within the last 5 minutes).
/// </summary>
/// <returns>True if the heartbeat is valid, false otherwise.</returns>
private bool IsHeartbeatValid()
{
return DateTime.Now <= LastHeartbeat.AddMinutes(5);
}
/// <summary>
/// Handles the click event for the SMTP button.
/// </summary>
private async void SmtpClick()
{
if (!IsHeartbeatValid())
{
return;
}
SmtpPending = true;
StateHasChanged();
SmtpStatus = !SmtpStatus;
await UpdateSmtpStatus(SmtpStatus);
SmtpPending = false;
StateHasChanged();
}
/// <summary>
/// Initializes the page by fetching service statuses and updating the SMTP status.
/// </summary>
private async Task InitPage()
{
if (InitInProgress || SmtpPending)
{
return;
}
try
{
InitInProgress = true;
var dbContext = await DbContextFactory.CreateDbContextAsync();
ServiceStatus = await dbContext.WorkerServiceStatuses.ToListAsync();
var smtpEntry = ServiceStatus.Find(x => x.ServiceName == "AliasVault.SmtpService");
if (smtpEntry != null)
{
LastHeartbeat = smtpEntry.Heartbeat;
SmtpStatus = IsHeartbeatValid() && smtpEntry.CurrentStatus == "Started";
}
await InvokeAsync(StateHasChanged);
}
finally
{
InitInProgress = false;
}
}
/// <summary>
/// Update the service statuses.
/// </summary>
public async Task<bool> UpdateServiceStatus(string serviceName, bool newStatus)
{
// Refresh the DbContext to ensure we get the latest data.
var dbContext = await DbContextFactory.CreateDbContextAsync();
var entry = await dbContext.WorkerServiceStatuses.Where(x => x.ServiceName == serviceName).FirstOrDefaultAsync();
if (entry != null)
{
string newDesiredStatus = newStatus ? "Started" : "Stopped";
entry.DesiredStatus = newDesiredStatus;
await dbContext.SaveChangesAsync();
// Wait for service to have updated its status.
var timeout = DateTime.Now.AddSeconds(30);
while (true)
{
if (DateTime.Now > timeout)
{
// Timeout
return false;
}
dbContext = await DbContextFactory.CreateDbContextAsync();
var check = await dbContext.WorkerServiceStatuses.Where(x => x.ServiceName == serviceName).FirstAsync();
if (check.CurrentStatus == newDesiredStatus)
{
// Done
return true;
}
await Task.Delay(1000);
}
}
return false;
}
/// <summary>
/// Update the SMTP service status.
/// </summary>
public async Task<bool> UpdateSmtpStatus(bool newStatus)
{
return await UpdateServiceStatus("AliasVault.SmtpService", newStatus);
}
}

View File

@@ -3,9 +3,9 @@
<header>
<nav class="fixed z-30 w-full border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700 py-3 px-4 bg-primary-100">
<div class="flex justify-between items-center max-w-screen-2xl mx-auto">
<div class="flex justify-between items-center max-w-screen-2xl mx-auto relative">
<div class="flex justify-start items-center">
<a href="/" class="flex mr-14 flex-shrink-0">
<a href="@NavigationService.BaseUri" class="flex mr-14 flex-shrink-0">
<img src="/img/logo.svg" class="mr-3 h-8" alt="AliasVault Logo">
<span class="self-center hidden sm:flex text-2xl font-semibold whitespace-nowrap dark:text-white">AliasVault</span>
<span class="ps-2 self-center hidden sm:flex text-sm font-bold whitespace-nowrap text-white bg-red-600 rounded-full px-2 py-1 ml-2">Admin</span>
@@ -13,24 +13,32 @@
<div class="hidden justify-between items-center w-full lg:flex lg:w-auto lg:order-1">
<ul class="flex flex-col mt-4 space-x-6 text-sm font-medium lg:flex-row xl:space-x-8 lg:mt-0">
<NavLink href="/users" class="block text-gray-700 hover:text-primary-700 dark:text-gray-400 dark:hover:text-white" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
<NavLink href="users" class="block text-gray-700 hover:text-primary-700 dark:text-gray-400 dark:hover:text-white" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
Users
</NavLink>
<NavLink href="/emails" class="block text-gray-700 hover:text-primary-700 dark:text-gray-400 dark:hover:text-white" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
<NavLink href="emails" class="block text-gray-700 hover:text-primary-700 dark:text-gray-400 dark:hover:text-white" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
Emails
</NavLink>
<NavLink href="/logging/general" class="block text-gray-700 hover:text-primary-700 dark:text-gray-400 dark:hover:text-white" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
<NavLink href="logging/general" class="block text-gray-700 hover:text-primary-700 dark:text-gray-400 dark:hover:text-white" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
General logs
</NavLink>
<NavLink href="/logging/auth" class="block text-gray-700 hover:text-primary-700 dark:text-gray-400 dark:hover:text-white" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
<NavLink href="logging/auth" class="block text-gray-700 hover:text-primary-700 dark:text-gray-400 dark:hover:text-white" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
Auth logs
</NavLink>
<NavLink href="settings/server" class="block text-gray-700 hover:text-primary-700 dark:text-gray-400 dark:hover:text-white" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
Server settings
</NavLink>
</ul>
</div>
</div>
<div class="flex justify-end items-center lg:order-2">
<Services />
<button id="theme-toggle" data-tooltip-target="tooltip-toggle" type="button" class="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5">
<ServiceControl ServiceNames="@(new List<string> { "AliasVault.SmtpService", "AliasVault.TaskRunner" })"
ServiceDisplayNames="@(new Dictionary<string, string>
{
{ "AliasVault.SmtpService", "Smtp" },
{ "AliasVault.TaskRunner", "Tasks" }
})" />
<button id="theme-toggle" data-tooltip-target="tooltip-toggle" type="button" class="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5">
<svg id="theme-toggle-dark-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path></svg>
<svg id="theme-toggle-light-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" fill-rule="evenodd" clip-rule="evenodd"></path></svg>
</button>
@@ -46,18 +54,18 @@
@if (isMenuOpen)
{
<div class="absolute top-10 right-0 z-50 my-4 w-56 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700 dark:divide-gray-600" id="userMenuDropdown" data-popper-placement="bottom">
<div class="absolute top-[38px] right-0 z-50 my-4 w-56 text-base list-none bg-white rounded-b-lg divide-y divide-gray-100 shadow dark:bg-gray-700 dark:divide-gray-600" id="userMenuDropdown" data-popper-placement="bottom">
<div class="py-3 px-4">
<span class="block text-sm font-semibold text-gray-900 dark:text-white">@_username</span>
</div>
<ul class="py-1 font-light text-gray-500 dark:text-gray-400" aria-labelledby="userMenuDropdownButton">
<li>
<a href="account/manage" class="block py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-400 dark:hover:text-white">Account settings</a>
<a href="account/manage/change-password" class="block py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-400 dark:hover:text-white">Account settings</a>
</li>
</ul>
<ul class="py-1 font-light text-gray-500 dark:text-gray-400" aria-labelledby="dropdown">
<li>
<a href="/user/logout" class="block py-2 px-4 font-bold text-sm text-primary-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-primary-200 dark:hover:text-white">Sign out</a>
<a href="user/logout" class="block py-2 px-4 font-bold text-sm text-primary-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-primary-200 dark:hover:text-white">Sign out</a>
</li>
</ul>
</div>
@@ -75,30 +83,35 @@
<nav class="bg-white dark:bg-gray-900">
<ul id="mobileMenu" class="flex-col mt-0 pt-16 w-full text-sm font-medium lg:hidden">
<li class="block border-b dark:border-gray-700">
<NavLink href="/" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
<NavLink href="./" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
Home
</NavLink>
</li>
<li class="block border-b dark:border-gray-700">
<NavLink href="/users" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
<NavLink href="users" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
Users
</NavLink>
</li>
<li class="block border-b dark:border-gray-700">
<NavLink href="/emails" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
<NavLink href="emails" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
Emails
</NavLink>
</li>
<li class="block border-b dark:border-gray-700">
<NavLink href="/logging/general" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
<NavLink href="logging/general" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
General logs
</NavLink>
</li>
<li class="block border-b dark:border-gray-700">
<NavLink href="/logging/auth" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
<NavLink href="logging/auth" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
Auth logs
</NavLink>
</li>
<li class="block border-b dark:border-gray-700">
<NavLink href="settings/server" class="block py-3 px-4 text-gray-900 lg:py-0 dark:text-white lg:hover:underline lg:px-0" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">
Server settings
</NavLink>
</li>
</ul>
</nav>
}

View File

@@ -0,0 +1,49 @@
//-----------------------------------------------------------------------
// <copyright file="UserEmailClaimWithCount.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasVault.Admin.Main.Models;
/// <summary>
/// User email claim view model with count.
/// </summary>
public class UserEmailClaimWithCount
{
/// <summary>
/// Gets or sets the id.
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// Gets or sets the address.
/// </summary>
public string Address { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the address local.
/// </summary>
public string AddressLocal { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the address domain.
/// </summary>
public string AddressDomain { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the created at timestamp.
/// </summary>
public DateTime CreatedAt { get; set; }
/// <summary>
/// Gets or sets the updated at timestamp.
/// </summary>
public DateTime UpdatedAt { get; set; }
/// <summary>
/// Gets or sets the email count.
/// </summary>
public int EmailCount { get; set; }
}

View File

@@ -32,6 +32,11 @@ public class UserViewModel
/// </summary>
public bool TwoFactorEnabled { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the user is blocked.
/// </summary>
public bool Blocked { get; set; }
/// <summary>
/// Gets or sets the vault count.
/// </summary>

View File

@@ -2,13 +2,12 @@
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Identity
@inject UserManager<AdminUser> UserManager
@inject ILogger<ChangePassword> Logger
<LayoutPageTitle>Change password</LayoutPageTitle>
<div class="max-w-2xl mx-auto">
<div class="p-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-6">Change password</h3>
<EditForm Model="Input" FormName="change-password" OnValidSubmit="OnValidSubmitAsync" method="post" class="space-y-6">
<DataAnnotationsValidator/>
@@ -41,15 +40,13 @@
private async Task OnValidSubmitAsync()
{
var changePasswordResult = await UserManager.ChangePasswordAsync(UserService.User(), Input.OldPassword, Input.NewPassword);
var user = UserService.User();
user.LastPasswordChanged = DateTime.UtcNow;
await UserService.UpdateUserAsync(user);
var user = await UserManager.FindByIdAsync(UserService.User().Id);
if (user == null)
{
throw new InvalidOperationException("User not found.");
}
// Clear the password fields
Input.OldPassword = "";
Input.NewPassword = "";
Input.ConfirmPassword = "";
var changePasswordResult = await UserManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword);
if (!changePasswordResult.Succeeded)
{
@@ -57,10 +54,15 @@
return;
}
user.LastPasswordChanged = DateTime.UtcNow;
await UserManager.UpdateAsync(user);
Input.OldPassword = "";
Input.NewPassword = "";
Input.ConfirmPassword = "";
Logger.LogInformation("User changed their password successfully.");
GlobalNotificationService.AddSuccessMessage("Your password has been changed.");
NavigationService.RedirectToCurrentPage();
}
@@ -82,5 +84,4 @@
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; } = "";
}
}

View File

@@ -31,7 +31,13 @@
/// <inheritdoc />
protected override async Task OnInitializedAsync()
{
if (!await UserManager.GetTwoFactorEnabledAsync(UserService.User()))
var user = await UserManager.FindByIdAsync(UserService.User().Id);
if (user == null)
{
throw new InvalidOperationException("User not found.");
}
if (!await UserManager.GetTwoFactorEnabledAsync(user))
{
throw new InvalidOperationException("Cannot disable 2FA for user as it's not currently enabled.");
}
@@ -39,7 +45,13 @@
private async Task OnSubmitAsync()
{
var disable2FaResult = await UserManager.SetTwoFactorEnabledAsync(UserService.User(), false);
var user = await UserManager.FindByIdAsync(UserService.User().Id);
if (user == null)
{
throw new InvalidOperationException("User not found.");
}
var disable2FaResult = await UserManager.SetTwoFactorEnabledAsync(user, false);
if (!disable2FaResult.Succeeded)
{
await AuthLoggingService.LogAuthEventFailAsync(UserService.User().UserName!, AuthEventType.TwoFactorAuthDisable, AuthFailureReason.Unknown);

View File

@@ -13,6 +13,12 @@
<LayoutPageTitle>Configure authenticator app</LayoutPageTitle>
@if (_isLoading)
{
<LoadingIndicator />
return;
}
@if (RecoveryCodes is not null)
{
<ShowRecoveryCodes RecoveryCodes="RecoveryCodes.ToArray()"/>
@@ -69,15 +75,20 @@ else
private string? SharedKey { get; set; }
private string? AuthenticatorUri { get; set; }
private IEnumerable<string>? RecoveryCodes { get; set; }
private bool _isLoading = true;
[SupplyParameterFromForm] private InputModel Input { get; set; } = new();
/// <inheritdoc />
protected override async Task OnInitializedAsync()
/// <inheritdoc/>
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnInitializedAsync();
await LoadSharedKeyAndQrCodeUriAsync(UserService.User());
await JsInvokeService.RetryInvokeAsync("generateQrCode", TimeSpan.Zero, 5, "authenticator-uri");
if (firstRender)
{
await LoadSharedKeyAndQrCodeUriAsync();
_isLoading = false;
StateHasChanged();
await JsInvokeService.RetryInvokeAsync("generateQrCode", TimeSpan.Zero, 5, "authenticator-uri");
}
}
private async Task OnValidSubmitAsync()
@@ -85,8 +96,13 @@ else
// Strip spaces and hyphens
var verificationCode = Input.Code.Replace(" ", string.Empty).Replace("-", string.Empty);
var is2FaTokenValid = await UserManager.VerifyTwoFactorTokenAsync(
UserService.User(), UserManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode);
var user = await UserManager.FindByIdAsync(UserService.User().Id);
if (user == null)
{
throw new InvalidOperationException("User not found.");
}
var is2FaTokenValid = await UserManager.VerifyTwoFactorTokenAsync(user, UserManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode);
if (!is2FaTokenValid)
{
@@ -94,25 +110,31 @@ else
return;
}
await UserManager.SetTwoFactorEnabledAsync(UserService.User(), true);
await UserManager.SetTwoFactorEnabledAsync(user, true);
await AuthLoggingService.LogAuthEventSuccessAsync(UserService.User().UserName!, AuthEventType.TwoFactorAuthEnable);
Logger.LogInformation("User with ID '{UserId}' has enabled 2FA with an authenticator app.", UserService.User().Id);
GlobalNotificationService.AddSuccessMessage("Your authenticator app has been verified.");
if (await UserManager.CountRecoveryCodesAsync(UserService.User()) == 0)
if (await UserManager.CountRecoveryCodesAsync(user) == 0)
{
RecoveryCodes = await UserManager.GenerateNewTwoFactorRecoveryCodesAsync(UserService.User(), 10);
RecoveryCodes = await UserManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
}
else
{
// Navigate back to the two factor authentication page.
// Navigate back to the two-factor authentication page.
NavigationService.RedirectTo("account/manage/2fa", forceLoad: true);
}
}
private async ValueTask LoadSharedKeyAndQrCodeUriAsync(AdminUser user)
private async ValueTask LoadSharedKeyAndQrCodeUriAsync()
{
// Load the authenticator key & QR code URI to display on the form
var user = await UserManager.FindByIdAsync(UserService.User().Id);
if (user == null)
{
throw new InvalidOperationException("User not found.");
}
// Load the authenticator key & QR code URI to display on the form.
var unformattedKey = await UserManager.GetAuthenticatorKeyAsync(user);
if (string.IsNullOrEmpty(unformattedKey))
{
@@ -126,7 +148,7 @@ else
AuthenticatorUri = GenerateQrCodeUri(username!, unformattedKey!);
}
private string FormatKey(string unformattedKey)
private static string FormatKey(string unformattedKey)
{
var result = new StringBuilder();
int currentPosition = 0;

View File

@@ -7,9 +7,9 @@
<LayoutPageTitle>Generate two-factor authentication (2FA) recovery codes</LayoutPageTitle>
@if (recoveryCodes is not null)
@if (_recoveryCodes is not null)
{
<ShowRecoveryCodes RecoveryCodes="recoveryCodes.ToArray()"/>
<ShowRecoveryCodes RecoveryCodes="_recoveryCodes.ToArray()"/>
}
else
{
@@ -35,14 +35,20 @@ else
}
@code {
private IEnumerable<string>? recoveryCodes;
private IEnumerable<string>? _recoveryCodes;
/// <inheritdoc />
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
var isTwoFactorEnabled = await UserManager.GetTwoFactorEnabledAsync(UserService.User());
var user = await UserManager.FindByIdAsync(UserService.User().Id);
if (user == null)
{
throw new InvalidOperationException("User not found.");
}
var isTwoFactorEnabled = await UserManager.GetTwoFactorEnabledAsync(user);
if (!isTwoFactorEnabled)
{
throw new InvalidOperationException("Cannot generate recovery codes for user because they do not have 2FA enabled.");
@@ -51,11 +57,16 @@ else
private async Task GenerateCodes()
{
var userId = await UserManager.GetUserIdAsync(UserService.User());
recoveryCodes = await UserManager.GenerateNewTwoFactorRecoveryCodesAsync(UserService.User(), 10);
var user = await UserManager.FindByIdAsync(UserService.User().Id);
if (user == null)
{
throw new InvalidOperationException("User not found.");
}
_recoveryCodes = await UserManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
GlobalNotificationService.AddSuccessMessage("You have generated new recovery codes.");
Logger.LogInformation("User with ID '{UserId}' has generated new 2FA recovery codes.", userId);
Logger.LogInformation("User with ID '{UserId}' has generated new 2FA recovery codes.", UserService.User().Id);
}
}

View File

@@ -1,67 +0,0 @@
@page "/account/manage"
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Identity
@inject UserManager<AdminUser> UserManager
<LayoutPageTitle>Profile</LayoutPageTitle>
<div class="max-w-2xl mx-auto">
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-6">Profile</h3>
<EditForm Model="Input" FormName="profile" OnValidSubmit="OnValidSubmitAsync" class="space-y-6">
<DataAnnotationsValidator/>
<ValidationSummary class="text-red-600 dark:text-red-400" role="alert"/>
<div>
<label for="username" class="block mb-2 text-sm font-medium text-gray-700 dark:text-gray-200">Username</label>
<input type="text" value="@username" id="username" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 bg-gray-100 cursor-not-allowed dark:bg-gray-700 dark:border-gray-600 dark:text-gray-400" placeholder="Please choose your username." disabled/>
</div>
<div>
<label for="phone-number" class="block mb-2 text-sm font-medium text-gray-700 dark:text-gray-200">Phone number</label>
<InputText @bind-Value="Input.PhoneNumber" id="phone-number" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white" placeholder="Please enter your phone number."/>
<ValidationMessage For="() => Input.PhoneNumber" class="mt-1 text-sm text-red-600 dark:text-red-400"/>
</div>
<div>
<SubmitButton>Save</SubmitButton>
</div>
</EditForm>
</div>
@code {
private string? username;
private string? phoneNumber;
[SupplyParameterFromForm] private InputModel Input { get; set; } = new();
/// <inheritdoc />
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
username = await UserManager.GetUserNameAsync(UserService.User());
phoneNumber = await UserManager.GetPhoneNumberAsync(UserService.User());
Input.PhoneNumber ??= phoneNumber;
}
private async Task OnValidSubmitAsync()
{
if (Input.PhoneNumber != phoneNumber)
{
var setPhoneResult = await UserManager.SetPhoneNumberAsync(UserService.User(), Input.PhoneNumber);
if (!setPhoneResult.Succeeded)
{
GlobalNotificationService.AddErrorMessage("Phone number could not be set", true);
}
}
GlobalNotificationService.AddSuccessMessage("Your profile has been updated", true);
}
private sealed class InputModel
{
[Phone]
[Display(Name = "Phone number")]
public string? PhoneNumber { get; set; }
}
}

View File

@@ -30,15 +30,19 @@
@code {
private async Task OnSubmitAsync()
{
await UserManager.SetTwoFactorEnabledAsync(UserService.User(), false);
await UserManager.ResetAuthenticatorKeyAsync(UserService.User());
var userId = await UserManager.GetUserIdAsync(UserService.User());
Logger.LogInformation("User with ID '{UserId}' has reset their authentication app key.", userId);
var user = await UserManager.FindByIdAsync(UserService.User().Id);
if (user == null)
{
throw new InvalidOperationException("User not found.");
}
await UserManager.SetTwoFactorEnabledAsync(user, false);
await UserManager.ResetAuthenticatorKeyAsync(user);
Logger.LogInformation("User with ID '{UserId}' has reset their authentication app key.", UserService.User().Id);
GlobalNotificationService.AddSuccessMessage("Your authenticator app key has been reset, you will need to re-configure your authenticator app using the new key.");
NavigationService.RedirectTo(
"account/manage/2fa");
NavigationService.RedirectTo("account/manage/2fa");
}
}

View File

@@ -1,35 +1,33 @@
@page "/account/manage/2fa"
@using Microsoft.AspNetCore.Identity
@inject UserManager<AdminUser> UserManager
@inject SignInManager<AdminUser> SignInManager
<LayoutPageTitle>Two-factor authentication (2FA)</LayoutPageTitle>
@if (is2FaEnabled)
@if (_is2FaEnabled)
{
<div class="mx-auto mt-8 p-6 bg-white dark:bg-gray-800 rounded-lg shadow-md">
<div class="p-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-4">Two-factor authentication (2FA)</h3>
@if (recoveryCodesLeft == 0)
@if (_recoveryCodesLeft == 0)
{
<div class="mb-4 p-4 bg-red-100 border-l-4 border-red-500 text-red-700 dark:bg-red-900 dark:text-red-100">
<p class="font-bold">You have no recovery codes left.</p>
<p>You must <a href="account/manage/generate-recovery-codes" class="text-red-800 dark:text-red-200 underline">generate a new set of recovery codes</a> before you can log in with a recovery code.</p>
</div>
}
else if (recoveryCodesLeft == 1)
else if (_recoveryCodesLeft == 1)
{
<div class="mb-4 p-4 bg-red-100 border-l-4 border-red-500 text-red-700 dark:bg-red-900 dark:text-red-100">
<p class="font-bold">You have 1 recovery code left.</p>
<p>You can <a href="account/manage/generate-recovery-codes" class="text-red-800 dark:text-red-200 underline">generate a new set of recovery codes</a>.</p>
</div>
}
else if (recoveryCodesLeft <= 3)
else if (_recoveryCodesLeft <= 3)
{
<div class="mb-4 p-4 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-100">
<p class="font-bold">You have @recoveryCodesLeft recovery codes left.</p>
<p class="font-bold">You have @_recoveryCodesLeft recovery codes left.</p>
<p>You should <a href="account/manage/generate-recovery-codes" class="text-yellow-800 dark:text-yellow-200 underline">generate a new set of recovery codes</a>.</p>
</div>
}
@@ -41,10 +39,10 @@
</div>
}
<div class="mt-6 p-4 bg-gray-100 dark:bg-gray-700 rounded-lg">
<div class="p-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<h4 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Authenticator app</h4>
<div class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-2">
@if (!hasAuthenticator)
@if (!_hasAuthenticator)
{
<LinkButton Href="account/manage/enable-authenticator" Color="primary" Text="Add authenticator app" />
}
@@ -57,17 +55,23 @@
</div>
@code {
private bool hasAuthenticator;
private int recoveryCodesLeft;
private bool is2FaEnabled;
private bool _hasAuthenticator;
private int _recoveryCodesLeft;
private bool _is2FaEnabled;
/// <inheritdoc />
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
hasAuthenticator = await UserManager.GetAuthenticatorKeyAsync(UserService.User()) is not null;
is2FaEnabled = await UserManager.GetTwoFactorEnabledAsync(UserService.User());
recoveryCodesLeft = await UserManager.CountRecoveryCodesAsync(UserService.User());
var user = await UserManager.FindByIdAsync(UserService.User().Id);
if (user == null)
{
throw new InvalidOperationException("User not found.");
}
_hasAuthenticator = await UserManager.GetAuthenticatorKeyAsync(user) is not null;
_is2FaEnabled = await UserManager.GetTwoFactorEnabledAsync(user);
_recoveryCodesLeft = await UserManager.CountRecoveryCodesAsync(user);
}
}

View File

@@ -5,11 +5,10 @@
<PageHeader
BreadcrumbItems="@BreadcrumbItems"
Title="Manage account"
Description="Manage your profile here.">
Description="Manage security settings for the admin account here.">
</PageHeader>
<div class="container mx-auto px-4 py-8">
<hr class="mb-6 border-t border-gray-300"/>
<div class="mx-auto px-4 py-8">
<div class="flex flex-col md:flex-row">
<div class="w-full md:w-1/4 mb-6 md:mb-0">
<ManageNavMenu/>

View File

@@ -4,12 +4,9 @@
<ul class="flex flex-col space-y-1">
<li>
<NavLink href="account/manage" Match="NavLinkMatch.All" class="block px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white transition-colors duration-150">Profile</NavLink>
<NavLink href="account/manage/change-password" class="block px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white transition-colors duration-150" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">Password</NavLink>
</li>
<li>
<NavLink href="account/manage/change-password" class="block px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white transition-colors duration-150">Password</NavLink>
</li>
<li>
<NavLink href="account/manage/2fa" class="block px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white transition-colors duration-150">Two-factor authentication</NavLink>
<NavLink href="account/manage/2fa" class="block px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white transition-colors duration-150" ActiveClass="text-primary-700 dark:text-primary-500" Match="NavLinkMatch.All">Two-factor authentication</NavLink>
</li>
</ul>

View File

@@ -0,0 +1,139 @@
<div class="p-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Active users</h3>
<button
@onclick="ToggleUserNames"
class="text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300">
@(ShowUserNames ? "Hide names" : "Show names")
</button>
</div>
@if (IsLoading)
{
<LoadingIndicator />
}
else
{
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="bg-green-50 dark:bg-green-900/30 p-4 rounded-lg">
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Last 24 hours</p>
<h4 class="text-2xl font-bold text-gray-900 dark:text-white">@UserStats.Last24Hours</h4>
@if (ShowUserNames)
{
<div class="mt-2 text-sm text-gray-600 dark:text-gray-300">
<ul>
@foreach (var user in UserStats.Last24HourUsers)
{
<li>@user</li>
}
</ul>
</div>
}
</div>
<div class="bg-green-50 dark:bg-green-900/30 p-4 rounded-lg">
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Last 7 days</p>
<h4 class="text-2xl font-bold text-gray-900 dark:text-white">@UserStats.Last7Days</h4>
@if (ShowUserNames)
{
<div class="mt-2 text-sm text-gray-600 dark:text-gray-300">
<ul>
@foreach (var user in UserStats.Last7DayUsers)
{
<li>@user</li>
}
</ul>
</div>
}
</div>
<div class="bg-green-50 dark:bg-green-900/30 p-4 rounded-lg">
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Last 14 days</p>
<h4 class="text-2xl font-bold text-gray-900 dark:text-white">@UserStats.Last14Days</h4>
@if (ShowUserNames)
{
<div class="mt-2 text-sm text-gray-600 dark:text-gray-300">
<ul>
@foreach (var user in UserStats.Last14DayUsers)
{
<li>@user</li>
}
</ul>
</div>
}
</div>
</div>
}
</div>
@code {
private bool IsLoading { get; set; } = true;
private UserStatistics UserStats { get; set; } = new();
private bool ShowUserNames { get; set; }
/// <summary>
/// Refreshes the data displayed on the card.
/// </summary>
public async Task RefreshData()
{
IsLoading = true;
StateHasChanged();
var now = DateTime.UtcNow;
var last24Hours = now.AddHours(-24);
var last7Days = now.AddDays(-7);
var last14Days = now.AddDays(-14);
// Get user statistics
var (count24h, users24h) = await GetActiveUserCount(last24Hours);
var (count7d, users7d) = await GetActiveUserCount(last7Days);
var (count14d, users14d) = await GetActiveUserCount(last14Days);
UserStats = new UserStatistics
{
Last24Hours = count24h,
Last7Days = count7d,
Last14Days = count14d,
Last24HourUsers = users24h,
Last7DayUsers = users7d,
Last14DayUsers = users14d
};
IsLoading = false;
StateHasChanged();
}
private async Task<(int count, List<string> users)> GetActiveUserCount(DateTime since)
{
// Get unique users who either:
// 1. Have successful auth logs
// 2. Have updated their vault
await using var dbContext = await DbContextFactory.CreateDbContextAsync();
var activeUsers = await dbContext.AuthLogs
.Where(l => l.Timestamp >= since && l.IsSuccess)
.Select(l => l.Username)
.Union(
dbContext.Vaults
.Where(v => v.UpdatedAt >= since)
.Select(v => v.User.UserName!)
)
.Distinct()
.ToListAsync();
return (activeUsers.Count, activeUsers);
}
private void ToggleUserNames()
{
ShowUserNames = !ShowUserNames;
StateHasChanged();
}
private sealed class UserStatistics
{
public int Last24Hours { get; set; }
public int Last7Days { get; set; }
public int Last14Days { get; set; }
public List<string> Last24HourUsers { get; set; } = new();
public List<string> Last7DayUsers { get; set; } = new();
public List<string> Last14DayUsers { get; set; } = new();
}
}

View File

@@ -0,0 +1,65 @@
<div class="p-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Recent emails received</h3>
</div>
@if (IsLoading)
{
<LoadingIndicator />
}
else
{
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="bg-primary-50 dark:bg-gray-700/50 p-4 rounded-lg">
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Last 24 hours</p>
<h4 class="text-2xl font-bold text-gray-900 dark:text-white">@EmailStats.Last24Hours</h4>
</div>
<div class="bg-primary-50 dark:bg-gray-700/50 p-4 rounded-lg">
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Last 7 days</p>
<h4 class="text-2xl font-bold text-gray-900 dark:text-white">@EmailStats.Last7Days</h4>
</div>
<div class="bg-primary-50 dark:bg-gray-700/50 p-4 rounded-lg">
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Last 14 days</p>
<h4 class="text-2xl font-bold text-gray-900 dark:text-white">@EmailStats.Last14Days</h4>
</div>
</div>
}
</div>
@code {
private bool IsLoading { get; set; } = true;
private EmailStatistics EmailStats { get; set; } = new();
/// <summary>
/// Refreshes the data displayed on the card.
/// </summary>
public async Task RefreshData()
{
IsLoading = true;
StateHasChanged();
var now = DateTime.UtcNow;
var last24Hours = now.AddHours(-24);
var last7Days = now.AddDays(-7);
var last14Days = now.AddDays(-14);
// Get email statistics
await using var dbContext = await DbContextFactory.CreateDbContextAsync();
var emailQuery = dbContext.Emails.AsQueryable();
EmailStats = new EmailStatistics
{
Last24Hours = await emailQuery.CountAsync(e => e.DateSystem >= last24Hours),
Last7Days = await emailQuery.CountAsync(e => e.DateSystem >= last7Days),
Last14Days = await emailQuery.CountAsync(e => e.DateSystem >= last14Days)
};
IsLoading = false;
StateHasChanged();
}
private sealed class EmailStatistics
{
public int Last24Hours { get; set; }
public int Last7Days { get; set; }
public int Last14Days { get; set; }
}
}

Some files were not shown because too many files have changed in this diff Show More