mirror of https://github.com/wg-easy/wg-easy
36 changed files with 6874 additions and 3266 deletions
@ -0,0 +1,6 @@ |
|||
{ |
|||
"trailingComma": "es5", |
|||
"tabWidth": 2, |
|||
"semi": true, |
|||
"singleQuote": true |
|||
} |
File diff suppressed because it is too large
@ -1,6 +1,6 @@ |
|||
[v-cloak] { |
|||
display: none; |
|||
} |
|||
.line-chart .apexcharts-svg{ |
|||
transform: translateY(3px); |
|||
} |
|||
display: none; |
|||
} |
|||
.line-chart .apexcharts-svg { |
|||
transform: translateY(3px); |
|||
} |
|||
|
@ -1,3 +1,3 @@ |
|||
import { createConfigForNuxt } from '@nuxt/eslint-config/flat' |
|||
import { createConfigForNuxt } from '@nuxt/eslint-config/flat'; |
|||
|
|||
export default createConfigForNuxt({}) |
|||
export default createConfigForNuxt({}); |
|||
|
File diff suppressed because it is too large
@ -1,5 +1,5 @@ |
|||
export default defineNuxtRouteMiddleware(async (to) => { |
|||
if (REQUIRES_PASSWORD || !to.path.startsWith('/api/')) { |
|||
return abortNavigation(); |
|||
} |
|||
}) |
|||
if (REQUIRES_PASSWORD || !to.path.startsWith('/api/')) { |
|||
return abortNavigation(); |
|||
} |
|||
}); |
|||
|
File diff suppressed because it is too large
@ -1,11 +1,11 @@ |
|||
{ |
|||
"name": "WireGuard", |
|||
"display": "standalone", |
|||
"background_color": "#fff", |
|||
"icons": [ |
|||
{ |
|||
"src": "/favicon.png", |
|||
"type": "image/png" |
|||
} |
|||
] |
|||
} |
|||
"name": "WireGuard", |
|||
"display": "standalone", |
|||
"background_color": "#fff", |
|||
"icons": [ |
|||
{ |
|||
"src": "/favicon.png", |
|||
"type": "image/png" |
|||
} |
|||
] |
|||
} |
|||
|
@ -1,7 +1,7 @@ |
|||
import { LANG } from "~/utils/config"; |
|||
import { LANG } from '~/utils/config'; |
|||
|
|||
export default defineEventHandler((event) => { |
|||
assertMethod(event, "GET"); |
|||
setHeader(event, 'Content-Type', 'application/json'); |
|||
return `"${LANG}"`; |
|||
}) |
|||
assertMethod(event, 'GET'); |
|||
setHeader(event, 'Content-Type', 'application/json'); |
|||
return `"${LANG}"`; |
|||
}); |
|||
|
@ -1,7 +1,7 @@ |
|||
import { RELEASE } from "~/utils/config"; |
|||
import { RELEASE } from '~/utils/config'; |
|||
|
|||
export default defineEventHandler((event) => { |
|||
assertMethod(event, "GET"); |
|||
setHeader(event, 'Content-Type', 'application/json'); |
|||
return RELEASE; |
|||
}) |
|||
assertMethod(event, 'GET'); |
|||
setHeader(event, 'Content-Type', 'application/json'); |
|||
return RELEASE; |
|||
}); |
|||
|
@ -1,51 +1,55 @@ |
|||
import { REQUIRES_PASSWORD, SERVER_DEBUG, SESSION_CONFIG } from "~/utils/config"; |
|||
import { isPasswordValid } from "~/utils/password"; |
|||
import { |
|||
REQUIRES_PASSWORD, |
|||
SERVER_DEBUG, |
|||
SESSION_CONFIG, |
|||
} from '~/utils/config'; |
|||
import { isPasswordValid } from '~/utils/password'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
if (isMethod(event, "GET")) { |
|||
const session = await useSession(event, SESSION_CONFIG); |
|||
const authenticated = REQUIRES_PASSWORD |
|||
? !!(session.data && session.data.authenticated) |
|||
: true; |
|||
|
|||
return { |
|||
REQUIRES_PASSWORD, |
|||
authenticated, |
|||
}; |
|||
} else if (isMethod(event, "POST")) { |
|||
const session = await useSession(event, SESSION_CONFIG); |
|||
const { password } = await readBody(event); |
|||
|
|||
if (!REQUIRES_PASSWORD) { |
|||
// if no password is required, the API should never be called.
|
|||
// Do not automatically authenticate the user.
|
|||
throw createError({ |
|||
status: 401, |
|||
message: 'Invalid state', |
|||
}); |
|||
} |
|||
|
|||
if (!isPasswordValid(password)) { |
|||
throw createError({ |
|||
status: 401, |
|||
message: 'Incorrect Password', |
|||
}); |
|||
} |
|||
|
|||
const data = await session.update({ |
|||
authenticated: true |
|||
}); |
|||
|
|||
SERVER_DEBUG(`New Session: ${data.id}`); |
|||
|
|||
return { success: true }; |
|||
} else if (isMethod(event, "DELETE")) { |
|||
const session = await useSession(event, SESSION_CONFIG); |
|||
const sessionId = session.id; |
|||
|
|||
await session.clear(); |
|||
|
|||
SERVER_DEBUG(`Deleted Session: ${sessionId}`); |
|||
return { success: true }; |
|||
if (isMethod(event, 'GET')) { |
|||
const session = await useSession(event, SESSION_CONFIG); |
|||
const authenticated = REQUIRES_PASSWORD |
|||
? !!(session.data && session.data.authenticated) |
|||
: true; |
|||
|
|||
return { |
|||
REQUIRES_PASSWORD, |
|||
authenticated, |
|||
}; |
|||
} else if (isMethod(event, 'POST')) { |
|||
const session = await useSession(event, SESSION_CONFIG); |
|||
const { password } = await readBody(event); |
|||
|
|||
if (!REQUIRES_PASSWORD) { |
|||
// if no password is required, the API should never be called.
|
|||
// Do not automatically authenticate the user.
|
|||
throw createError({ |
|||
status: 401, |
|||
message: 'Invalid state', |
|||
}); |
|||
} |
|||
}) |
|||
|
|||
if (!isPasswordValid(password)) { |
|||
throw createError({ |
|||
status: 401, |
|||
message: 'Incorrect Password', |
|||
}); |
|||
} |
|||
|
|||
const data = await session.update({ |
|||
authenticated: true, |
|||
}); |
|||
|
|||
SERVER_DEBUG(`New Session: ${data.id}`); |
|||
|
|||
return { success: true }; |
|||
} else if (isMethod(event, 'DELETE')) { |
|||
const session = await useSession(event, SESSION_CONFIG); |
|||
const sessionId = session.id; |
|||
|
|||
await session.clear(); |
|||
|
|||
SERVER_DEBUG(`Deleted Session: ${sessionId}`); |
|||
return { success: true }; |
|||
} |
|||
}); |
|||
|
@ -1,7 +1,7 @@ |
|||
import { UI_CHART_TYPE } from "~/utils/config"; |
|||
import { UI_CHART_TYPE } from '~/utils/config'; |
|||
|
|||
export default defineEventHandler((event) => { |
|||
assertMethod(event, "GET"); |
|||
setHeader(event, 'Content-Type', 'application/json'); |
|||
return `"${UI_CHART_TYPE}"`; |
|||
}) |
|||
assertMethod(event, 'GET'); |
|||
setHeader(event, 'Content-Type', 'application/json'); |
|||
return `"${UI_CHART_TYPE}"`; |
|||
}); |
|||
|
@ -1,7 +1,7 @@ |
|||
import { UI_TRAFFIC_STATS } from "~/utils/config"; |
|||
import { UI_TRAFFIC_STATS } from '~/utils/config'; |
|||
|
|||
export default defineEventHandler((event) => { |
|||
assertMethod(event, "GET"); |
|||
setHeader(event, 'Content-Type', 'application/json'); |
|||
return `"${UI_TRAFFIC_STATS}"`; |
|||
}) |
|||
assertMethod(event, 'GET'); |
|||
setHeader(event, 'Content-Type', 'application/json'); |
|||
return `"${UI_TRAFFIC_STATS}"`; |
|||
}); |
|||
|
@ -1,9 +1,9 @@ |
|||
import WireGuard from "~/utils/WireGuard"; |
|||
import WireGuard from '~/utils/WireGuard'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
assertMethod(event, "GET"); |
|||
const config = await WireGuard.backupConfiguration(); |
|||
setHeader(event, 'Content-Disposition', 'attachment; filename="wg0.json"'); |
|||
setHeader(event, 'Content-Type', 'text/json'); |
|||
return config; |
|||
}) |
|||
assertMethod(event, 'GET'); |
|||
const config = await WireGuard.backupConfiguration(); |
|||
setHeader(event, 'Content-Disposition', 'attachment; filename="wg0.json"'); |
|||
setHeader(event, 'Content-Type', 'text/json'); |
|||
return config; |
|||
}); |
|||
|
@ -1,12 +1,16 @@ |
|||
import WireGuard from "~/utils/WireGuard"; |
|||
import WireGuard from '~/utils/WireGuard'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
assertMethod(event, "PUT"); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
if (clientId === '__proto__' || clientId === 'constructor' || clientId === 'prototype') { |
|||
throw createError({ status: 403 }); |
|||
} |
|||
const { address } = await readBody(event); |
|||
await WireGuard.updateClientAddress({ clientId, address }); |
|||
return { success: true }; |
|||
}) |
|||
assertMethod(event, 'PUT'); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
if ( |
|||
clientId === '__proto__' || |
|||
clientId === 'constructor' || |
|||
clientId === 'prototype' |
|||
) { |
|||
throw createError({ status: 403 }); |
|||
} |
|||
const { address } = await readBody(event); |
|||
await WireGuard.updateClientAddress({ clientId, address }); |
|||
return { success: true }; |
|||
}); |
|||
|
@ -1,16 +1,20 @@ |
|||
import WireGuard from "~/utils/WireGuard"; |
|||
import WireGuard from '~/utils/WireGuard'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
assertMethod(event, "GET"); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
const client = await WireGuard.getClient({ clientId }); |
|||
const config = await WireGuard.getClientConfiguration({ clientId }); |
|||
const configName = client.name |
|||
.replace(/[^a-zA-Z0-9_=+.-]/g, '-') |
|||
.replace(/(-{2,}|-$)/g, '-') |
|||
.replace(/-$/, '') |
|||
.substring(0, 32); |
|||
setHeader(event, 'Content-Disposition', `attachment; filename="${configName || clientId}.conf"`); |
|||
setHeader(event, 'Content-Type', 'text/plain'); |
|||
return config; |
|||
}) |
|||
assertMethod(event, 'GET'); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
const client = await WireGuard.getClient({ clientId }); |
|||
const config = await WireGuard.getClientConfiguration({ clientId }); |
|||
const configName = client.name |
|||
.replace(/[^a-zA-Z0-9_=+.-]/g, '-') |
|||
.replace(/(-{2,}|-$)/g, '-') |
|||
.replace(/-$/, '') |
|||
.substring(0, 32); |
|||
setHeader( |
|||
event, |
|||
'Content-Disposition', |
|||
`attachment; filename="${configName || clientId}.conf"` |
|||
); |
|||
setHeader(event, 'Content-Type', 'text/plain'); |
|||
return config; |
|||
}); |
|||
|
@ -1,11 +1,15 @@ |
|||
import WireGuard from "~/utils/WireGuard"; |
|||
import WireGuard from '~/utils/WireGuard'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
assertMethod(event, "POST"); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
if (clientId === '__proto__' || clientId === 'constructor' || clientId === 'prototype') { |
|||
throw createError({ status: 403 }); |
|||
} |
|||
await WireGuard.disableClient({ clientId }); |
|||
return { success: true }; |
|||
}) |
|||
assertMethod(event, 'POST'); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
if ( |
|||
clientId === '__proto__' || |
|||
clientId === 'constructor' || |
|||
clientId === 'prototype' |
|||
) { |
|||
throw createError({ status: 403 }); |
|||
} |
|||
await WireGuard.disableClient({ clientId }); |
|||
return { success: true }; |
|||
}); |
|||
|
@ -1,11 +1,15 @@ |
|||
import WireGuard from "~/utils/WireGuard"; |
|||
import WireGuard from '~/utils/WireGuard'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
assertMethod(event, "POST"); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
if (clientId === '__proto__' || clientId === 'constructor' || clientId === 'prototype') { |
|||
throw createError({ status: 403 }); |
|||
} |
|||
await WireGuard.enableClient({ clientId }); |
|||
return { success: true }; |
|||
}) |
|||
assertMethod(event, 'POST'); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
if ( |
|||
clientId === '__proto__' || |
|||
clientId === 'constructor' || |
|||
clientId === 'prototype' |
|||
) { |
|||
throw createError({ status: 403 }); |
|||
} |
|||
await WireGuard.enableClient({ clientId }); |
|||
return { success: true }; |
|||
}); |
|||
|
@ -1,8 +1,8 @@ |
|||
import WireGuard from "~/utils/WireGuard"; |
|||
import WireGuard from '~/utils/WireGuard'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
assertMethod(event, "DELETE"); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
await WireGuard.deleteClient({ clientId }); |
|||
return { success: true }; |
|||
assertMethod(event, 'DELETE'); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
await WireGuard.deleteClient({ clientId }); |
|||
return { success: true }; |
|||
}); |
@ -1,12 +1,16 @@ |
|||
import WireGuard from "~/utils/WireGuard"; |
|||
import WireGuard from '~/utils/WireGuard'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
assertMethod(event, "PUT"); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
if (clientId === '__proto__' || clientId === 'constructor' || clientId === 'prototype') { |
|||
throw createError({ status: 403 }); |
|||
} |
|||
const { name } = await readBody(event); |
|||
await WireGuard.updateClientName({ clientId, name }); |
|||
return { success: true }; |
|||
}) |
|||
assertMethod(event, 'PUT'); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
if ( |
|||
clientId === '__proto__' || |
|||
clientId === 'constructor' || |
|||
clientId === 'prototype' |
|||
) { |
|||
throw createError({ status: 403 }); |
|||
} |
|||
const { name } = await readBody(event); |
|||
await WireGuard.updateClientName({ clientId, name }); |
|||
return { success: true }; |
|||
}); |
|||
|
@ -1,9 +1,9 @@ |
|||
import WireGuard from "~/utils/WireGuard"; |
|||
import WireGuard from '~/utils/WireGuard'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
assertMethod(event, "GET"); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
const svg = await WireGuard.getClientQRCodeSVG({ clientId }); |
|||
setHeader(event, 'Content-Type', 'image/svg+xml'); |
|||
return svg; |
|||
}) |
|||
assertMethod(event, 'GET'); |
|||
const clientId = getRouterParam(event, 'clientId'); |
|||
const svg = await WireGuard.getClientQRCodeSVG({ clientId }); |
|||
setHeader(event, 'Content-Type', 'image/svg+xml'); |
|||
return svg; |
|||
}); |
|||
|
@ -1,11 +1,11 @@ |
|||
import WireGuard from "~/utils/WireGuard"; |
|||
import WireGuard from '~/utils/WireGuard'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
if (isMethod(event, "GET")) { |
|||
return WireGuard.getClients(); |
|||
} else if (isMethod(event, "POST")) { |
|||
const { name } = await readBody(event); |
|||
await WireGuard.createClient({ name }); |
|||
return { success: true }; |
|||
} |
|||
}) |
|||
if (isMethod(event, 'GET')) { |
|||
return WireGuard.getClients(); |
|||
} else if (isMethod(event, 'POST')) { |
|||
const { name } = await readBody(event); |
|||
await WireGuard.createClient({ name }); |
|||
return { success: true }; |
|||
} |
|||
}); |
|||
|
@ -1,8 +1,8 @@ |
|||
import WireGuard from "~/utils/WireGuard"; |
|||
import WireGuard from '~/utils/WireGuard'; |
|||
|
|||
export default defineEventHandler(async (event) => { |
|||
assertMethod(event, "PUT"); |
|||
const { file } = await readBody(event); |
|||
await WireGuard.restoreConfiguration(file); |
|||
return { success: true }; |
|||
}) |
|||
assertMethod(event, 'PUT'); |
|||
const { file } = await readBody(event); |
|||
await WireGuard.restoreConfiguration(file); |
|||
return { success: true }; |
|||
}); |
|||
|
@ -1,24 +1,29 @@ |
|||
import childProcess from 'child_process'; |
|||
|
|||
export function exec(cmd: string, {log}: {log: boolean|string} = {log: true}) { |
|||
if (typeof log === 'string') { |
|||
|
|||
console.log(`$ ${log}`); |
|||
} else if (log === true) { |
|||
|
|||
console.log(`$ ${cmd}`); |
|||
} |
|||
export function exec( |
|||
cmd: string, |
|||
{ log }: { log: boolean | string } = { log: true } |
|||
) { |
|||
if (typeof log === 'string') { |
|||
console.log(`$ ${log}`); |
|||
} else if (log === true) { |
|||
console.log(`$ ${cmd}`); |
|||
} |
|||
|
|||
if (process.platform !== 'linux') { |
|||
return Promise.resolve(""); |
|||
} |
|||
if (process.platform !== 'linux') { |
|||
return Promise.resolve(''); |
|||
} |
|||
|
|||
return new Promise((resolve, reject) => { |
|||
childProcess.exec(cmd, { |
|||
return new Promise((resolve, reject) => { |
|||
childProcess.exec( |
|||
cmd, |
|||
{ |
|||
shell: 'bash', |
|||
}, (err, stdout) => { |
|||
}, |
|||
(err, stdout) => { |
|||
if (err) return reject(err); |
|||
return resolve(String(stdout).trim()); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
); |
|||
}); |
|||
} |
|||
|
@ -1,5 +1,7 @@ |
|||
export function getRandomHex(size: number) { |
|||
const array = new Uint8Array(size); |
|||
crypto.getRandomValues(array); |
|||
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join(''); |
|||
const array = new Uint8Array(size); |
|||
crypto.getRandomValues(array); |
|||
return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join( |
|||
'' |
|||
); |
|||
} |
@ -1,12 +1,12 @@ |
|||
export function isValidIPv4(str) { |
|||
const blocks = str.split('.'); |
|||
if (blocks.length !== 4) return false; |
|||
const blocks = str.split('.'); |
|||
if (blocks.length !== 4) return false; |
|||
|
|||
for (let value of blocks) { |
|||
value = parseInt(value, 10); |
|||
if (Number.isNaN(value)) return false; |
|||
if (value < 0 || value > 255) return false; |
|||
} |
|||
|
|||
return true; |
|||
for (let value of blocks) { |
|||
value = parseInt(value, 10); |
|||
if (Number.isNaN(value)) return false; |
|||
if (value < 0 || value > 255) return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
@ -1,25 +1,30 @@ |
|||
export type Theme = 'light' | 'dark' | 'auto' |
|||
export type Theme = 'light' | 'dark' | 'auto'; |
|||
|
|||
export type LocalStorage = { |
|||
theme: Theme, |
|||
uiShowCharts: '1' | '0', |
|||
lang: string |
|||
} |
|||
theme: Theme; |
|||
uiShowCharts: '1' | '0'; |
|||
lang: string; |
|||
}; |
|||
|
|||
export function getItem<K extends keyof LocalStorage>(item: K): LocalStorage[K]|null { |
|||
if (import.meta.client) { |
|||
return localStorage.getItem(item) as LocalStorage[K]|null |
|||
} else { |
|||
return null |
|||
} |
|||
export function getItem<K extends keyof LocalStorage>( |
|||
item: K |
|||
): LocalStorage[K] | null { |
|||
if (import.meta.client) { |
|||
return localStorage.getItem(item) as LocalStorage[K] | null; |
|||
} else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
export function setItem<K extends keyof LocalStorage>(item: K, value: LocalStorage[K]) { |
|||
if (import.meta.client) { |
|||
localStorage.setItem(item, value) |
|||
export function setItem<K extends keyof LocalStorage>( |
|||
item: K, |
|||
value: LocalStorage[K] |
|||
) { |
|||
if (import.meta.client) { |
|||
localStorage.setItem(item, value); |
|||
|
|||
return true |
|||
} else { |
|||
return false |
|||
} |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
Loading…
Reference in new issue