sub: kcp finalmask

This commit is contained in:
MHSanaei 2026-04-26 23:04:47 +02:00
parent 8529f4f0cf
commit 0aca2d3b3d
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A
4 changed files with 731 additions and 615 deletions

File diff suppressed because it is too large Load diff

View file

@ -1370,6 +1370,50 @@ class Inbound extends XrayCommonClass {
}
}
static hasShareableFinalMaskValue(value) {
if (value == null) {
return false;
}
if (Array.isArray(value)) {
return value.some(item => Inbound.hasShareableFinalMaskValue(item));
}
if (typeof value === 'object') {
return Object.values(value).some(item => Inbound.hasShareableFinalMaskValue(item));
}
if (typeof value === 'string') {
return value.length > 0;
}
return true;
}
static serializeFinalMask(finalmask) {
if (!finalmask) {
return '';
}
const value = typeof finalmask.toJson === 'function' ? finalmask.toJson() : finalmask;
return Inbound.hasShareableFinalMaskValue(value) ? JSON.stringify(value) : '';
}
// Export finalmask with the same compact JSON payload shape that
// v2rayN-compatible share links use: fm=<json>.
static applyFinalMaskToParams(finalmask, params) {
if (!params) return;
const payload = Inbound.serializeFinalMask(finalmask);
if (payload.length > 0) {
params.set("fm", payload);
}
}
// VMess links are a base64 JSON object, so keep the same fm payload
// under a flat property instead of a URL query string.
static applyFinalMaskToObj(finalmask, obj) {
if (!obj) return;
const payload = Inbound.serializeFinalMask(finalmask);
if (payload.length > 0) {
obj.fm = payload;
}
}
get clients() {
switch (this.protocol) {
case Protocols.VMESS: return this.settings.vmesses;
@ -1590,6 +1634,8 @@ class Inbound extends XrayCommonClass {
Inbound.applyXhttpPaddingToObj(xhttp, obj);
}
Inbound.applyFinalMaskToObj(this.stream.finalmask, obj);
if (tls === 'tls') {
if (!ObjectUtil.isEmpty(this.stream.tls.sni)) {
obj.sni = this.stream.tls.sni;
@ -1658,6 +1704,8 @@ class Inbound extends XrayCommonClass {
break;
}
Inbound.applyFinalMaskToParams(this.stream.finalmask, params);
if (security === 'tls') {
params.set("security", "tls");
if (this.stream.isTls) {
@ -1761,6 +1809,8 @@ class Inbound extends XrayCommonClass {
break;
}
Inbound.applyFinalMaskToParams(this.stream.finalmask, params);
if (security === 'tls') {
params.set("security", "tls");
if (this.stream.isTls) {
@ -1840,6 +1890,8 @@ class Inbound extends XrayCommonClass {
break;
}
Inbound.applyFinalMaskToParams(this.stream.finalmask, params);
if (security === 'tls') {
params.set("security", "tls");
if (this.stream.isTls) {
@ -1907,6 +1959,8 @@ class Inbound extends XrayCommonClass {
}
}
Inbound.applyFinalMaskToParams(this.stream.finalmask, params);
const url = new URL(link);
for (const [key, value] of params) {
url.searchParams.set(key, value);

View file

@ -992,6 +992,10 @@ class Outbound extends CommonClass {
stream.kcp = new KcpStreamSettings();
stream.type = json.type;
stream.seed = json.path;
const mtu = Number(json.mtu);
if (Number.isFinite(mtu) && mtu > 0) stream.kcp.mtu = mtu;
const tti = Number(json.tti);
if (Number.isFinite(tti) && tti > 0) stream.kcp.tti = tti;
} else if (network === 'ws') {
stream.ws = new WsStreamSettings(json.path, json.host);
} else if (network === 'grpc') {
@ -1029,6 +1033,7 @@ class Outbound extends CommonClass {
let headerType = url.searchParams.get('headerType') ?? undefined;
let host = url.searchParams.get('host') ?? undefined;
let path = url.searchParams.get('path') ?? undefined;
let seed = url.searchParams.get('seed') ?? path ?? undefined;
let mode = url.searchParams.get('mode') ?? undefined;
if (type === 'tcp' || type === 'none') {
@ -1036,7 +1041,11 @@ class Outbound extends CommonClass {
} else if (type === 'kcp') {
stream.kcp = new KcpStreamSettings();
stream.kcp.type = headerType ?? 'none';
stream.kcp.seed = path;
stream.kcp.seed = seed;
const mtu = Number(url.searchParams.get('mtu'));
if (Number.isFinite(mtu) && mtu > 0) stream.kcp.mtu = mtu;
const tti = Number(url.searchParams.get('tti'));
if (Number.isFinite(tti) && tti > 0) stream.kcp.tti = tti;
} else if (type === 'ws') {
stream.ws = new WsStreamSettings(path, host);
} else if (type === 'grpc') {

View file

@ -6,6 +6,23 @@
<script src="{{ .base_path }}assets/js/util/index.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/qrcode/qrious2.min.js?{{ .cur_ver }}"></script>
<style>
.subscription-page tr-qr-box.qr-box {
display: inline-flex;
flex-direction: column;
align-items: center;
width: 220px;
}
.subscription-page tr-qr-box.qr-box .qr-tag {
width: 100%;
justify-content: center;
}
.subscription-page tr-qr-box.qr-box .qr-bg,
.subscription-page tr-qr-box.qr-box .qr-bg-sub {
margin-inline: auto;
}
.subscription-page .subscription-link-box {
cursor: pointer;
border-radius: 12px;
@ -193,8 +210,6 @@
</div>
</div>
</div>
</div>
<br />
<a-form layout="vertical">