mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-19 23:35:48 +00:00
[outbound] add json mode and link convertor
This commit is contained in:
@@ -470,6 +470,61 @@ class Outbound extends CommonClass {
|
||||
streamSettings: this.canEnableStream() ? this.stream.toJson() : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
static fromLink(link) {
|
||||
data = link.split('://');
|
||||
if(data.length !=2) return null;
|
||||
switch(data[0].toLowerCase()){
|
||||
case Protocols.VMess:
|
||||
return this.fromVmessLink(JSON.parse(atob(data[1])));
|
||||
case Protocols.VLESS:
|
||||
case Protocols.Trojan:
|
||||
case 'ss':
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static fromVmessLink(json={}){
|
||||
let stream = new StreamSettings(json.net, json.tls);
|
||||
|
||||
let network = json.net;
|
||||
if (network === 'tcp') {
|
||||
stream.tcp = new TcpStreamSettings(
|
||||
json.type,
|
||||
json.host ? json.host.split(','): [],
|
||||
json.path ? json.path.split(','): []);
|
||||
} else if (network === 'kcp') {
|
||||
stream.kcp = new KcpStreamSettings();
|
||||
stream.type = json.type;
|
||||
stream.seed = json.path;
|
||||
} else if (network === 'ws') {
|
||||
stream.ws = new WsStreamSettings(json.path,json.host);
|
||||
} else if (network === 'http' || network == 'h2') {
|
||||
stream.network = 'http'
|
||||
stream.http = new HttpStreamSettings(
|
||||
json.path,
|
||||
json.host ? json.host.split(',') : []);
|
||||
} else if (network === 'quic') {
|
||||
strem.quic = new QuicStreamSettings(
|
||||
json.host ? json.host : 'none',
|
||||
json.path,
|
||||
json.type ? json.type : 'none');
|
||||
} else if (network === 'grpc') {
|
||||
stream.grpc = new GrpcStreamSettings(json.path, json.type == 'multi');
|
||||
}
|
||||
|
||||
if(json.tls && json.tls == 'tls'){
|
||||
stream.tls = new TlsStreamSettings(
|
||||
json.sni,
|
||||
json.alpn ? json.alpn.split(',') : [],
|
||||
json.fp,
|
||||
json.allowInsecure);
|
||||
}
|
||||
|
||||
|
||||
return new Outbound(json.ps, Protocols.VMess, new Outbound.VmessSettings(json.add, json.port, json.id), stream);
|
||||
}
|
||||
}
|
||||
|
||||
Outbound.Settings = class extends CommonClass {
|
||||
@@ -512,7 +567,6 @@ Outbound.Settings = class extends CommonClass {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
Outbound.FreedomSettings = class extends CommonClass {
|
||||
constructor(domainStrategy='', fragment={}) {
|
||||
super();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{{define "form/outbound"}}
|
||||
<!-- base -->
|
||||
<a-tabs :active-key="outModal.activeKey" style="padding: 0; background-color: transparent;" @change="(activeKey) => {outModal.toggleJson(activeKey == '2'); }">
|
||||
<a-tab-pane key="1" tab="Form">
|
||||
<a-form layout="inline">
|
||||
<table width="100%" class="ant-table-tbody">
|
||||
<tr>
|
||||
@@ -16,7 +18,7 @@
|
||||
<td>{{ i18n "pages.xray.outbound.tag" }}</td>
|
||||
<td>
|
||||
<a-form-item>
|
||||
<a-input v-model.trim="outbound.tag" style="width: 250px" @change="check" :style="duplicateTag? 'border-color: red;' : ''"></a-input>
|
||||
<a-input v-model.trim="outbound.tag" style="width: 250px" @change="outModal.check()" :style="outModal.duplicateTag? 'border-color: red;' : ''"></a-input>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -527,7 +529,17 @@
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</table>
|
||||
</a-form>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="2" tab="JSON" force-render="true">
|
||||
<a-form-item style="margin: 10px 0">
|
||||
Link: <a-input v-model.trim="outModal.link" style="width: 300px; margin-right: 5px;" placeholder="vmess:// vless:// trojan:// ss://"></a-input>
|
||||
<a-button @click="convertLink" type="primary"><a-icon type="form"></a-icon></a-button>
|
||||
</a-form-item>
|
||||
<textarea style="position:absolute; left: -800px;" id="outboundJson"></textarea>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
{{end}}
|
||||
@@ -1,9 +1,8 @@
|
||||
{{define "outModal"}}
|
||||
<a-modal id="out-modal" v-model="outModal.visible" :title="outModal.title" @ok="outModal.ok"
|
||||
:confirm-loading="outModal.confirmLoading" :closable="true" :mask-closable="false"
|
||||
:ok-button-props="{ props: { disabled: !isValid } }"
|
||||
:ok-button-props="{ props: { disabled: !outModal.isValid } }" style="overflow: hidden;"
|
||||
:ok-text="outModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme">
|
||||
<pre>[[ outModal.outbound ]]</pre>
|
||||
{{template "form/outbound"}}
|
||||
</a-modal>
|
||||
<script>
|
||||
@@ -16,7 +15,12 @@
|
||||
isEdit: false,
|
||||
confirm: null,
|
||||
outbound: new Outbound(),
|
||||
outboundTags: [],
|
||||
jsonMode: false,
|
||||
link: '',
|
||||
cm: null,
|
||||
duplicateTag: false,
|
||||
isValid: true,
|
||||
activeKey: '1',
|
||||
ok() {
|
||||
ObjectUtil.execute(outModal.confirm, outModal.outbound.toJson());
|
||||
},
|
||||
@@ -24,11 +28,13 @@
|
||||
this.title = title;
|
||||
this.okText = okText;
|
||||
this.confirm = confirm;
|
||||
this.jsonMode = false;
|
||||
this.link = '';
|
||||
this.activeKey = '1';
|
||||
this.visible = true;
|
||||
this.outbound = isEdit ? Outbound.fromJson(outbound) : new Outbound();
|
||||
|
||||
this.isEdit = isEdit;
|
||||
this.outboundTags = app.templateSettings.outbounds.map(obj => obj.tag);
|
||||
this.check()
|
||||
},
|
||||
close() {
|
||||
outModal.visible = false;
|
||||
@@ -36,7 +42,49 @@
|
||||
},
|
||||
loading(loading) {
|
||||
outModal.confirmLoading = loading;
|
||||
}
|
||||
},
|
||||
check(){
|
||||
if(outModal.outbound.tag == ''){
|
||||
this.duplicateTag = true;
|
||||
this.isValid = false;
|
||||
} else {
|
||||
this.duplicateTag = false;
|
||||
this.isValid = true;
|
||||
}
|
||||
},
|
||||
toggleJson(jsonTab) {
|
||||
textAreaObj = document.getElementById('outboundJson');
|
||||
if(jsonTab){
|
||||
if(this.cm != null) {
|
||||
this.cm.toTextArea();
|
||||
this.cm=null;
|
||||
}
|
||||
textAreaObj.value = JSON.stringify(this.outbound.toJson(), null, 2);
|
||||
this.cm = CodeMirror.fromTextArea(textAreaObj, app.cmOptions);
|
||||
this.cm.on('change',editor => {
|
||||
value = editor.getValue();
|
||||
if(this.isJsonString(value)){
|
||||
this.outbound = Outbound.fromJson(JSON.parse(value));
|
||||
this.check();
|
||||
}
|
||||
});
|
||||
this.activeKey = '2';
|
||||
} else {
|
||||
if(this.cm != null) {
|
||||
this.cm.toTextArea();
|
||||
this.cm=null;
|
||||
}
|
||||
this.activeKey = '1';
|
||||
}
|
||||
},
|
||||
isJsonString(str) {
|
||||
try {
|
||||
JSON.parse(str);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
new Vue({
|
||||
@@ -44,8 +92,6 @@
|
||||
el: '#out-modal',
|
||||
data: {
|
||||
outModal: outModal,
|
||||
duplicateTag: false,
|
||||
isValid: false,
|
||||
get outbound() {
|
||||
return outModal.outbound;
|
||||
},
|
||||
@@ -59,14 +105,10 @@
|
||||
canEnableTls() {
|
||||
return this.outModal.outbound.canEnableTls();
|
||||
},
|
||||
check(){
|
||||
if(outModal.outbound.tag == '' || this.outModal.outboundTags.includes(outModal.outbound.tag)){
|
||||
this.duplicateTag = true;
|
||||
this.isValid = false;
|
||||
} else {
|
||||
this.duplicateTag = false;
|
||||
this.isValid = true;
|
||||
}
|
||||
convertLink(){
|
||||
this.outModal.outbound = Outbound.fromLink(outModal.link);
|
||||
this.outModal.toggleJson(true);
|
||||
this.outModal.check();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user