Files
VirtWeb/virtweb_frontend/src/widgets/forms/IPInput.tsx
Pierre HUBERT c7de64cc02
All checks were successful
continuous-integration/drone/push Build is passing
Add API tokens support (#9)
Make it possible to create token authorized to query predetermined set of routes.

Reviewed-on: #9
Co-authored-by: Pierre HUBERT <pierre.git@communiquons.org>
Co-committed-by: Pierre HUBERT <pierre.git@communiquons.org>
2024-04-23 17:04:43 +00:00

140 lines
3.3 KiB
TypeScript

import React from "react";
import { TextInput } from "./TextInput";
export function IPInput(p: {
label: string;
editable: boolean;
value?: string;
onValueChange?: (newVal: string | undefined) => void;
version: 4 | 6;
}): React.ReactElement {
const { onValueChange, ...props } = p;
return (
<TextInput
onValueChange={(v) => {
onValueChange?.(p.version === 4 ? sanitizeIpV4(v) : sanitizeIpV6(v));
}}
{...props}
/>
);
}
export function IPInputWithMask(p: {
label: string;
editable: boolean;
ipAndMask?: string;
ip?: string;
mask?: number;
onValueChange?: (ip?: string, mask?: number, ipAndMask?: string) => void;
version: 4 | 6;
}): React.ReactElement {
const showSlash = React.useRef(!!p.mask);
const currValue =
p.ipAndMask ??
(p.ip ?? "") + (p.mask || showSlash.current ? "/" : "") + (p.mask ?? "");
const { onValueChange, ...props } = p;
return (
<TextInput
onValueChange={(v) => {
showSlash.current = false;
if (!v) {
onValueChange?.(undefined, undefined, undefined);
return;
}
const split = v?.split("/");
const ip =
p.version === 4 ? sanitizeIpV4(split[0]) : sanitizeIpV6(split[0]);
let mask = undefined;
if (split.length > 1) {
showSlash.current = true;
mask = sanitizeMask(p.version, split[1]);
}
onValueChange?.(
ip,
mask,
mask || showSlash.current ? `${ip}/${mask ?? ""}` : ip
);
}}
value={currValue}
{...props}
/>
);
}
function sanitizeIpV4(s: string | undefined): string | undefined {
if (s === "" || s === undefined) return s;
let split = s.split(".");
if (split.length > 4) split.splice(4);
let needAnotherIteration = false;
const res = split
.map((v) => {
if (v === "") return "";
const num = Number(v);
if (isNaN(num) || num < 0) return "0";
if (num > 255) {
needAnotherIteration = true;
return v.slice(0, 2) + "." + v.slice(2);
}
return num.toString();
})
.join(".");
return needAnotherIteration ? sanitizeIpV4(res) : res;
}
function sanitizeIpV6(s: string | undefined): string | undefined {
if (s === "" || s === undefined) return s;
const split = s.split(":");
if (split.length > 8) split.splice(8);
let needAnotherIteration = false;
let res = split
.map((e) => {
if (e === "") return e;
const num = parseInt(e, 16);
if (isNaN(num)) return "0";
let s = num.toString(16);
if (num > 0xffff) {
needAnotherIteration = true;
return s.slice(0, 4) + ":" + s.slice(4);
}
return s;
})
.join(":");
const firstIndex = res.indexOf("::");
let nextIndex = res.lastIndexOf("::");
while (nextIndex !== firstIndex) {
res = res.slice(0, nextIndex) + res.slice(nextIndex + 1);
nextIndex = res.lastIndexOf("::");
}
return needAnotherIteration ? sanitizeIpV6(res) : res;
}
function sanitizeMask(version: 4 | 6, mask?: string): number | undefined {
if (!mask) return undefined;
const value = Math.floor(Number(mask));
if (version === 4) {
return value < 0 || value > 32 ? 32 : value;
} else {
return value < 0 || value > 128 ? 128 : value;
}
}