* mlkem768

* VlessEnc
This commit is contained in:
Sanaei 2025-09-07 22:35:38 +02:00 committed by GitHub
parent da6b89fdcd
commit b008ff4ad2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 215 additions and 42 deletions

View file

@ -106,3 +106,10 @@ type Client struct {
CreatedAt int64 `json:"created_at,omitempty"` CreatedAt int64 `json:"created_at,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"` UpdatedAt int64 `json:"updated_at,omitempty"`
} }
type VLESSSettings struct {
Clients []Client `json:"clients"`
Decryption string `json:"decryption"`
Encryption string `json:"encryption"`
Fallbacks []any `json:"fallbacks"`
}

View file

@ -53,7 +53,6 @@ func (a *SUBController) initRouter(g *gin.RouterGroup) {
gJson := g.Group(a.subJsonPath) gJson := g.Group(a.subJsonPath)
gLink.GET(":subid", a.subs) gLink.GET(":subid", a.subs)
gJson.GET(":subid", a.subJsons) gJson.GET(":subid", a.subJsons)
} }
@ -85,7 +84,7 @@ func (a *SUBController) subs(c *gin.Context) {
// Add headers // Add headers
c.Writer.Header().Set("Subscription-Userinfo", header) c.Writer.Header().Set("Subscription-Userinfo", header)
c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval) c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval)
c.Writer.Header().Set("Profile-Title", "base64:" + base64.StdEncoding.EncodeToString([]byte(a.subTitle))) c.Writer.Header().Set("Profile-Title", "base64:"+base64.StdEncoding.EncodeToString([]byte(a.subTitle)))
if a.subEncrypt { if a.subEncrypt {
c.String(200, base64.StdEncoding.EncodeToString([]byte(result))) c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
@ -119,7 +118,7 @@ func (a *SUBController) subJsons(c *gin.Context) {
// Add headers // Add headers
c.Writer.Header().Set("Subscription-Userinfo", header) c.Writer.Header().Set("Subscription-Userinfo", header)
c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval) c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval)
c.Writer.Header().Set("Profile-Title", "base64:" + base64.StdEncoding.EncodeToString([]byte(a.subTitle))) c.Writer.Header().Set("Profile-Title", "base64:"+base64.StdEncoding.EncodeToString([]byte(a.subTitle)))
c.String(200, jsonSub) c.String(200, jsonSub)
} }

View file

@ -184,8 +184,14 @@ func (s *SubJsonService) getConfig(inbound *model.Inbound, client model.Client,
var newOutbounds []json_util.RawMessage var newOutbounds []json_util.RawMessage
switch inbound.Protocol { switch inbound.Protocol {
case "vmess", "vless": case "vmess":
newOutbounds = append(newOutbounds, s.genVnext(inbound, streamSettings, client)) newOutbounds = append(newOutbounds, s.genVnext(inbound, streamSettings, client, ""))
case "vless":
var vlessSettings model.VLESSSettings
_ = json.Unmarshal([]byte(inbound.Settings), &vlessSettings)
newOutbounds = append(newOutbounds,
s.genVnext(inbound, streamSettings, client, vlessSettings.Encryption))
case "trojan", "shadowsocks": case "trojan", "shadowsocks":
newOutbounds = append(newOutbounds, s.genServer(inbound, streamSettings, client)) newOutbounds = append(newOutbounds, s.genServer(inbound, streamSettings, client))
} }
@ -284,7 +290,7 @@ func (s *SubJsonService) realityData(rData map[string]any) map[string]any {
return rltyData return rltyData
} }
func (s *SubJsonService) genVnext(inbound *model.Inbound, streamSettings json_util.RawMessage, client model.Client) json_util.RawMessage { func (s *SubJsonService) genVnext(inbound *model.Inbound, streamSettings json_util.RawMessage, client model.Client, encryption string) json_util.RawMessage {
outbound := Outbound{} outbound := Outbound{}
usersData := make([]UserVnext, 1) usersData := make([]UserVnext, 1)
@ -295,7 +301,7 @@ func (s *SubJsonService) genVnext(inbound *model.Inbound, streamSettings json_ut
} }
if inbound.Protocol == model.VLESS { if inbound.Protocol == model.VLESS {
usersData[0].Flow = client.Flow usersData[0].Flow = client.Flow
usersData[0].Encryption = "none" usersData[0].Encryption = encryption
} }
vnextData := make([]VnextSetting, 1) vnextData := make([]VnextSetting, 1)

View file

@ -313,6 +313,9 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
if inbound.Protocol != model.VLESS { if inbound.Protocol != model.VLESS {
return "" return ""
} }
var vlessSettings model.VLESSSettings
_ = json.Unmarshal([]byte(inbound.Settings), &vlessSettings)
var stream map[string]any var stream map[string]any
json.Unmarshal([]byte(inbound.StreamSettings), &stream) json.Unmarshal([]byte(inbound.StreamSettings), &stream)
clients, _ := s.inboundService.GetClients(inbound) clients, _ := s.inboundService.GetClients(inbound)
@ -327,6 +330,9 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
port := inbound.Port port := inbound.Port
streamNetwork := stream["network"].(string) streamNetwork := stream["network"].(string)
params := make(map[string]string) params := make(map[string]string)
if vlessSettings.Encryption != "" {
params["encryption"] = vlessSettings.Encryption
}
params["type"] = streamNetwork params["type"] = streamNetwork
switch streamNetwork { switch streamNetwork {

View file

@ -1301,6 +1301,7 @@ class Inbound extends XrayCommonClass {
const security = forceTls == 'same' ? this.stream.security : forceTls; const security = forceTls == 'same' ? this.stream.security : forceTls;
const params = new Map(); const params = new Map();
params.set("type", this.stream.network); params.set("type", this.stream.network);
params.set("encryption", this.settings.encryption);
switch (type) { switch (type) {
case "tcp": case "tcp":
const tcp = this.stream.tcp; const tcp = this.stream.tcp;
@ -1859,13 +1860,16 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
constructor( constructor(
protocol, protocol,
vlesses = [new Inbound.VLESSSettings.VLESS()], vlesses = [new Inbound.VLESSSettings.VLESS()],
decryption = 'none', decryption = "none",
fallbacks = [] encryption = "",
fallbacks = [],
) { ) {
super(protocol); super(protocol);
this.vlesses = vlesses; this.vlesses = vlesses;
this.decryption = decryption; this.decryption = decryption;
this.encryption = encryption;
this.fallbacks = fallbacks; this.fallbacks = fallbacks;
this.selectedAuth = "X25519, not Post-Quantum";
} }
addFallback() { addFallback() {
@ -1876,22 +1880,43 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
this.fallbacks.splice(index, 1); this.fallbacks.splice(index, 1);
} }
// decryption should be set to static value
static fromJson(json = {}) { static fromJson(json = {}) {
return new Inbound.VLESSSettings( const obj = new Inbound.VLESSSettings(
Protocols.VLESS, Protocols.VLESS,
json.clients.map(client => Inbound.VLESSSettings.VLESS.fromJson(client)), (json.clients || []).map(client => Inbound.VLESSSettings.VLESS.fromJson(client)),
json.decryption || 'none', json.decryption,
Inbound.VLESSSettings.Fallback.fromJson(json.fallbacks),); json.encryption,
Inbound.VLESSSettings.Fallback.fromJson(json.fallbacks || [])
);
obj.selectedAuth = json.selectedAuth || "X25519, not Post-Quantum";
return obj;
} }
toJson() { toJson() {
return { const json = {
clients: Inbound.VLESSSettings.toJsonArray(this.vlesses), clients: Inbound.VLESSSettings.toJsonArray(this.vlesses),
decryption: this.decryption,
fallbacks: Inbound.VLESSSettings.toJsonArray(this.fallbacks),
}; };
if (this.decryption) {
json.decryption = this.decryption;
} }
if (this.encryption) {
json.encryption = this.encryption;
}
if (this.fallbacks && this.fallbacks.length > 0) {
json.fallbacks = Inbound.VLESSSettings.toJsonArray(this.fallbacks);
}
if (this.selectedAuth) {
json.selectedAuth = this.selectedAuth;
}
return json;
}
}; };
Inbound.VLESSSettings.VLESS = class extends XrayCommonClass { Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {

View file

@ -813,7 +813,7 @@ class Outbound extends CommonClass {
var settings; var settings;
switch (protocol) { switch (protocol) {
case Protocols.VLESS: case Protocols.VLESS:
settings = new Outbound.VLESSSettings(address, port, userData, url.searchParams.get('flow') ?? ''); settings = new Outbound.VLESSSettings(address, port, userData, url.searchParams.get('flow') ?? '', url.searchParams.get('encryption') ?? 'none');
break; break;
case Protocols.Trojan: case Protocols.Trojan:
settings = new Outbound.TrojanSettings(address, port, userData); settings = new Outbound.TrojanSettings(address, port, userData);
@ -1046,13 +1046,13 @@ Outbound.VmessSettings = class extends CommonClass {
} }
}; };
Outbound.VLESSSettings = class extends CommonClass { Outbound.VLESSSettings = class extends CommonClass {
constructor(address, port, id, flow, encryption = 'none') { constructor(address, port, id, flow, encryption) {
super(); super();
this.address = address; this.address = address;
this.port = port; this.port = port;
this.id = id; this.id = id;
this.flow = flow; this.flow = flow;
this.encryption = encryption this.encryption = encryption;
} }
static fromJson(json = {}) { static fromJson(json = {}) {
@ -1071,7 +1071,7 @@ Outbound.VLESSSettings = class extends CommonClass {
vnext: [{ vnext: [{
address: this.address, address: this.address,
port: this.port, port: this.port,
users: [{ id: this.id, flow: this.flow, encryption: 'none', }], users: [{ id: this.id, flow: this.flow, encryption: this.encryption }],
}], }],
}; };
} }

View file

@ -55,6 +55,7 @@ func (a *ServerController) initRouter(g *gin.RouterGroup) {
g.POST("/getNewX25519Cert", a.getNewX25519Cert) g.POST("/getNewX25519Cert", a.getNewX25519Cert)
g.POST("/getNewmldsa65", a.getNewmldsa65) g.POST("/getNewmldsa65", a.getNewmldsa65)
g.POST("/getNewEchCert", a.getNewEchCert) g.POST("/getNewEchCert", a.getNewEchCert)
g.POST("/getNewVlessEnc", a.getNewVlessEnc)
} }
func (a *ServerController) refreshStatus() { func (a *ServerController) refreshStatus() {
@ -266,3 +267,12 @@ func (a *ServerController) getNewEchCert(c *gin.Context) {
} }
jsonObj(c, cert, nil) jsonObj(c, cert, nil)
} }
func (a *ServerController) getNewVlessEnc(c *gin.Context) {
out, err := a.serverService.GetNewVlessEnc()
if err != nil {
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.getNewVlessEncError"), err)
return
}
jsonObj(c, out, nil)
}

View file

@ -226,6 +226,11 @@
</template> </template>
<!-- vless settings --> <!-- vless settings -->
<template v-if="outbound.protocol === Protocols.VLESS">
<a-form-item label='encryption'>
<a-input v-model.trim="outbound.settings.encryption"></a-input>
</a-form-item>
</template>
<template v-if="outbound.canEnableTlsFlow()"> <template v-if="outbound.canEnableTlsFlow()">
<a-form-item label='Flow'> <a-form-item label='Flow'>
<a-select v-model="outbound.settings.flow" :dropdown-class-name="themeSwitcher.currentTheme"> <a-select v-model="outbound.settings.flow" :dropdown-class-name="themeSwitcher.currentTheme">

View file

@ -18,7 +18,29 @@
</table> </table>
</a-collapse-panel> </a-collapse-panel>
</a-collapse> </a-collapse>
<template v-if="inbound.isTcp"> <template v-if="!inbound.stream.isTLS || !inbound.stream.isReality">
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label="Authentication">
<a-select v-model="inbound.settings.selectedAuth" @change="getNewVlessEnc" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="X25519, not Post-Quantum">X25519 (not Post-Quantum)</a-select-option>
<a-select-option value="ML-KEM-768, Post-Quantum">ML-KEM-768 (Post-Quantum)</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="decryption">
<a-input v-model.trim="inbound.settings.decryption"></a-input>
</a-form-item>
<a-form-item label="encryption">
<a-input v-model="inbound.settings.encryption" disabled></a-input>
</a-form-item>
<a-form-item label=" ">
<a-space>
<a-button type="primary" icon="import" @click="getNewVlessEnc">Get New keys</a-button>
<a-button danger @click="clearKeys">Clear</a-button>
</a-space>
</a-form-item>
</a-form>
</template>
<template v-if="inbound.isTcp && !inbound.settings.encryption">
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label="Fallbacks"> <a-form-item label="Fallbacks">
<a-button icon="plus" type="primary" size="small" @click="inbound.settings.addFallback()"></a-button> <a-button icon="plus" type="primary" size="small" @click="inbound.settings.addFallback()"></a-button>

View file

@ -5,13 +5,13 @@
<a-form-item label='{{ i18n "security" }}'> <a-form-item label='{{ i18n "security" }}'>
<a-radio-group v-model="inbound.stream.security" button-style="solid"> <a-radio-group v-model="inbound.stream.security" button-style="solid">
<a-radio-button value="none">{{ i18n "none" }}</a-radio-button> <a-radio-button value="none">{{ i18n "none" }}</a-radio-button>
<a-radio-button v-if="inbound.canEnableReality()" value="reality">Reality</a-radio-button> <a-radio-button v-if="inbound.canEnableReality() && !inbound.settings.encryption" value="reality">Reality</a-radio-button>
<a-radio-button value="tls">TLS</a-radio-button> <a-radio-button v-if="!inbound.settings.encryption" value="tls">TLS</a-radio-button>
</a-radio-group> </a-radio-group>
</a-form-item> </a-form-item>
<!-- tls settings --> <!-- tls settings -->
<template v-if="inbound.stream.isTls"> <template v-if="inbound.stream.isTls && !inbound.settings.encryption">
<a-form-item label="SNI" placeholder="Server Name Indication"> <a-form-item label="SNI" placeholder="Server Name Indication">
<a-input v-model.trim="inbound.stream.tls.sni"></a-input> <a-input v-model.trim="inbound.stream.tls.sni"></a-input>
</a-form-item> </a-form-item>
@ -121,7 +121,7 @@
</template> </template>
<!-- reality settings --> <!-- reality settings -->
<template v-if="inbound.stream.isReality"> <template v-if="inbound.stream.isReality && !inbound.settings.encryption">
{{template "form/realitySettings"}} {{template "form/realitySettings"}}
</template> </template>
</a-form> </a-form>

View file

@ -706,7 +706,7 @@
}, { }, {
title: '{{ i18n "pages.inbounds.enable" }}', title: '{{ i18n "pages.inbounds.enable" }}',
align: 'center', align: 'center',
width: 30, width: 35,
scopedSlots: { customRender: 'enable' }, scopedSlots: { customRender: 'enable' },
}, { }, {
title: '{{ i18n "pages.inbounds.remark" }}', title: '{{ i18n "pages.inbounds.remark" }}',
@ -770,8 +770,8 @@
const innerColumns = [ const innerColumns = [
{ title: '{{ i18n "pages.inbounds.operate" }}', width: 65, scopedSlots: { customRender: 'actions' } }, { title: '{{ i18n "pages.inbounds.operate" }}', width: 65, scopedSlots: { customRender: 'actions' } },
{ title: '{{ i18n "pages.inbounds.enable" }}', width: 30, scopedSlots: { customRender: 'enable' } }, { title: '{{ i18n "pages.inbounds.enable" }}', width: 35, scopedSlots: { customRender: 'enable' } },
{ title: '{{ i18n "online" }}', width: 30, scopedSlots: { customRender: 'online' } }, { title: '{{ i18n "online" }}', width: 32, scopedSlots: { customRender: 'online' } },
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } }, { title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
{ title: '{{ i18n "pages.inbounds.traffic" }}', width: 80, align: 'center', scopedSlots: { customRender: 'traffic' } }, { title: '{{ i18n "pages.inbounds.traffic" }}', width: 80, align: 'center', scopedSlots: { customRender: 'traffic' } },
{ title: '{{ i18n "pages.inbounds.allTimeTraffic" }}', width: 80, align: 'center', scopedSlots: { customRender: 'allTime' } }, { title: '{{ i18n "pages.inbounds.allTimeTraffic" }}', width: 80, align: 'center', scopedSlots: { customRender: 'allTime' } },

View file

@ -101,6 +101,12 @@
{{ i18n "security" }} {{ i18n "security" }}
<a-tag :color="inbound.stream.security == 'none' ? 'red' : 'green'">[[ inbound.stream.security ]]</a-tag> <a-tag :color="inbound.stream.security == 'none' ? 'red' : 'green'">[[ inbound.stream.security ]]</a-tag>
<br /> <br />
<td>Authentication</td>
<a-tag :color="inbound.settings.selectedAuth ? 'green' : 'red'">[[ inbound.settings.selectedAuth ? inbound.settings.selectedAuth : '' ]]</a-tag>
<br />
{{ i18n "encryption" }}
<a-tag :color="inbound.settings.encryption ? 'green' : 'red'">[[ inbound.settings.encryption ? inbound.settings.encryption : '' ]]</a-tag>
<br />
<template v-if="inbound.stream.security != 'none'"> <template v-if="inbound.stream.security != 'none'">
{{ i18n "domainName" }} {{ i18n "domainName" }}
<a-tag v-if="inbound.serverName" :color="inbound.serverName ? 'green' : 'orange'">[[ inbound.serverName ? inbound.serverName : '' ]]</a-tag> <a-tag v-if="inbound.serverName" :color="inbound.serverName ? 'green' : 'orange'">[[ inbound.serverName ? inbound.serverName : '' ]]</a-tag>

View file

@ -1,9 +1,7 @@
{{define "modals/inboundModal"}} {{define "modals/inboundModal"}}
<a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title" <a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title" :dialog-style="{ top: '20px' }"
:dialog-style="{ top: '20px' }" @ok="inModal.ok" @ok="inModal.ok" :confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false"
:confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false" :class="themeSwitcher.currentTheme" :ok-text="inModal.okText" cancel-text='{{ i18n "close" }}'>
:class="themeSwitcher.currentTheme"
:ok-text="inModal.okText" cancel-text='{{ i18n "close" }}'>
{{template "form/inbound"}} {{template "form/inbound"}}
</a-modal> </a-modal>
<script> <script>
@ -20,7 +18,7 @@
ok() { ok() {
ObjectUtil.execute(inModal.confirm, inModal.inbound, inModal.dbInbound); ObjectUtil.execute(inModal.confirm, inModal.inbound, inModal.dbInbound);
}, },
show({ title = '', okText = '{{ i18n "sure" }}', inbound = null, dbInbound = null, confirm = (inbound, dbInbound) => {}, isEdit = false }) { show({ title = '', okText = '{{ i18n "sure" }}', inbound = null, dbInbound = null, confirm = (inbound, dbInbound) => { }, isEdit = false }) {
this.title = title; this.title = title;
this.okText = okText; this.okText = okText;
if (inbound) { if (inbound) {
@ -41,7 +39,7 @@
inModal.visible = false; inModal.visible = false;
inModal.loading(false); inModal.loading(false);
}, },
loading(loading=true) { loading(loading = true) {
inModal.confirmLoading = loading; inModal.confirmLoading = loading;
}, },
}; };
@ -107,7 +105,7 @@
this.inModal.inbound.settings.password = RandomUtil.randomShadowsocksPassword(this.inModal.inbound.settings.method) this.inModal.inbound.settings.password = RandomUtil.randomShadowsocksPassword(this.inModal.inbound.settings.method)
if (this.inModal.inbound.isSSMultiUser) { if (this.inModal.inbound.isSSMultiUser) {
if (this.inModal.inbound.settings.shadowsockses.length ==0){ if (this.inModal.inbound.settings.shadowsockses.length == 0) {
this.inModal.inbound.settings.shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()]; this.inModal.inbound.settings.shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()];
} }
if (!this.inModal.inbound.isSS2022) { if (!this.inModal.inbound.isSS2022) {
@ -123,7 +121,7 @@
client.password = RandomUtil.randomShadowsocksPassword(this.inModal.inbound.settings.method) client.password = RandomUtil.randomShadowsocksPassword(this.inModal.inbound.settings.method)
}) })
} else { } else {
if (this.inModal.inbound.settings.shadowsockses.length > 0){ if (this.inModal.inbound.settings.shadowsockses.length > 0) {
this.inModal.inbound.settings.shadowsockses = []; this.inModal.inbound.settings.shadowsockses = [];
} }
} }
@ -154,7 +152,7 @@
}, },
async getNewEchCert() { async getNewEchCert() {
inModal.loading(true); inModal.loading(true);
const msg = await HttpUtil.post('/server/getNewEchCert', {sni: inModal.inbound.stream.tls.sni}); const msg = await HttpUtil.post('/server/getNewEchCert', { sni: inModal.inbound.stream.tls.sni });
inModal.loading(false); inModal.loading(false);
if (!msg.success) { if (!msg.success) {
return; return;
@ -162,6 +160,32 @@
inModal.inbound.stream.tls.echServerKeys = msg.obj.echServerKeys; inModal.inbound.stream.tls.echServerKeys = msg.obj.echServerKeys;
inModal.inbound.stream.tls.settings.echConfigList = msg.obj.echConfigList; inModal.inbound.stream.tls.settings.echConfigList = msg.obj.echConfigList;
}, },
async getNewVlessEnc() {
inModal.loading(true);
const msg = await HttpUtil.post('/server/getNewVlessEnc');
inModal.loading(false);
if (!msg.success) {
return;
}
const auths = msg.obj.auths || [];
const selected = inModal.inbound.settings.selectedAuth;
const block = auths.find(a => a.label === selected);
if (!block) {
console.error("No auth block for", selected);
return;
}
inModal.inbound.settings.decryption = block.decryption;
inModal.inbound.settings.encryption = block.encryption;
},
clearKeys() {
this.inbound.settings.decryption = 'none';
this.inbound.settings.encryption = '';
}
}, },
}); });

View file

@ -871,3 +871,53 @@ func (s *ServerService) GetNewEchCert(sni string) (interface{}, error) {
"echConfigList": configList, "echConfigList": configList,
}, nil }, nil
} }
type AuthBlock struct {
Label string `json:"label"`
Decryption string `json:"decryption"`
Encryption string `json:"encryption"`
}
func (s *ServerService) GetNewVlessEnc() (any, error) {
cmd := exec.Command(xray.GetBinaryPath(), "vlessenc")
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return nil, err
}
lines := strings.Split(out.String(), "\n")
var blocks []AuthBlock
var current *AuthBlock
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "Authentication:") {
if current != nil {
blocks = append(blocks, *current)
}
current = &AuthBlock{Label: strings.TrimSpace(strings.TrimPrefix(line, "Authentication:"))}
} else if strings.HasPrefix(line, `"decryption"`) || strings.HasPrefix(line, `"encryption"`) {
parts := strings.SplitN(line, ":", 2)
if len(parts) == 2 && current != nil {
key := strings.Trim(parts[0], `" `)
val := strings.Trim(parts[1], `" `)
switch key {
case "decryption":
current.Decryption = val
case "encryption":
current.Encryption = val
}
}
}
}
if current != nil {
blocks = append(blocks, *current)
}
return map[string]any{
"auths": blocks,
}, nil
}

View file

@ -267,6 +267,7 @@
"trafficGetError" = "خطأ في الحصول على حركات المرور" "trafficGetError" = "خطأ في الحصول على حركات المرور"
"getNewX25519CertError" = "حدث خطأ أثناء الحصول على شهادة X25519." "getNewX25519CertError" = "حدث خطأ أثناء الحصول على شهادة X25519."
"getNewmldsa65Error" = "حدث خطاء في الحصول على mldsa65." "getNewmldsa65Error" = "حدث خطاء في الحصول على mldsa65."
"getNewVlessEncError" = "حدث خطأ أثناء الحصول على VlessEnc."
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "طلب" "request" = "طلب"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "Error getting traffics." "trafficGetError" = "Error getting traffics."
"getNewX25519CertError" = "Error while obtaining the X25519 certificate." "getNewX25519CertError" = "Error while obtaining the X25519 certificate."
"getNewmldsa65Error" = "Error while obtaining mldsa65." "getNewmldsa65Error" = "Error while obtaining mldsa65."
"getNewVlessEncError" = "Error while obtaining VlessEnc."
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "Request" "request" = "Request"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "Error al obtener los tráficos" "trafficGetError" = "Error al obtener los tráficos"
"getNewX25519CertError" = "Error al obtener el certificado X25519." "getNewX25519CertError" = "Error al obtener el certificado X25519."
"getNewmldsa65Error" = "Error al obtener el certificado mldsa65." "getNewmldsa65Error" = "Error al obtener el certificado mldsa65."
"getNewVlessEncError" = "Error al obtener el certificado VlessEnc."
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "Pedido" "request" = "Pedido"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "خطا در دریافت ترافیک‌ها" "trafficGetError" = "خطا در دریافت ترافیک‌ها"
"getNewX25519CertError" = "خطا در دریافت گواهی X25519." "getNewX25519CertError" = "خطا در دریافت گواهی X25519."
"getNewmldsa65Error" = "خطا در دریافت گواهی mldsa65." "getNewmldsa65Error" = "خطا در دریافت گواهی mldsa65."
"getNewVlessEncError" = "خطا در دریافت گواهی VlessEnc."
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "درخواست" "request" = "درخواست"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "Gagal mendapatkan data lalu lintas" "trafficGetError" = "Gagal mendapatkan data lalu lintas"
"getNewX25519CertError" = "Terjadi kesalahan saat mendapatkan sertifikat X25519." "getNewX25519CertError" = "Terjadi kesalahan saat mendapatkan sertifikat X25519."
"getNewmldsa65Error" = "Terjadi kesalahan saat mendapatkan sertifikat mldsa65." "getNewmldsa65Error" = "Terjadi kesalahan saat mendapatkan sertifikat mldsa65."
"getNewVlessEncError" = "Terjadi kesalahan saat mendapatkan sertifikat VlessEnc."
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "Permintaan" "request" = "Permintaan"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "トラフィックの取得中にエラーが発生しました" "trafficGetError" = "トラフィックの取得中にエラーが発生しました"
"getNewX25519CertError" = "X25519証明書の取得中にエラーが発生しました。" "getNewX25519CertError" = "X25519証明書の取得中にエラーが発生しました。"
"getNewmldsa65Error" = "mldsa65証明書の取得中にエラーが発生しました。" "getNewmldsa65Error" = "mldsa65証明書の取得中にエラーが発生しました。"
"getNewVlessEncError" = "VlessEnc証明書の取得中にエラーが発生しました。"
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "リクエスト" "request" = "リクエスト"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "Erro ao obter tráfegos" "trafficGetError" = "Erro ao obter tráfegos"
"getNewX25519CertError" = "Erro ao obter o certificado X25519." "getNewX25519CertError" = "Erro ao obter o certificado X25519."
"getNewmldsa65Error" = "Erro ao obter o certificado mldsa65." "getNewmldsa65Error" = "Erro ao obter o certificado mldsa65."
"getNewVlessEncError" = "Erro ao obter o certificado VlessEnc."
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "Requisição" "request" = "Requisição"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "Ошибка получения данных о трафике" "trafficGetError" = "Ошибка получения данных о трафике"
"getNewX25519CertError" = "Ошибка при получении сертификата X25519." "getNewX25519CertError" = "Ошибка при получении сертификата X25519."
"getNewmldsa65Error" = "Ошибка при получении сертификата mldsa65." "getNewmldsa65Error" = "Ошибка при получении сертификата mldsa65."
"getNewVlessEncError" = "Ошибка при получении сертификата VlessEnc."
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "Запрос" "request" = "Запрос"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "Trafik bilgisi alınırken hata oluştu" "trafficGetError" = "Trafik bilgisi alınırken hata oluştu"
"getNewX25519CertError" = "X25519 sertifikası alınırken hata oluştu." "getNewX25519CertError" = "X25519 sertifikası alınırken hata oluştu."
"getNewmldsa65Error" = "mldsa65 sertifikası alınırken hata oluştu." "getNewmldsa65Error" = "mldsa65 sertifikası alınırken hata oluştu."
"getNewVlessEncError" = "VlessEnc sertifikası alınırken hata oluştu."
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "İstek" "request" = "İstek"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "Помилка отримання даних про трафік" "trafficGetError" = "Помилка отримання даних про трафік"
"getNewX25519CertError" = "Помилка при отриманні сертифіката X25519." "getNewX25519CertError" = "Помилка при отриманні сертифіката X25519."
"getNewmldsa65Error" = "Помилка при отриманні сертифіката mldsa65." "getNewmldsa65Error" = "Помилка при отриманні сертифіката mldsa65."
"getNewVlessEncError" = "Помилка при отриманні сертифіката VlessEnc."
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "Запит" "request" = "Запит"

View file

@ -266,7 +266,8 @@
"resetInboundClientTrafficSuccess" = "Đã đặt lại lưu lượng" "resetInboundClientTrafficSuccess" = "Đã đặt lại lưu lượng"
"trafficGetError" = "Lỗi khi lấy thông tin lưu lượng" "trafficGetError" = "Lỗi khi lấy thông tin lưu lượng"
"getNewX25519CertError" = "Lỗi khi lấy chứng chỉ X25519." "getNewX25519CertError" = "Lỗi khi lấy chứng chỉ X25519."
"getNewmldsa65Error" = "Lỗi khi lấy chúng tôi mldsa65." "getNewmldsa65Error" = "Lỗi khi lấy chứng chỉ mldsa65."
"getNewVlessEncError" = "Lỗi khi lấy chứng chỉ VlessEnc."
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "Lời yêu cầu" "request" = "Lời yêu cầu"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "获取流量数据时出错" "trafficGetError" = "获取流量数据时出错"
"getNewX25519CertError" = "获取X25519证书时出错。" "getNewX25519CertError" = "获取X25519证书时出错。"
"getNewmldsa65Error" = "获取mldsa65证书时出错。" "getNewmldsa65Error" = "获取mldsa65证书时出错。"
"getNewVlessEncError" = "获取VlessEnc证书时出错。"
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "请求" "request" = "请求"

View file

@ -267,6 +267,7 @@
"trafficGetError" = "取得流量資料時發生錯誤" "trafficGetError" = "取得流量資料時發生錯誤"
"getNewX25519CertError" = "取得X25519憑證時發生錯誤。" "getNewX25519CertError" = "取得X25519憑證時發生錯誤。"
"getNewmldsa65Error" = "取得mldsa65憑證時發生錯誤。" "getNewmldsa65Error" = "取得mldsa65憑證時發生錯誤。"
"getNewVlessEncError" = "取得VlessEnc憑證時發生錯誤。"
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"request" = "請求" "request" = "請求"