fix(warp): harden API client and frontend, bump to v0a4005

Backend:
- check HTTP status on every Cloudflare API call so error bodies don't
  get parsed as success
- replace unchecked type assertions with comma-ok form (no more panics
  when Cloudflare returns an error response)
- return real errors when license/id/token fields are missing instead
  of swallowing the failure
- guard SetWarpLicense against an empty errors array
- 15s timeout on the shared http.Client
- build all request bodies and persisted state with json.Marshal
- bump API path to v0a4005 and CF-Client-Version to a-6.30-3596 to
  match the current Cloudflare WARP client

Frontend (warp_modal.html):
- remove stray </a-form-item> closing tag
- declare config/peer with const and null-check before dereferencing
- guard addOutbound/resetOutbound against missing warpOutbound
- rename getResolved -> getReserved (the array it builds is "reserved")

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
MHSanaei
2026-05-08 09:29:42 +02:00
parent f2bc4938b7
commit d8198f543b
2 changed files with 143 additions and 105 deletions
+23 -21
View File
@@ -88,7 +88,6 @@
<a-button @click="addOutbound" :loading="warpModal.confirmLoading"
type="primary">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
</template>
</a-form-item>
</a-form>
</template>
</template>
@@ -131,26 +130,27 @@
},
methods: {
collectConfig() {
config = warpModal.warpConfig.config;
peer = config.peers[0];
if (config) {
warpModal.warpOutbound = Outbound.fromJson({
tag: 'warp',
protocol: Protocols.Wireguard,
settings: {
mtu: 1420,
secretKey: warpModal.warpData.private_key,
address: this.getAddresses(config.interface.addresses),
reserved: this.getResolved(config.client_id),
domainStrategy: 'ForceIP',
peers: [{
publicKey: peer.public_key,
endpoint: peer.endpoint.host,
}],
noKernelTun: false,
}
});
const config = warpModal.warpConfig && warpModal.warpConfig.config;
if (!config || !config.peers || !config.peers.length) {
return;
}
const peer = config.peers[0];
warpModal.warpOutbound = Outbound.fromJson({
tag: 'warp',
protocol: Protocols.Wireguard,
settings: {
mtu: 1420,
secretKey: warpModal.warpData.private_key,
address: this.getAddresses(config.interface.addresses),
reserved: this.getReserved(config.client_id),
domainStrategy: 'ForceIP',
peers: [{
publicKey: peer.public_key,
endpoint: peer.endpoint.host,
}],
noKernelTun: false,
}
});
},
getAddresses(addrs) {
let addresses = [];
@@ -158,7 +158,7 @@
if (addrs.v6) addresses.push(addrs.v6 + "/128");
return addresses;
},
getResolved(client_id) {
getReserved(client_id) {
let reserved = [];
let decoded = atob(client_id);
let hexString = '';
@@ -218,11 +218,13 @@
}
},
addOutbound() {
if (!warpModal.warpOutbound) return;
app.templateSettings.outbounds.push(warpModal.warpOutbound.toJson());
app.outboundSettings = JSON.stringify(app.templateSettings.outbounds);
warpModal.close();
},
resetOutbound() {
if (!warpModal.warpOutbound) return;
app.templateSettings.outbounds[this.warpOutboundIndex] = warpModal.warpOutbound.toJson();
app.outboundSettings = JSON.stringify(app.templateSettings.outbounds);
warpModal.close();