36 lines
2.5 KiB
Java
36 lines
2.5 KiB
Java
package ru.kusoft.qsafe;
|
|
|
|
import java.io.IOException;
|
|
import java.net.*;
|
|
|
|
/** Pure validation: never resolves DNS and never opens a socket. */
|
|
public final class LanPolicy {
|
|
private LanPolicy() {}
|
|
public static byte[] ipv4(String text) throws IOException {
|
|
if(text==null||!text.matches("[0-9]{1,3}(\\.[0-9]{1,3}){3}"))throw new IOException("Нужен локальный IPv4 Pi, без доменного имени");
|
|
String[] parts=text.split("\\.");byte[] out=new byte[4];
|
|
for(int i=0;i<4;i++){int value=Integer.parseInt(parts[i]);if(value>255||(parts[i].length()>1&&parts[i].charAt(0)=='0'))throw new IOException("Неверный IPv4");out[i]=(byte)value;}
|
|
int a=out[0]&255,b=out[1]&255;
|
|
if(!(a==10||a==172&&b>=16&&b<=31||a==192&&b==168))throw new IOException("Внешние адреса базы запрещены. Нужен локальный IPv4 Pi");
|
|
return out;
|
|
}
|
|
public static String url(String address) throws IOException {
|
|
try {
|
|
URI uri=new URI(address==null?"":address.trim());
|
|
if(!"https".equalsIgnoreCase(uri.getScheme())||uri.getHost()==null||uri.getRawUserInfo()!=null||uri.getRawQuery()!=null||uri.getRawFragment()!=null)throw new IOException("Нужен локальный HTTPS-адрес Pi без логина и параметров");
|
|
ipv4(uri.getHost());String result=uri.toASCIIString();return result.endsWith("/")?result:result+"/";
|
|
}catch(URISyntaxException e){throw new IOException("Неверный адрес Pi",e);}
|
|
}
|
|
public static void identity(String ssid,String pin)throws IOException {
|
|
if(ssid==null||ssid.isEmpty()||ssid.getBytes(java.nio.charset.StandardCharsets.UTF_8).length>32)throw new IOException("Укажите точное имя домашнего Wi-Fi");
|
|
if(pin==null||!pin.matches("[0-9a-fA-F]{64}"))throw new IOException("Нужен SHA-256 локального сертификата Pi из файла подключения");
|
|
}
|
|
public static boolean sameSubnet(byte[] target,byte[] local,int prefix) {
|
|
if(target.length!=4||local.length!=4||prefix<16||prefix>30||java.util.Arrays.equals(target,local))return false;
|
|
long value=0;for(byte b:target)value=value<<8|(b&255);long hostMask=(1L<<(32-prefix))-1;
|
|
if((value&hostMask)==0||(value&hostMask)==hostMask)return false;
|
|
for(int i=0;i<4;i++){int bits=Math.max(0,Math.min(8,prefix-i*8));int mask=255<<(8-bits)&255;if((target[i]&mask)!=(local[i]&mask))return false;}
|
|
return true;
|
|
}
|
|
}
|