Compare commits

...

101 Commits
0.6.0 ... 0.8.0

Author SHA1 Message Date
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
159 changed files with 3042 additions and 1230 deletions

View File

@@ -1,7 +1,8 @@
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

View File

@@ -1,3 +1,4 @@
# This workflow will test if building the Docker Compose containers from scratch works.
name: Docker Compose Build
on:
@@ -20,7 +21,7 @@ jobs:
- name: Set permissions and run install.sh
run: |
chmod +x install.sh
./install.sh
./install.sh build --verbose
- name: Set up Docker Compose
run: |
@@ -31,58 +32,69 @@ jobs:
- 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)
sleep 15
- 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 is configured correctly."
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: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)
- 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 is configured correctly."
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: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: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: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
- 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

@@ -0,0 +1,111 @@
# 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: |
echo "REPO_FULL_NAME=${GITHUB_REPOSITORY}" >> $GITHUB_ENV
echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_ENV
- 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: Set permissions and run install.sh
run: |
chmod +x install.sh
./install.sh install --verbose
- name: Set up Docker Compose
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: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
@@ -25,7 +26,7 @@ jobs:
run: dotnet build
- 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
@@ -29,7 +30,7 @@ jobs:
run: dotnet build
- 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
@@ -25,7 +26,7 @@ jobs:
run: dotnet build
- 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

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,87 @@
# 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: 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 API image
uses: docker/build-push-action@v5
with:
context: .
file: src/AliasVault.Api/Dockerfile
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
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
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-admin:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-admin:${{ github.ref_name }}
- name: Build and push SMTP image
uses: docker/build-push-action@v5
with:
context: .
file: src/Services/AliasVault.SmtpService/Dockerfile
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-smtp:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-smtp:${{ github.ref_name }}
- name: Build and push Reverse Proxy image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
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 InstallCli image
uses: docker/build-push-action@v5
with:
context: .
file: src/Utilities/AliasVault.InstallCli/Dockerfile
push: true
tags: ${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-installcli:latest,${{ env.REGISTRY }}/${{ env.REPO_LOWER }}-installcli:${{ github.ref_name }}

View File

@@ -1,3 +1,4 @@
# 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.
name: SonarCloud code analysis
on:
push:
@@ -10,6 +11,14 @@ jobs:
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:

12
.gitignore vendored
View File

@@ -268,6 +268,7 @@ ServiceFabricBackup/
# SQLite files
*.sqlite
*.sqlite.*
*.sqlite-shm
*.sqlite-wal
@@ -392,3 +393,14 @@ src/Tests/AliasVault.E2ETests/appsettings.Development.json
# Draw.io diagram temp files
*.drawio.*
# Certificates
certificates/**/*.crt
certificates/**/*.key
certificates/**/*.pfx
certificates/**/*.pem
certificates/letsencrypt/**
# Docs
docs/_site
docs/vendor
docs/.bundle

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"]

View File

@@ -3,14 +3,14 @@
<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">Live demo 🔥</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="#installation">Installation ⚙️</a>
</p>
<h3 align="center">
Open-source password and alias manager
</h3>
[<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,6 +19,12 @@ 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>
<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 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.
### What makes AliasVault unique:
@@ -32,47 +38,48 @@ AliasVault is an open-source password and alias manager built with C# ASP.NET te
## 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.
<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">
## 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.
### Requirements:
- Access to a terminal
- Docker
- Git
To install AliasVault, 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.
### 1. Install using install script
This method uses pre-built Docker images and works on minimal hardware specifications:
- Linux VM with root access (Ubuntu or RHEL based distros recommended)
- 1 vCPU
- 512MB 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
curl -o install.sh https://raw.githubusercontent.com/lanedirt/AliasVault/main/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.
### 2. Post-Installation
### 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.
The install script will output the URL where the app is available. By default this is:
- Client: https://localhost
- Admin portal: https://localhost/admin
> Note: If you want to change the default AliasVault ports you can do so in the `docker-compose.yml` file.
> Note: If you want to change the default AliasVault ports you can do so in the `docker-compose.yml` file for the `nginx` (reverse-proxy) container.
#### 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.
## Detailed 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)
#### 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.
Here you can also find step-by-step instructions on how to install AliasVault to e.g. Azure, AWS and other popular cloud providers.
## 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,7 +88,9 @@ 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)
## Tech stack / credits
The following technologies, frameworks and libraries are used in this project:

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

@@ -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.

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

@@ -0,0 +1,30 @@
services:
reverse-proxy:
image: aliasvault-reverse-proxy
build:
context: .
dockerfile: 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
smtp:
image: aliasvault-smtp
build:
context: .
dockerfile: src/Services/AliasVault.SmtpService/Dockerfile

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,49 +1,58 @@
services:
admin:
image: aliasvault-admin
build:
context: .
dockerfile: src/AliasVault.Admin/Dockerfile
reverse-proxy:
image: ghcr.io/lanedirt/aliasvault-reverse-proxy:latest
ports:
- "8080:8082"
- "80:80"
- "443:443"
volumes:
- ./certificates:/certificates:rw
- ./database:/database:rw
- ./logs:/logs:rw
- ./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
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
env_file:
- .env
restart: always
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
smtp:
image: aliasvault-smtp
build:
context: .
dockerfile: src/Services/AliasVault.SmtpService/Dockerfile
image: ghcr.io/lanedirt/aliasvault-smtp:latest
ports:
- "25:25"
- "587:587"

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).

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){: .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: Installation Guide
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 2GB 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,83 @@
---
layout: default
title: Installation Guide
nav_order: 2
---
# Installation
Follow the steps below 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
- 512MB 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 `docker-compose.yml` file for the `reverse-proxy` (nginx) container. 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. 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
```

View File

@@ -0,0 +1,140 @@
---
layout: default
title: Manual Setup
parent: Installation Guide
nav_order: 2
---
# 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 logs/msbuild
```
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. **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
```
5. **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
```
6. **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
```
7. **Set SUPPORT_EMAIL (Optional)**
Add a support email address if desired:
```bash
SUPPORT_EMAIL=support@yourdomain.com
```
8. **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
```
9. **Build and start Docker containers**
Build the Docker Compose stack:
```bash
docker compose build
```
Start the Docker Compose stack:
```bash
docker compose up -d
```
10. **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 8]
- Client Website: https://localhost/
- Create your own account from here
## Important Notes
- Make sure to save the admin password you used in step 8 in a secure location.
- If you need to reset the admin password in the future, repeat step 8 and restart the Docker containers.
- 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:
```bash
docker compose logs
```
2. Ensure all required ports (80 and 443) 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,30 @@
---
layout: default
title: Start/stop
parent: Installation Guide
nav_order: 3
---
# 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: 5
---
# 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,32 @@
---
layout: default
title: Update
parent: Installation Guide
nav_order: 4
---
# Updating AliasVault
To update AliasVault to the latest version, run the install script with the `update` option. This will pull the latest version of AliasVault from GitHub and restart all containers.
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.
## Updating to the latest available version
To update to the latest version, run the install script with the `update` option. The script will check for the latest version and prompt you to confirm the update. Follow the prompts to complete the update.
```bash
./install.sh update
```
## 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.
```bash
./install.sh install <version>
# Example:
./install.sh install 0.7.0
```

View File

@@ -1,3 +1,12 @@
---
layout: default
title: Configure SQLite for use with WebAssembly
parent: Development
grand_parent: Miscellaneous
nav_order: 2
---
# Configure SQLite for use with WebAssembly
To configure SQLite for use with WebAssembly follow these steps:
1. Add NuGet package

View File

@@ -1,3 +1,12 @@
---
layout: default
title: Enable WebAuthn
parent: Development
grand_parent: Miscellaneous
nav_order: 1
---
# WebAuthn
The webauthn implementation in order to quick unlock the vault requires the use of a FIDO2 authenticator.
This can be either the built-in browser authenticator or an external authenticator like a Yubikey.

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

@@ -1,3 +1,11 @@
---
layout: default
title: 1. Run GitHub Actions Locally
parent: Development
grand_parent: Miscellaneous
nav_order: 1
---
# 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.

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.

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;"

1348
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.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

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>

View File

@@ -34,7 +34,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,21 @@
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 mcr.microsoft.com/dotnet/sdk:9.0 AS build
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"
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
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

@@ -5,7 +5,7 @@
<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-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,16 +13,16 @@
<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>
</ul>
@@ -57,7 +57,7 @@
</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,27 +75,27 @@
<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>

View File

@@ -16,6 +16,6 @@
base.OnInitialized();
// Redirect to users page.
NavigationService.RedirectTo("/users");
NavigationService.RedirectTo("users");
}
}

View File

@@ -89,11 +89,11 @@ else
GlobalNotificationService.AddSuccessMessage("User successfully deleted.");
GlobalLoadingSpinner.Hide();
NavigationService.RedirectTo("/users");
NavigationService.RedirectTo("users");
}
private void Cancel()
{
NavigationService.RedirectTo("/users/" + Id);
NavigationService.RedirectTo("users/" + Id);
}
}

View File

@@ -16,7 +16,7 @@ else
Description="View details of the user below.">
<CustomActions>
<RefreshButton OnClick="RefreshData" ButtonText="Refresh" />
<LinkButton Color="danger" Href="@($"/users/{Id}/delete")" Text="Delete user" />
<LinkButton Color="danger" Href="@($"users/{Id}/delete")" Text="Delete user" />
</CustomActions>
</PageHeader>
@@ -133,7 +133,7 @@ else
{
// Error loading user.
GlobalNotificationService.AddErrorMessage("This user does not exist (anymore). Please try again.");
NavigationService.RedirectTo("/users");
NavigationService.RedirectTo("users");
return;
}

View File

@@ -18,6 +18,7 @@ using AliasVault.Cryptography.Server;
using AliasVault.Logging;
using AliasVault.RazorComponents.Services;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
@@ -32,10 +33,12 @@ var adminPasswordHash = Environment.GetEnvironmentVariable("ADMIN_PASSWORD_HASH"
config.AdminPasswordHash = adminPasswordHash;
var lastPasswordChanged = Environment.GetEnvironmentVariable("ADMIN_PASSWORD_GENERATED") ?? throw new KeyNotFoundException("ADMIN_PASSWORD_GENERATED environment variable is not set.");
config.LastPasswordChanged = DateTime.ParseExact(lastPasswordChanged, "yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
config.LastPasswordChanged = DateTime.Parse(lastPasswordChanged, CultureInfo.InvariantCulture);
builder.Services.AddSingleton(config);
builder.Services.AddAliasVaultDataProtection("AliasVault.Api");
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
@@ -84,8 +87,6 @@ builder.Services.AddIdentityCore<AdminUser>(options =>
.AddSignInManager()
.AddDefaultTokenProviders();
builder.Services.AddAliasVaultDataProtection("AliasVault.Admin");
builder.Services.Configure<DataProtectionTokenProviderOptions>(options =>
{
options.TokenLifespan = TimeSpan.FromDays(30);
@@ -105,8 +106,24 @@ else
app.UseHsts();
}
// If the ASPNETCORE_PATHBASE environment variable is set, use it as the path base for the application.
// This is required for running the admin interface behind a reverse proxy on the same port as the client app.
// E.g. default Docker Compose setup makes admin app available on /admin path.
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPNETCORE_PATHBASE")))
{
app.UsePathBase(Environment.GetEnvironmentVariable("ASPNETCORE_PATHBASE"));
}
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto,
});
app.UseStaticFiles();
app.UseRouting();
app.UseAntiforgery();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();

View File

@@ -72,7 +72,6 @@ public static class StartupTasks
// Clear existing recovery codes
await userManager.GenerateNewTwoFactorRecoveryCodesAsync(adminUser, 0);
await userManager.UpdateAsync(adminUser);
Console.WriteLine("Admin password hash updated.");

View File

@@ -0,0 +1,29 @@
#!/bin/sh
# Create SSL directory if it doesn't exist
mkdir -p /app/ssl
# Generate self-signed SSL certificate if not exists
if [ ! -f /app/ssl/admin.crt ] || [ ! -f /app/ssl/admin.key ]; then
echo "Generating new SSL certificate..."
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /app/ssl/admin.key \
-out /app/ssl/admin.crt \
-subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
# Set proper permissions
chmod 644 /app/ssl/admin.crt
chmod 600 /app/ssl/admin.key
# Create PFX for ASP.NET Core
openssl pkcs12 -export -out /app/ssl/admin.pfx \
-inkey /app/ssl/admin.key \
-in /app/ssl/admin.crt \
-password pass:YourSecurePassword
fi
export ASPNETCORE_Kestrel__Certificates__Default__Path=/app/ssl/admin.pfx
export ASPNETCORE_Kestrel__Certificates__Default__Password=YourSecurePassword
# Start the application
dotnet AliasVault.Admin.dll

View File

@@ -357,9 +357,9 @@
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz",
"integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",

View File

@@ -1,13 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>AliasVault.Api</RootNamespace>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<DefineConstants Condition="'$(E2ETEST)' == 'true'">$(DefineConstants);E2ETEST</DefineConstants>
<LangVersion>13</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
@@ -21,14 +22,14 @@
<ItemGroup>
<PackageReference Include="Asp.Versioning.Mvc" Version="8.1.0" />
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.0" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.0" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.1" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.2.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.0.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -17,7 +17,7 @@ using Microsoft.AspNetCore.Mvc;
/// Base controller that concrete controllers can extend from if all requests require authentication.
/// </summary>
/// <param name="userManager">UserManager instance.</param>
[Route("api/v{version:apiVersion}/[controller]")]
[Route("v{version:apiVersion}/[controller]")]
[ApiController]
[Authorize]
public abstract class AuthenticatedRequestController(UserManager<AliasVaultUser> userManager) : ControllerBase

View File

@@ -39,7 +39,7 @@ using SecureRemotePassword;
/// <param name="cache">IMemoryCache instance for persisting SRP values during multistep login process.</param>
/// <param name="timeProvider">ITimeProvider instance. This returns the time which can be mutated for testing.</param>
/// <param name="authLoggingService">AuthLoggingService instance. This is used to log auth attempts to the database.</param>
[Route("api/v{version:apiVersion}/[controller]")]
[Route("v{version:apiVersion}/[controller]")]
[ApiController]
[ApiVersion("1")]
public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFactory, UserManager<AliasVaultUser> userManager, SignInManager<AliasVaultUser> signInManager, IConfiguration configuration, IMemoryCache cache, ITimeProvider timeProvider, AuthLoggingService authLoggingService) : ControllerBase
@@ -137,8 +137,6 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
return Ok(new ValidateLoginResponse(true, string.Empty, null));
}
// If 2FA is not required, then it means the user is successfully authenticated at this point.
// Reset failed login attempts.
await userManager.ResetAccessFailedCountAsync(user);
@@ -246,6 +244,12 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
{
await using var context = await dbContextFactory.CreateDbContextAsync();
// If the token is not provided, return bad request.
if (string.IsNullOrWhiteSpace(tokenModel.RefreshToken))
{
return BadRequest("Refresh token is required.");
}
var principal = GetPrincipalFromToken(tokenModel.Token);
if (principal.FindFirst(ClaimTypes.NameIdentifier)?.Value == null)
{
@@ -284,6 +288,12 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
{
await using var context = await dbContextFactory.CreateDbContextAsync();
// If the token is not provided, return bad request.
if (string.IsNullOrWhiteSpace(model.RefreshToken))
{
return BadRequest("Refresh token is required.");
}
var principal = GetPrincipalFromToken(model.Token);
if (principal.FindFirst(ClaimTypes.NameIdentifier)?.Value == null)
{
@@ -297,16 +307,18 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
}
// Check if the refresh token is valid.
var deviceIdentifier = GenerateDeviceIdentifier(Request);
var existingToken = await context.AliasVaultUserRefreshTokens.FirstOrDefaultAsync(t => t.UserId == user.Id && t.DeviceIdentifier == deviceIdentifier);
if (existingToken == null || existingToken.Value != model.RefreshToken)
var providedTokenExists = await context.AliasVaultUserRefreshTokens.AnyAsync(t => t.UserId == user.Id && t.Value == model.RefreshToken);
if (!providedTokenExists)
{
await authLoggingService.LogAuthEventFailAsync(user.UserName!, AuthEventType.Logout, AuthFailureReason.InvalidRefreshToken);
return Unauthorized("Invalid refresh token");
}
// Remove the existing refresh token.
context.AliasVaultUserRefreshTokens.Remove(existingToken);
// Remove the provided refresh token and any other existing refresh tokens that are issued to the current device ID.
// This to make sure all tokens are revoked for this device that user is "logging out" from.
var deviceIdentifier = GenerateDeviceIdentifier(Request);
var allDeviceTokens = await context.AliasVaultUserRefreshTokens.Where(t => t.UserId == user.Id && (t.Value == model.RefreshToken || t.DeviceIdentifier == deviceIdentifier)).ToListAsync();
context.AliasVaultUserRefreshTokens.RemoveRange(allDeviceTokens);
await context.SaveChangesAsync();
await authLoggingService.LogAuthEventSuccessAsync(user.UserName!, AuthEventType.Logout);
@@ -705,8 +717,14 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
// New refresh token lifetime is the same as the existing one.
var existingTokenLifetime = existingToken.ExpireDate - existingToken.CreatedAt;
// Retrieve new refresh token.
var newRefreshToken = await GenerateRefreshToken(user, existingTokenLifetime, existingToken.Value);
// After successfully retrieving new refresh token, remove the existing one by saving changes.
await context.SaveChangesAsync();
// Return new refresh token.
return await GenerateRefreshToken(user, existingTokenLifetime, existingToken.Value);
return newRefreshToken;
}
finally
{

View File

@@ -44,6 +44,7 @@ public class EmailController(ILogger<VaultController> logger, IDbContextFactory<
{
Id = email!.Id,
Subject = email.Subject,
FromDisplay = email.From,
FromDomain = email.FromDomain,
FromLocal = email.FromLocal,
ToDomain = email.ToDomain,

View File

@@ -18,8 +18,9 @@ using Microsoft.AspNetCore.Mvc;
/// Controller for retrieving favicons from external websites.
/// </summary>
/// <param name="userManager">UserManager instance.</param>
/// <param name="logger">Logger instance.</param>
[ApiVersion("1")]
public class FaviconController(UserManager<AliasVaultUser> userManager) : AuthenticatedRequestController(userManager)
public class FaviconController(UserManager<AliasVaultUser> userManager, ILogger<FaviconController> logger) : AuthenticatedRequestController(userManager)
{
/// <summary>
/// Proxies the request to the identity generator to generate a random identity.
@@ -36,9 +37,22 @@ public class FaviconController(UserManager<AliasVaultUser> userManager) : Authen
}
// Get the favicon from the URL.
var image = await FaviconExtractor.FaviconExtractor.GetFaviconAsync(url);
try
{
var image = await FaviconExtractor.FaviconExtractor.GetFaviconAsync(url);
// Return the favicon as base64 string of image representation.
return Ok(new FaviconExtractModel { Image = image });
// Return the favicon as base64 string of image representation.
return Ok(new FaviconExtractModel { Image = image });
}
catch (Exception ex)
{
// Anonymize the URL by replacing all a-Z characters with 'x' before logging.
// This will still allow to see the host structure but not the actual domain.
var anonymizedUrl = new string(url.Select(c => char.IsLetter(c) ? 'x' : c).ToArray());
logger.LogInformation(ex, "Failed to extract favicon from {Url}", anonymizedUrl);
}
// Return null if favicon extraction failed.
return Ok(new FaviconExtractModel { Image = null });
}
}

View File

@@ -21,7 +21,7 @@ using Microsoft.EntityFrameworkCore;
/// </summary>
/// <param name="dbContextFactory">AliasServerDbContext instance.</param>
/// <param name="userManager">UserManager instance.</param>
[Route("api/v{version:apiVersion}/[controller]")]
[Route("v{version:apiVersion}/[controller]")]
[ApiController]
[ApiVersion("1")]
public class SecurityController(IDbContextFactory<AliasServerDbContext> dbContextFactory, UserManager<AliasVaultUser> userManager) : AuthenticatedRequestController(userManager)
@@ -48,6 +48,7 @@ public class SecurityController(IDbContextFactory<AliasServerDbContext> dbContex
ExpireDate = x.ExpireDate,
CreatedAt = x.CreatedAt,
})
.Where(x => x.ExpireDate > DateTime.UtcNow)
.OrderByDescending(x => x.CreatedAt)
.ToListAsync();

View File

@@ -24,7 +24,7 @@ using Microsoft.EntityFrameworkCore;
/// <param name="urlEncoder">UrlEncoder instance.</param>
/// <param name="authLoggingService">AuthLoggingService instance. This is used to log auth attempts to the database.</param>
/// <param name="userManager">UserManager instance.</param>
[Route("api/v{version:apiVersion}/[controller]")]
[Route("v{version:apiVersion}/[controller]")]
[ApiController]
[ApiVersion("1")]
public class TwoFactorAuthController(IDbContextFactory<AliasServerDbContext> dbContextFactory, UrlEncoder urlEncoder, AuthLoggingService authLoggingService, UserManager<AliasVaultUser> userManager) : AuthenticatedRequestController(userManager)

View File

@@ -1,31 +1,22 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
EXPOSE 8081
EXPOSE 3001
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
# Copy the project files and restore dependencies
COPY ["src/AliasVault.Api/AliasVault.Api.csproj", "src/AliasVault.Api/"]
RUN dotnet restore "src/AliasVault.Api/AliasVault.Api.csproj"
COPY . .
# Build the WebApi project
WORKDIR "/src/src/AliasVault.Api"
RUN dotnet build "AliasVault.Api.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.Api.csproj" -c "$BUILD_CONFIGURATION" -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
COPY /src/AliasVault.Api/entrypoint.sh /app
RUN chmod +x /app/entrypoint.sh
EXPOSE 8081
ENV ASPNETCORE_URLS=http://+:8081
ENTRYPOINT ["/app/entrypoint.sh"]
COPY --from=build /app/publish .
ENV ASPNETCORE_URLS=http://+:3001
ENV ASPNETCORE_PATHBASE=/api
ENTRYPOINT ["dotnet", "AliasVault.Api.dll"]

View File

@@ -26,6 +26,7 @@ builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnC
builder.Configuration.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true);
builder.Services.ConfigureLogging(builder.Configuration, Assembly.GetExecutingAssembly().GetName().Name!, "../../logs");
builder.Services.AddAliasVaultDataProtection("AliasVault.Api");
builder.Services.AddSingleton<ITimeProvider, SystemTimeProvider>();
builder.Services.AddScoped<TimeValidationJwtBearerEvents>();
builder.Services.AddScoped<AuthLoggingService>();
@@ -40,8 +41,6 @@ builder.Services.AddLogging(logging =>
});
builder.Services.AddAliasVaultSqliteConfiguration();
builder.Services.AddAliasVaultDataProtection("AliasVault.Api");
builder.Services.AddIdentity<AliasVaultUser, AliasVaultRole>(options =>
{
options.Password.RequireDigit = false;
@@ -157,6 +156,12 @@ if (app.Environment.IsDevelopment())
app.UseCors("CorsPolicy");
// If the ASPNETCORE_PATHBASE environment variable is set, use it as the path base
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPNETCORE_PATHBASE")))
{
app.UsePathBase(Environment.GetEnvironmentVariable("ASPNETCORE_PATHBASE"));
}
app.UseAuthentication();
app.UseAuthorization();

View File

@@ -1,5 +0,0 @@
#!/bin/sh
# Start the application
echo "Starting application..."
dotnet /app/AliasVault.Api.dll

View File

@@ -1,23 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<RootNamespace>AliasVault.Client</RootNamespace>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<BuildVersion>$([System.DateTime]::UtcNow.ToString("yyyy-MM-dd HH:mm:ss"))</BuildVersion>
<WasmBuildNative>true</WasmBuildNative>
<LangVersion>13</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DocumentationFile>bin\Debug\net8.0\AliasVault.Client.xml</DocumentationFile>
<DocumentationFile>bin\Debug\net9.0\AliasVault.Client.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CacheBuster>dev</CacheBuster>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugSymbols>true</DebugSymbols>
<DocumentationFile>bin\Release\net8.0\AliasVault.Client.xml</DocumentationFile>
<DocumentationFile>bin\Release\net9.0\AliasVault.Client.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Optimize>True</Optimize>
<CacheBuster>$([System.DateTime]::UtcNow.ToString("yyyyMMddHHmmss"))</CacheBuster>
@@ -48,15 +49,16 @@
<ItemGroup>
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.10" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Private.Uri" Version="4.3.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -9,7 +9,7 @@
</Found>
<NotFound>
<LayoutView Layout="@typeof(Auth.Layout.MainLayout)">
<p>Sorry, there's nothing at this address.</p>
<p class="text-gray-500 dark:text-gray-400">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>

View File

@@ -207,7 +207,7 @@ else
var username = _loginModel.Username.ToLowerInvariant().Trim();
// Send request to server with username to get server ephemeral public key.
var result = await Http.PostAsJsonAsync("api/v1/Auth/login", new LoginInitiateRequest(username));
var result = await Http.PostAsJsonAsync("v1/Auth/login", new LoginInitiateRequest(username));
var responseContent = await result.Content.ReadAsStringAsync();
if (!result.IsSuccessStatusCode)
@@ -238,7 +238,7 @@ else
username);
// 4. Client sends proof of session key to server.
result = await Http.PostAsJsonAsync("api/v1/Auth/validate", new ValidateLoginRequest(username, _loginModel.RememberMe, _clientEphemeral.Public, _clientSession.Proof));
result = await Http.PostAsJsonAsync("v1/Auth/validate", new ValidateLoginRequest(username, _loginModel.RememberMe, _clientEphemeral.Public, _clientSession.Proof));
responseContent = await result.Content.ReadAsStringAsync();
if (!result.IsSuccessStatusCode)
@@ -280,7 +280,7 @@ else
var username = _loginModel.Username.ToLowerInvariant().Trim();
// Validate 2-factor auth code auth and login
var result = await Http.PostAsJsonAsync("api/v1/Auth/validate-recovery-code", new ValidateLoginRequestRecoveryCode(username, _loginModel.RememberMe, _clientEphemeral.Public, _clientSession.Proof, _loginModelRecoveryCode.RecoveryCode));
var result = await Http.PostAsJsonAsync("v1/Auth/validate-recovery-code", new ValidateLoginRequestRecoveryCode(username, _loginModel.RememberMe, _clientEphemeral.Public, _clientSession.Proof, _loginModelRecoveryCode.RecoveryCode));
var responseContent = await result.Content.ReadAsStringAsync();
if (!result.IsSuccessStatusCode)
@@ -338,7 +338,7 @@ else
var username = _loginModel.Username.ToLowerInvariant().Trim();
// Validate 2-factor auth code auth and login
var result = await Http.PostAsJsonAsync("api/v1/Auth/validate-2fa", new ValidateLoginRequest2Fa(username, _loginModel.RememberMe, _clientEphemeral.Public, _clientSession.Proof, _loginModel2Fa.TwoFactorCode ?? 0));
var result = await Http.PostAsJsonAsync("v1/Auth/validate-2fa", new ValidateLoginRequest2Fa(username, _loginModel.RememberMe, _clientEphemeral.Public, _clientSession.Proof, _loginModel2Fa.TwoFactorCode ?? 0));
var responseContent = await result.Content.ReadAsStringAsync();
if (!result.IsSuccessStatusCode)

View File

@@ -169,7 +169,7 @@
try
{
var response = await Http.PostAsJsonAsync("api/v1/Auth/validate-username", new { Username });
var response = await Http.PostAsJsonAsync("v1/Auth/validate-username", new { Username });
if (response.IsSuccessStatusCode)
{

View File

@@ -10,7 +10,7 @@
<div class="flex-grow p-6 pt-4 lg:pt-6 pb-28 lg:pb-4">
<div class="flex justify-between items-center mb-4">
<div>
<button @onclick="GoBack" class="text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200">
<button @onclick="GoBack" class="text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200 @(_currentStep == SetupStep.TermsAndConditions ? "invisible" : "")">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
</svg>

View File

@@ -123,7 +123,7 @@ else
await StatusCheck();
// Send request to server with email to get user salt.
var result = await Http.PostAsJsonAsync("api/v1/Auth/login", new LoginInitiateRequest(Username!));
var result = await Http.PostAsJsonAsync("v1/Auth/login", new LoginInitiateRequest(Username!));
var responseContent = await result.Content.ReadAsStringAsync();
if (!result.IsSuccessStatusCode)
@@ -234,7 +234,7 @@ else
// If user has no valid authentication an automatic redirect to login page will take place.
try
{
await Http.GetAsync("api/v1/Auth/status");
await Http.GetAsync("v1/Auth/status");
}
catch (Exception ex)
{

View File

@@ -1,15 +1,14 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG BUILD_CONFIGURATION=Release
# Add environment variable for opting out of telemetry which fixes
# "error MSB4166: Child node "8" exited prematurely." issues.
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
ENV MSBUILDDEBUGPATH=/src/msbuild-logs
WORKDIR /src
# Install Python which is required by the WebAssembly tools
RUN apt-get update && apt-get install -y python3 && apt-get clean
# Create the debug directory and install Python which is required by the WebAssembly tools
RUN mkdir -p /src/msbuild-logs && apt-get update && apt-get install -y python3 && apt-get clean
# Install the WebAssembly tools
RUN dotnet workload install wasm-tools
@@ -19,23 +18,19 @@ COPY ["src/AliasVault.Client/AliasVault.Client.csproj", "src/AliasVault.Client/"
RUN dotnet restore "src/AliasVault.Client/AliasVault.Client.csproj"
COPY . .
# Build the Client project
# Build and publish
WORKDIR "/src/src/AliasVault.Client"
RUN dotnet build "AliasVault.Client.csproj" -c "$BUILD_CONFIGURATION" -o /app/build
# Publish the Client project
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "AliasVault.Client.csproj" -c "$BUILD_CONFIGURATION" -o /app/publish /p:UseAppHost=false
# Final stage
FROM nginx:1.24.0 AS final
WORKDIR /usr/share/nginx/html
COPY --from=publish /app/publish/wwwroot .
COPY --from=build /app/publish/wwwroot .
COPY /src/AliasVault.Client/nginx.conf /etc/nginx/nginx.conf
COPY /src/AliasVault.Client/entrypoint.sh /app/
COPY /src/AliasVault.Client/entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
EXPOSE 8080
ENV ASPNETCORE_URLS=http://+:8080
EXPOSE 3000
ENV ASPNETCORE_URLS=http://+:3000
ENTRYPOINT ["/app/entrypoint.sh"]

View File

@@ -26,7 +26,7 @@
</button>
</div>
<div class="mt-4">
<p class="text-sm text-gray-500 dark:text-gray-400">From: @Email?.FromDisplay</p>
<p class="text-sm text-gray-500 dark:text-gray-400">From: @(Email?.FromLocal)@@@(Email?.FromDomain)</p>
<p class="text-sm text-gray-500 dark:text-gray-400">To: @(Email?.ToLocal)@@@(Email?.ToDomain)</p>
<p class="text-sm text-gray-500 dark:text-gray-400">Date: @Email?.DateSystem</p>
</div>
@@ -147,7 +147,7 @@
try
{
var response = await HttpClient.DeleteAsync($"api/v1/Email/{Email.Id}");
var response = await HttpClient.DeleteAsync($"v1/Email/{Email.Id}");
if (response.IsSuccessStatusCode)
{
GlobalNotificationService.AddSuccessMessage("Email deleted successfully", true);

View File

@@ -285,7 +285,7 @@
/// </summary>
private async Task LoadAliasVaultEmails()
{
var request = new HttpRequestMessage(HttpMethod.Get, $"api/v1/EmailBox/{EmailAddress}");
var request = new HttpRequestMessage(HttpMethod.Get, $"v1/EmailBox/{EmailAddress}");
try
{
var response = await HttpClient.SendAsync(request);
@@ -351,7 +351,7 @@
/// </summary>
private async Task ShowAliasVaultEmailInModal(int emailId)
{
EmailApiModel? mail = await HttpClient.GetFromJsonAsync<EmailApiModel>($"api/v1/Email/{emailId}");
EmailApiModel? mail = await HttpClient.GetFromJsonAsync<EmailApiModel>($"v1/Email/{emailId}");
if (mail != null)
{
// Decrypt the email content locally.

View File

@@ -11,12 +11,21 @@
</div>
@code {
/// <summary>
/// Title tag text of the loading indicator.
/// </summary>
[Parameter]
public string Title { get; set; } = string.Empty;
/// <summary>
/// Whether the loading indicator is spinning.
/// </summary>
[Parameter]
public bool Spinning { get; set; } = true;
/// <summary>
/// The content to display inside the loading indicator.
/// </summary>
[Parameter]
public RenderFragment? ChildContent { get; set; }
}

View File

@@ -8,7 +8,7 @@
<ConfirmModal />
<FullScreenLoadingIndicator @ref="LoadingIndicator" />
<TopMenu />
<div class="flex pt-16 pb-4 lg:pb-16 overflow-hidden bg-gray-100 dark:bg-gray-900">
<div class="flex pt-16 mb-4 lg:mb-16 overflow-hidden bg-gray-100 dark:bg-gray-900 relative z-20">
<div id="main-content" class="relative z-10 w-full max-w-screen-2xl mx-auto h-full overflow-y-auto bg-gray-100 dark:bg-gray-900">
<main>
<GlobalNotificationDisplay />

View File

@@ -138,7 +138,7 @@ else
Addresses = emailClaimList,
};
var request = new HttpRequestMessage(HttpMethod.Post, $"api/v1/EmailBox/bulk");
var request = new HttpRequestMessage(HttpMethod.Post, $"v1/EmailBox/bulk");
request.Content = new StringContent(JsonSerializer.Serialize(requestModel), Encoding.UTF8, "application/json");
try
@@ -245,7 +245,7 @@ else
/// </summary>
private async Task ShowAliasVaultEmailInModal(int emailId)
{
EmailApiModel? mail = await HttpClient.GetFromJsonAsync<EmailApiModel>($"api/v1/Email/{emailId}");
EmailApiModel? mail = await HttpClient.GetFromJsonAsync<EmailApiModel>($"v1/Email/{emailId}");
if (mail != null)
{
// Decrypt the email content locally.

View File

@@ -108,7 +108,7 @@ else
if (firstRender)
{
// Get the QR code and secret for the authenticator app.
var response = await Http.GetFromJsonAsync<PasswordChangeInitiateResponse>("api/v1/Auth/change-password/initiate");
var response = await Http.GetFromJsonAsync<PasswordChangeInitiateResponse>("v1/Auth/change-password/initiate");
if (response == null)
{
@@ -191,7 +191,7 @@ else
PasswordChangeModel = new PasswordChangeModel();
// 4. Client sends proof of session key to server.
var response = await Http.PostAsJsonAsync("api/v1/Vault/change-password", vaultPasswordChangeObject);
var response = await Http.PostAsJsonAsync("v1/Vault/change-password", vaultPasswordChangeObject);
var responseContent = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)

View File

@@ -70,7 +70,7 @@
{
IsLoading = true;
StateHasChanged();
var sessionsResponse = await Http.GetFromJsonAsync<List<RefreshTokenModel>>("api/v1/Security/sessions");
var sessionsResponse = await Http.GetFromJsonAsync<List<RefreshTokenModel>>("v1/Security/sessions");
if (sessionsResponse is not null)
{
Sessions = sessionsResponse;
@@ -89,7 +89,7 @@
{
try
{
var response = await Http.DeleteAsync($"api/v1/Security/sessions/{id}");
var response = await Http.DeleteAsync($"v1/Security/sessions/{id}");
if (response.IsSuccessStatusCode)
{
GlobalNotificationService.AddSuccessMessage("Session revoked successfully.", true);

View File

@@ -85,7 +85,7 @@
/// </summary>
public async Task DisableWebAuthn()
{
await AuthService.SetWebAuthnEnabledAsync(false, string.Empty, string.Empty, string.Empty);
await AuthService.SetWebAuthnEnabledAsync(false);
GlobalNotificationService.AddSuccessMessage("Quick Vault Unlock is successfully disabled.", true);
await LoadData();
}

View File

@@ -73,7 +73,7 @@
{
IsLoading = true;
StateHasChanged();
var authlogResponse = await Http.GetFromJsonAsync<List<AuthLogModel>>("api/v1/Security/authlogs");
var authlogResponse = await Http.GetFromJsonAsync<List<AuthLogModel>>("v1/Security/authlogs");
if (authlogResponse is not null)
{
AuthLogs = authlogResponse;

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