Browse Source

update: remove PASWORD_HASH forever

- set up a username and password at the initial start
pull/1228/head
tetuaoro 2 years ago
parent
commit
c571fcf88b
  1. 11
      .vscode/settings.json
  2. 4
      Dockerfile
  3. 28
      How_to_generate_an_bcrypt_hash.md
  4. 10
      README.md
  5. 1
      docker-compose.dev.yml
  6. 1
      docker-compose.yml
  7. 9
      src/lib/Server.js
  8. 25
      src/lib/database/AbstractDatabase.js
  9. 12
      src/lib/database/Lowdb.js
  10. 23
      src/templates/Settings.vue
  11. 8
      src/templates/Setup.vue
  12. 54
      src/wgpw.mjs
  13. 5
      src/wgpw.sh
  14. 4
      src/www/css/app.css
  15. 16
      src/www/index.html
  16. 4
      src/www/js/app.js
  17. 4
      src/www/js/i18n.js
  18. 2
      src/www/js/vendor/vue-settings.umd.min.js
  19. 2
      src/www/js/vendor/vue-settings.umd.min.js.map
  20. 2
      src/www/js/vendor/vue-setup.umd.min.js
  21. 2
      src/www/js/vendor/vue-setup.umd.min.js.map
  22. 1
      wg-easy.service

11
.vscode/settings.json

@ -1,11 +0,0 @@
{
"[javascript]": {
"editor.formatOnSave": true,
"editor.formatOnType": true
},
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false,
"javascript.format.semicolons": "insert",
"editor.tabSize": 2,
"editor.indentSize": "tabSize",
"editor.detectIndentation": false
}

4
Dockerfile

@ -26,10 +26,6 @@ COPY --from=build_node_modules /app /app
# than what runs inside of docker. # than what runs inside of docker.
COPY --from=build_node_modules /node_modules /node_modules COPY --from=build_node_modules /node_modules /node_modules
# Copy the needed wg-password scripts
COPY --from=build_node_modules /app/wgpw.sh /bin/wgpw
RUN chmod +x /bin/wgpw
# Install Linux packages # Install Linux packages
RUN apk add --no-cache \ RUN apk add --no-cache \
dpkg \ dpkg \

28
How_to_generate_an_bcrypt_hash.md

@ -1,28 +0,0 @@
# wg-password
`wg-password` (wgpw) is a script that generates bcrypt password hashes for use with `wg-easy`, enhancing security by requiring passwords.
## Features
- Generate bcrypt password hashes.
- Easily integrate with `wg-easy` to enforce password requirements.
## Usage with Docker
To generate a bcrypt password hash using docker, run the following command :
```sh
docker run ghcr.io/wg-easy/wg-easy wgpw YOUR_PASSWORD
PASSWORD_HASH='$2b$12$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW' // literally YOUR_PASSWORD
```
*Important* : make sure to enclose your password in single quotes when you run `docker run` command :
```bash
$ echo $2b$12$coPqCsPtcF
b2
$ echo "$2b$12$coPqCsPtcF"
b2
$ echo '$2b$12$coPqCsPtcF'
$2b$12$coPqCsPtcF
```

10
README.md

@ -65,7 +65,6 @@ To automatically install & run wg-easy, simply run:
--name=wg-easy \ --name=wg-easy \
-e LANG=de \ -e LANG=de \
-e WG_HOST=<🚨YOUR_SERVER_IP> \ -e WG_HOST=<🚨YOUR_SERVER_IP> \
-e PASSWORD_HASH=<🚨YOUR_ADMIN_PASSWORD_HASH> \
-e PORT=51821 \ -e PORT=51821 \
-e WG_PORT=51820 \ -e WG_PORT=51820 \
-v ~/.wg-easy:/etc/wireguard \ -v ~/.wg-easy:/etc/wireguard \
@ -80,8 +79,6 @@ To automatically install & run wg-easy, simply run:
``` ```
> 💡 Replace `YOUR_SERVER_IP` with your WAN IP, or a Dynamic DNS hostname. > 💡 Replace `YOUR_SERVER_IP` with your WAN IP, or a Dynamic DNS hostname.
>
> 💡 Replace `YOUR_ADMIN_PASSWORD_HASH` with a bcrypt password hash to log in on the Web UI. See [How_to_generate_an_bcrypt_hash.md](./How_to_generate_an_bcrypt_hash.md) for know how generate the hash.
The Web UI will now be available on `http://0.0.0.0:51821`. The Web UI will now be available on `http://0.0.0.0:51821`.
@ -95,12 +92,6 @@ execute `docker compose up --detach`.
Are you enjoying this project? [Buy Emile a beer!](https://github.com/sponsors/WeeJeWel) 🍻 Are you enjoying this project? [Buy Emile a beer!](https://github.com/sponsors/WeeJeWel) 🍻
## Password initialization
When the application initializes the database for the first time, it sets up an admin user with a default password : `admin`. You have the option to set your own password instead using either the `PASSWORD` environment variable or the `PASSWORD_HASH` environment variable. Follow [this link](./How_to_generate_an_bcrypt_hash.md) to generate a bcrypt hash password.
The `PASSWORD` environment variable is plain text and will be hashed at runtime by wg-easy. On the other hand, the `PASSWORD_HASH` environment variable is already hashed.
## Options ## Options
These options can be configured by setting environment variables using `-e KEY="VALUE"` in the `docker run` command. These options can be configured by setting environment variables using `-e KEY="VALUE"` in the `docker run` command.
@ -109,7 +100,6 @@ These options can be configured by setting environment variables using `-e KEY="
| - | - | - |------------------------------------------------------------------------------------------------------------------------------------------------------| | - | - | - |------------------------------------------------------------------------------------------------------------------------------------------------------|
| `PORT` | `51821` | `6789` | TCP port for Web UI. | | `PORT` | `51821` | `6789` | TCP port for Web UI. |
| `WEBUI_HOST` | `0.0.0.0` | `localhost` | IP address web UI binds to. | | `WEBUI_HOST` | `0.0.0.0` | `localhost` | IP address web UI binds to. |
| `PASSWORD_HASH` | - | `$2y$05$Ci...` | When set, requires a password when logging in to the Web UI. See [How to generate an bcrypt hash.md]("https://github.com/wg-easy/wg-easy/blob/master/How_to_generate_an_bcrypt_hash.md") for know how generate the hash. |
| `WG_HOST` | - | `vpn.myserver.com` | The public hostname of your VPN server. | | `WG_HOST` | - | `vpn.myserver.com` | The public hostname of your VPN server. |
| `WG_DEVICE` | `eth0` | `ens6f0` | Ethernet device the wireguard traffic should be forwarded through. | | `WG_DEVICE` | `eth0` | `ens6f0` | Ethernet device the wireguard traffic should be forwarded through. |
| `WG_PORT` | `51820` | `12345` | The public UDP port of your VPN server. WireGuard will listen on that (othwise default) inside the Docker container. | | `WG_PORT` | `51820` | `12345` | The public UDP port of your VPN server. WireGuard will listen on that (othwise default) inside the Docker container. |

1
docker-compose.dev.yml

@ -13,5 +13,4 @@ services:
- NET_ADMIN - NET_ADMIN
- SYS_MODULE - SYS_MODULE
environment: environment:
# - PASSWORD=p
- WG_HOST=192.168.1.233 - WG_HOST=192.168.1.233

1
docker-compose.yml

@ -12,7 +12,6 @@ services:
- WG_HOST=raspberrypi.local - WG_HOST=raspberrypi.local
# Optional: # Optional:
# - PASSWORD_HASH=$$2y$$10$$hBCoykrB95WSzuV4fafBzOHWKu9sbyVa34GJr8VV5R/pIelfEMYyG (needs double $$, hash of 'foobar123'; see "How_to_generate_an_bcrypt_hash.md" for generate the hash)
# - PORT=51821 # - PORT=51821
# - WG_PORT=51820 # - WG_PORT=51820
# - WG_CONFIG_PORT=92820 # - WG_CONFIG_PORT=92820

9
src/lib/Server.js

@ -128,7 +128,7 @@ module.exports = class Server {
// WireGuard // WireGuard
app.use( app.use(
fromNodeMiddleware(async (req, res, next) => { fromNodeMiddleware(async (req, _res, next) => {
if (!req.url.startsWith('/api/')) { if (!req.url.startsWith('/api/')) {
return next(); return next();
} }
@ -148,9 +148,10 @@ module.exports = class Server {
} }
} }
return res.status(401).json({ // this cause errors : status is not a function
error: 'Not Logged In', // return res.status(401).json({
}); // error: 'Not Logged In',
// });
}), }),
); );

25
src/lib/database/AbstractDatabase.js

@ -32,6 +32,17 @@ module.exports = class DatabaseInterface {
return password.length >= minLength && hasUpperCase && hasLowerCase && hasNumber && hasSpecialChar; return password.length >= minLength && hasUpperCase && hasLowerCase && hasNumber && hasSpecialChar;
} }
/**
* Check if database exist
*
* @abstract
* @returns {Promise<boolean>} Return `true` if it exists, otherwise `false`
* @throws {ServerError} If not implemented by the subclass
*/
firstSetupAuth() {
throw new ServerError('You must implement this function');
}
/** /**
* Initializes the database if does not exist * Initializes the database if does not exist
* *
@ -85,4 +96,18 @@ module.exports = class DatabaseInterface {
throw new ServerError('You must implement this function'); throw new ServerError('You must implement this function');
} }
/**
* Adds an admin user to the database if none exists
*
* @abstract
* @param {string} username - The username of the admin user
* @param {string} password - The password of the admin user
* @returns {Promise<void>}
* @throws {ServerError} If not implemented by the subclass
* @throws {ServerError} If `password` is not complex enough
*/
async addAdminUser(username, password) {
throw new ServerError('You must implement this function');
}
}; };

12
src/lib/database/Lowdb.js

@ -46,22 +46,25 @@ module.exports = class Lowdb extends DatabaseInterface {
} }
async initDb() { async initDb() {
debug('Loading database...'); // each function must call this method to check if the file exist
// lowdb is an esm module // lowdb is an esm module
// eslint-disable-next-line node/no-unsupported-features/es-syntax, import/no-unresolved, node/no-missing-import // eslint-disable-next-line node/no-unsupported-features/es-syntax, import/no-unresolved, node/no-missing-import
const { JSONFilePreset } = await import('lowdb/node'); const { JSONFilePreset } = await import('lowdb/node');
this.db = await JSONFilePreset(this.dbPath, Model); this.db = await JSONFilePreset(this.dbPath, Model);
await this.db.read(); await this.db.read();
if (!this.db.data.users) { if (!this.db.data.users) {
debug(`Created new database at ${this.dbPath}`);
this.db.data = { users: [] }; this.db.data = { users: [] };
await this.db.write(); await this.db.write();
debug(`Created new database at ${this.dbPath}`);
} }
} }
async comparePassword(username, password) { async comparePassword(username, password) {
debug('Compare password'); debug('Compare password');
this.initDb();
const user = this.db.data.users.find((u) => u.username === username); const user = this.db.data.users.find((u) => u.username === username);
if (!user) { if (!user) {
throw new ServerError('User not found'); throw new ServerError('User not found');
@ -72,6 +75,7 @@ module.exports = class Lowdb extends DatabaseInterface {
async updatePassword(username, oldPassword, newPassword) { async updatePassword(username, oldPassword, newPassword) {
debug('Update password'); debug('Update password');
this.initDb();
if (!super.isPasswordComplex(newPassword)) { if (!super.isPasswordComplex(newPassword)) {
throw new ServerError('Password does not meet complexity requirements : 8 characters minimum, uppercase, lowercase, number and special char'); throw new ServerError('Password does not meet complexity requirements : 8 characters minimum, uppercase, lowercase, number and special char');
@ -94,6 +98,7 @@ module.exports = class Lowdb extends DatabaseInterface {
async addUser(username, password) { async addUser(username, password) {
debug('Add user'); debug('Add user');
this.initDb();
if (!super.isPasswordComplex(password)) { if (!super.isPasswordComplex(password)) {
throw new ServerError('Password does not meet complexity requirements, minimum 8 characters, uppercase, lowercase, number and special char'); throw new ServerError('Password does not meet complexity requirements, minimum 8 characters, uppercase, lowercase, number and special char');
@ -118,6 +123,7 @@ module.exports = class Lowdb extends DatabaseInterface {
async addAdminUser(username, password) { async addAdminUser(username, password) {
debug('Add admin user'); debug('Add admin user');
this.initDb();
if (!this.firstSetupAuth()) { if (!this.firstSetupAuth()) {
// for the time being, when the first setup, this method is auth to be called, otherwise throw // for the time being, when the first setup, this method is auth to be called, otherwise throw
@ -146,6 +152,8 @@ module.exports = class Lowdb extends DatabaseInterface {
} }
firstSetupAuth() { firstSetupAuth() {
this.initDb();
return this.db.data.users.length === 0; return this.db.data.users.length === 0;
} }

23
src/templates/Settings.vue

@ -3,8 +3,12 @@
<script> <script>
export default { export default {
name: 'Settings', name: 'Settings',
props: {
username: String,
},
data() { data() {
return { return {
username: ref(props.username),
currentPassword: '', currentPassword: '',
newPassword: '', newPassword: '',
confirmNewPassword: '', confirmNewPassword: '',
@ -18,9 +22,8 @@ export default {
return; return;
} }
// temp username 'admin'
this.api.updatePassword({ this.api.updatePassword({
username: 'admin', username: this.username,
oldPassword: this.currentPassword, oldPassword: this.currentPassword,
newPassword: this.newPassword newPassword: this.newPassword
}).then((_result) => { }).then((_result) => {
@ -49,11 +52,19 @@ export default {
<div class="container p-2 flex flex-col md:items-center py-8"> <div class="container p-2 flex flex-col md:items-center py-8">
<form @submit="updatePassword" class="w-full md:w-[75%]"> <form @submit="updatePassword" class="w-full md:w-[75%]">
<div class="mb-4">
<label for="username" class="block text-sm font-medium dark:text-neutral-200 mb-4">
{{ $t('setupUsername') }}
</label>
<input id="username" disabled v-model="username" :placeholder="$t('setupUsername')" autocomplete="username"
class="outline-none focus:border-red-800 bg-transparent border border-neutral-500 p-2 rounded-md w-full" required />
</div>
<div class="mb-4"> <div class="mb-4">
<label for="currentPassword" class="block text-sm font-medium dark:text-neutral-200 mb-4"> <label for="currentPassword" class="block text-sm font-medium dark:text-neutral-200 mb-4">
{{ $t('currentPassword') }} {{ $t('currentPassword') }}
</label> </label>
<input id="currentPassword" v-model="currentPassword" type="password" :placeholder="$t('currentPassword')" <input id="currentPassword" v-model="currentPassword" type="password" :placeholder="$t('currentPassword')" autocomplete="current-password"
class="outline-none focus:border-red-800 bg-transparent border border-neutral-500 p-2 rounded-md w-full" required /> class="outline-none focus:border-red-800 bg-transparent border border-neutral-500 p-2 rounded-md w-full" required />
</div> </div>
@ -61,7 +72,7 @@ export default {
<label for="newPassword" class="block text-sm font-medium dark:text-neutral-200 mb-4"> <label for="newPassword" class="block text-sm font-medium dark:text-neutral-200 mb-4">
{{ $t('newPassword') }} {{ $t('newPassword') }}
</label> </label>
<input id="newPassword" v-model="newPassword" type="password" :placeholder="$t('newPassword')" <input id="newPassword" v-model="newPassword" type="password" :placeholder="$t('newPassword')" autocomplete="new-password"
class="outline-none focus:border-red-800 bg-transparent border border-neutral-500 p-2 rounded-md w-full" required /> class="outline-none focus:border-red-800 bg-transparent border border-neutral-500 p-2 rounded-md w-full" required />
</div> </div>
@ -69,11 +80,11 @@ export default {
<label for="confirmNewPassword" class="block text-sm font-medium dark:text-neutral-200 mb-4"> <label for="confirmNewPassword" class="block text-sm font-medium dark:text-neutral-200 mb-4">
{{ $t('confirmNewPassword') }} {{ $t('confirmNewPassword') }}
</label> </label>
<input id="confirmNewPassword" v-model="confirmNewPassword" type="password" :placeholder="$t('confirmNewPassword')" <input id="confirmNewPassword" v-model="confirmNewPassword" type="password" :placeholder="$t('confirmNewPassword')" autocomplete="new-password"
class="outline-none focus:border-red-800 bg-transparent border border-neutral-500 p-2 rounded-md w-full" required /> class="outline-none focus:border-red-800 bg-transparent border border-neutral-500 p-2 rounded-md w-full" required />
</div> </div>
<button type="submit" :disabled="!newPassword || !confirmNewPassword || newPassword != confirmNewPassword" :class="!newPassword || !confirmNewPassword || newPassword != confirmNewPassword ? 'bg-neutral-400 text-white p-2 rounded-md w-full transition' : 'bg-red-800 text-white p-2 rounded-md w-full transition'"> <button type="submit" :disabled="!username || !currentPassword || !newPassword || !confirmNewPassword || newPassword != confirmNewPassword" :class="!newPassword || !confirmNewPassword || newPassword != confirmNewPassword ? 'bg-neutral-400 text-white p-2 rounded-md w-full transition' : 'bg-red-800 text-white p-2 rounded-md w-full transition'">
{{ $t('updatePassword') }} {{ $t('updatePassword') }}
</button> </button>
</form> </form>

8
src/templates/Setup.vue

@ -25,7 +25,7 @@ export default {
this.username = ''; this.username = '';
this.newPassword = ''; this.newPassword = '';
this.confirmNewPassword = ''; this.confirmNewPassword = '';
alert('User created'); alert('User created, please reload your current page');
window.location.reload(); window.location.reload();
}).catch((err) => { }).catch((err) => {
alert(err.message || err.toString()); alert(err.message || err.toString());
@ -53,21 +53,21 @@ export default {
</svg> </svg>
</div> </div>
<div class="mb-4"> <div class="mb-3">
<label for="username" class="block mb-2 text-gray-500 dark:text-white">{{ $t('setupUsername') }}</label> <label for="username" class="block mb-2 text-gray-500 dark:text-white">{{ $t('setupUsername') }}</label>
<input id="username" name="username" :placeholder="$t('setupUsername')" v-model="username" required <input id="username" name="username" :placeholder="$t('setupUsername')" v-model="username" required
autocomplete="username" autocomplete="username"
class="px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-500 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 outline-none" /> class="px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-500 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 outline-none" />
</div> </div>
<div class="mb-4"> <div class="mb-3">
<label for="newPassword" class="block mb-2 text-gray-500 dark:text-white">{{ $t('newPassword') }}</label> <label for="newPassword" class="block mb-2 text-gray-500 dark:text-white">{{ $t('newPassword') }}</label>
<input id="newPassword" type="password" name="newPassword" :placeholder="$t('newPassword')" <input id="newPassword" type="password" name="newPassword" :placeholder="$t('newPassword')"
v-model="newPassword" required autocomplete="new-password" v-model="newPassword" required autocomplete="new-password"
class="px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-500 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 outline-none" /> class="px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-500 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 outline-none" />
</div> </div>
<div class="mb-4"> <div class="mb-3">
<label for="confirmNewPassword" class="block mb-2 text-gray-500 dark:text-white">{{ $t('confirmNewPassword') <label for="confirmNewPassword" class="block mb-2 text-gray-500 dark:text-white">{{ $t('confirmNewPassword')
}}</label> }}</label>
<input id="confirmNewPassword" type="password" name="confirmNewPassword" :placeholder="$t('confirmNewPassword')" <input id="confirmNewPassword" type="password" name="confirmNewPassword" :placeholder="$t('confirmNewPassword')"

54
src/wgpw.mjs

@ -1,54 +0,0 @@
'use strict';
// Import needed libraries
import bcrypt from 'bcryptjs';
// Function to generate hash
const generateHash = async (password) => {
try {
const salt = await bcrypt.genSalt(12);
const hash = await bcrypt.hash(password, salt);
// eslint-disable-next-line no-console
console.log(`PASSWORD_HASH='${hash}'`);
} catch (error) {
throw new Error(`Failed to generate hash : ${error}`);
}
};
// Function to compare password with hash
const comparePassword = async (password, hash) => {
try {
const match = await bcrypt.compare(password, hash);
if (match) {
// eslint-disable-next-line no-console
console.log('Password matches the hash !');
} else {
// eslint-disable-next-line no-console
console.log('Password does not match the hash.');
}
} catch (error) {
throw new Error(`Failed to compare password and hash : ${error}`);
}
};
(async () => {
try {
// Retrieve command line arguments
const args = process.argv.slice(2); // Ignore the first two arguments
if (args.length > 2) {
throw new Error('Usage : wgpw YOUR_PASSWORD [HASH]');
}
const [password, hash] = args;
if (password && hash) {
await comparePassword(password, hash);
} else if (password) {
await generateHash(password);
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
// eslint-disable-next-line no-process-exit
process.exit(1);
}
})();

5
src/wgpw.sh

@ -1,5 +0,0 @@
#!/bin/sh
# This script is intended to be run only inside a docker container, not on the development host machine
set -e
# proxy command
node /app/wgpw.mjs "$@"

4
src/www/css/app.css

@ -718,6 +718,10 @@ video {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.mb-3 {
margin-bottom: 0.75rem;
}
.mb-4 { .mb-4 {
margin-bottom: 1rem; margin-bottom: 1rem;
} }

16
src/www/index.html

@ -15,8 +15,7 @@
[v-cloak] { [v-cloak] {
display: none; display: none;
} }
.line-chart .apexcharts-svg{
.line-chart .apexcharts-svg {
transform: translateY(3px); transform: translateY(3px);
} }
</style> </style>
@ -437,7 +436,7 @@
</div> </div>
<!-- Settings --> <!-- Settings -->
<settings v-if="showPage === 'settings'"></settings> <settings v-if="showPage === 'settings'" :username="username"></settings>
</div> </div>
<!-- QR Code--> <!-- QR Code-->
@ -616,8 +615,17 @@
</svg> </svg>
</div> </div>
<input type="password" name="password" :placeholder="$t('password')" v-model="password" autocomplete="current-password" <div class="mb-3">
<label for="username" class="block mb-2 text-gray-500 dark:text-white">{{ $t("setupUsername") }}</label>
<input id="username" name="username" :placeholder="$t('setupUsername')" v-model="username" autocomplete="username"
class="px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-500 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 outline-none"/> class="px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-500 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 outline-none"/>
</div>
<div class="mb-3">
<label for="password" class="block mb-2 text-gray-500 dark:text-white">{{ $t("password") }}</label>
<input id="password" type="password" name="password" :placeholder="$t('password')" v-model="password" autocomplete="current-password"
class="px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-500 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 outline-none"/>
</div>
<button v-if="authenticating" <button v-if="authenticating"
class="bg-red-800 dark:bg-red-800 w-full rounded shadow py-2 text-sm text-white dark:text-white cursor-not-allowed"> class="bg-red-800 dark:bg-red-800 w-full rounded shadow py-2 text-sm text-white dark:text-white cursor-not-allowed">

4
src/www/js/app.js

@ -54,8 +54,7 @@ new Vue({
firstSetup: false, firstSetup: false,
authenticated: null, authenticated: null,
authenticating: false, authenticating: false,
// temp username 'admin' username: '',
username: 'admin',
password: null, password: null,
requiresPassword: null, requiresPassword: null,
@ -245,7 +244,6 @@ new Vue({
this.authenticating = true; this.authenticating = true;
this.api.createSession({ this.api.createSession({
// temp username 'admin'
username: this.username, username: this.username,
password: this.password, password: this.password,
}) })

4
src/www/js/i18n.js

@ -225,6 +225,10 @@ const messages = { // eslint-disable-line no-unused-vars
backup: 'Sauvegarder', backup: 'Sauvegarder',
titleRestoreConfig: 'Restaurer votre configuration', titleRestoreConfig: 'Restaurer votre configuration',
titleBackupConfig: 'Sauvegarder votre configuration', titleBackupConfig: 'Sauvegarder votre configuration',
setup: 'Configuration',
setupUsername: 'Nom d\'utilisateur',
setupBtnCU: 'Créer',
setupRequiredPatternPassword: '12 caractères minimum dont 1 majuscule, 1 minuscule, 1 chiffre et 1 caractère special',
navHome: 'Accueil', navHome: 'Accueil',
navSettings: 'Paramètres', navSettings: 'Paramètres',
settings: 'Paramètres', settings: 'Paramètres',

2
src/www/js/vendor/vue-settings.umd.min.js

File diff suppressed because one or more lines are too long

2
src/www/js/vendor/vue-settings.umd.min.js.map

File diff suppressed because one or more lines are too long

2
src/www/js/vendor/vue-setup.umd.min.js

File diff suppressed because one or more lines are too long

2
src/www/js/vendor/vue-setup.umd.min.js.map

File diff suppressed because one or more lines are too long

1
wg-easy.service

@ -4,7 +4,6 @@ After=network-online.target nss-lookup.target
[Service] [Service]
Environment="WG_HOST=raspberrypi.local" # Change this to your host's public address or static public ip. Environment="WG_HOST=raspberrypi.local" # Change this to your host's public address or static public ip.
Environment="PASSWORD=REPLACEME" # When set, requires a password when logging in to the Web UI, to disable add a hashtag
#Environment="WG_DEFAULT_ADDRESS=10.0.8.x" #Clients IP address range. #Environment="WG_DEFAULT_ADDRESS=10.0.8.x" #Clients IP address range.
#Environment="WG_DEFAULT_DNS=10.0.8.1, 1.1.1.1" #DNS server clients will use. If set to blank value, clients will not use any DNS. #Environment="WG_DEFAULT_DNS=10.0.8.1, 1.1.1.1" #DNS server clients will use. If set to blank value, clients will not use any DNS.
#Environment="WG_ALLOWED_IPS=0.0.0.0/0,::/0" #Allowed IPs clients will use. #Environment="WG_ALLOWED_IPS=0.0.0.0/0,::/0" #Allowed IPs clients will use.

Loading…
Cancel
Save