feature: the package installs the Router Manager, which is no longer a package of its own.
Release / release (push) Failing after 4s
Release / release (push) Failing after 4s
This commit is contained in:
1 parent
6d90441bee
commit
8efe21bfa6
129 files changed
+17381
-104
No files matched your search
@@ -0,0 +1,104 @@
|
||||
import type { WireGuardServer } from './api.ts'
|
||||
|
||||
/**
|
||||
* The WireGuard configuration of a device: its address, a placeholder for its private key, which the router never has,
|
||||
* the router's resolver as its DNS server while it runs, and the router as its peer, with the router's public key,
|
||||
* endpoint and allowed IPs.
|
||||
*/
|
||||
export function clientConfig(server: WireGuardServer, address: string): string {
|
||||
return [
|
||||
'[Interface]',
|
||||
'PrivateKey = <the private key of this device>',
|
||||
`Address = ${address}`,
|
||||
...(server.dns.length ? [`DNS = ${server.dns.join(', ')}`] : []),
|
||||
'',
|
||||
'[Peer]',
|
||||
`PublicKey = ${server.public_key}`,
|
||||
`Endpoint = ${server.endpoint}`,
|
||||
`AllowedIPs = ${server.allowed_ips.join(', ')}`,
|
||||
'PersistentKeepalive = 25',
|
||||
'',
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
/** An IPv4 address as a number, or null when the text is not one. */
|
||||
function addressOf(text: string): number | null {
|
||||
const parts = text.split('.')
|
||||
if (parts.length !== 4 || !parts.every((part) => /^(0|[1-9]\d{0,2})$/.test(part) && Number(part) <= 255)) {
|
||||
return null
|
||||
}
|
||||
return parts.reduce((value, part) => value * 256 + Number(part), 0)
|
||||
}
|
||||
|
||||
/** A number as an IPv4 address. */
|
||||
function textOf(value: number): string {
|
||||
return [24, 16, 8, 0].map((shift) => Math.floor(value / 2 ** shift) % 256).join('.')
|
||||
}
|
||||
|
||||
/** An IPv4 address or network, a.b.c.d or a.b.c.d/n, as its first address and size, or null when it is not one. */
|
||||
function networkOf(text: string, strict: boolean): { first: number; size: number } | null {
|
||||
const [address, prefix, ...rest] = text.trim().split('/')
|
||||
const value = addressOf(address)
|
||||
const length = prefix === undefined ? 32 : /^\d{1,2}$/.test(prefix) ? Number(prefix) : NaN
|
||||
if (value === null || rest.length > 0 || !(length >= 0 && length <= 32)) {
|
||||
return null
|
||||
}
|
||||
const size = 2 ** (32 - length)
|
||||
const first = value - (value % size)
|
||||
return strict && first !== value ? null : { first, size }
|
||||
}
|
||||
|
||||
/**
|
||||
* Why the router's own WireGuard address with its prefix, wireguard.address, is refused, or '' when it is an address of
|
||||
* its network other than the network's and the broadcast address, as the router requires.
|
||||
*/
|
||||
export function routerAddressProblem(text: string): string {
|
||||
const network = networkOf(text, false)
|
||||
const own = addressOf(text.trim().split('/')[0])
|
||||
if (network === null || own === null || !text.includes('/')) {
|
||||
return 'An IPv4 address with a prefix length, such as 192.168.200.1/24.'
|
||||
}
|
||||
if (network.size > 2 && (own === network.first || own === network.first + network.size - 1)) {
|
||||
return `The network or broadcast address of its network; give the router's own address in it, such as ${textOf(network.first + 1)}/${32 - Math.log2(network.size)}.`
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
/** Why a WireGuard public key is refused, or '' when it is 32 bytes in base64. */
|
||||
export function keyProblem(key: string): string {
|
||||
return /^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$/.test(key.trim()) ? '' : 'A WireGuard public key: 44 characters of base64 ending with =.'
|
||||
}
|
||||
|
||||
/** Why a list of a peer's IPs, separated by commas, is refused, or '' when each is an IPv4 address or network. */
|
||||
export function ipsProblem(text: string): string {
|
||||
const ips = ipsOf(text)
|
||||
if (ips.length === 0) {
|
||||
return 'At least one IP.'
|
||||
}
|
||||
const wrong = ips.find((ip) => networkOf(ip, true) === null)
|
||||
return wrong === undefined ? '' : `${wrong} is not an IPv4 address or network, such as 10.10.0.2 or 10.20.0.0/24.`
|
||||
}
|
||||
|
||||
/** The IPs of a list separated by commas, a single address written as /32. */
|
||||
export function ipsOf(text: string): string[] {
|
||||
return text.split(',').map((ip) => ip.trim()).filter((ip) => ip !== '').map((ip) => (ip.includes('/') ? ip : `${ip}/32`))
|
||||
}
|
||||
|
||||
/**
|
||||
* The first address of the network of the router's address (wireguard.address, such as 192.168.200.1/24) that is
|
||||
* neither the router's own nor covered by one of the taken IPs, as a.b.c.d/32; '' when there is none.
|
||||
*/
|
||||
export function nextFreeAddress(routerAddress: string, taken: string[]): string {
|
||||
const router = networkOf(routerAddress, false)
|
||||
const own = addressOf(routerAddress.split('/')[0])
|
||||
if (router === null || own === null) {
|
||||
return ''
|
||||
}
|
||||
const used = taken.map((ip) => networkOf(ip, false)).filter((network) => network !== null)
|
||||
for (let value = router.first + 1; value < router.first + router.size - 1; value += 1) {
|
||||
if (value !== own && !used.some((network) => value >= network.first && value < network.first + network.size)) {
|
||||
return `${textOf(value)}/32`
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
Reference in new issue
Block a user