Update 1140
This commit is contained in:
317
readme.md
317
readme.md
@@ -212,6 +212,19 @@ DtUuid.get();
|
||||
DtUuid.set(value);
|
||||
```
|
||||
|
||||
### `CakeApp.errors`
|
||||
|
||||
```js
|
||||
CakeApp.errors.getLast(); // retorna string JSON com o último erro de conexão
|
||||
```
|
||||
|
||||
Aliases equivalentes:
|
||||
|
||||
```js
|
||||
DtGetLastConnectionError.execute();
|
||||
DtGetConnectionError.execute();
|
||||
```
|
||||
|
||||
### `CakeApp.system`
|
||||
|
||||
```js
|
||||
@@ -271,7 +284,9 @@ function cleanBridgeValue(value) {
|
||||
| `DtExecuteVpnStart.execute()` | sem argumentos | void | Inicia/dispara o comando nativo da VPN. |
|
||||
| `DtExecuteVpnStop.execute()` | sem argumentos | void | Para a VPN. |
|
||||
| `DtGetNetworkDownloadBytes.execute()` | sem argumentos | string numérica | Retorna bytes baixados atuais da rede/app para verificação de tráfego. |
|
||||
| `DtGetLogs.execute()` | sem argumentos | string JSON | Retorna logs recentes de status/banner como array de objetos com timestamp. |
|
||||
| `DtGetLogs.execute()` | sem argumentos | string JSON | Retorna logs recentes de status/banner/proxy como array de objetos com timestamp. |
|
||||
| `DtGetLastConnectionError.execute()` | sem argumentos | string JSON | Retorna o último erro classificado de conexão, autenticação ou proxy. Retorna `{}` se não houver erro. |
|
||||
| `DtGetConnectionError.execute()` | sem argumentos | string JSON | Alias de compatibilidade de `DtGetLastConnectionError.execute()`. |
|
||||
| `DtShowLoggerDialog.execute()` | sem argumentos | void | Abre o diálogo nativo de logs. |
|
||||
|
||||
Possíveis estados de `DtGetVpnState` / `DtVpnStateListener`:
|
||||
@@ -286,6 +301,75 @@ Possíveis estados de `DtGetVpnState` / `DtVpnStateListener`:
|
||||
| `NO_NETWORK` | Aguardando rede. |
|
||||
| `AUTH_FAILED` | Falha de autenticação. |
|
||||
|
||||
#### 5.3.1 Erros de conexão/autenticação/proxy
|
||||
|
||||
O patch expõe um bridge específico para o tema entender por que a conexão falhou, sem precisar depender apenas de texto solto no botão ou no status.
|
||||
|
||||
```js
|
||||
function getLastConnectionError() {
|
||||
try {
|
||||
return JSON.parse(DtGetLastConnectionError.execute() || '{}');
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Formato retornado:
|
||||
|
||||
```json
|
||||
{
|
||||
"state": "AUTH_FAILED",
|
||||
"code": "LOGIN_INVALID",
|
||||
"message": "Authentication failed",
|
||||
"time": 1777290000000
|
||||
}
|
||||
```
|
||||
|
||||
Campos:
|
||||
|
||||
| Campo | Tipo | Significado |
|
||||
|---|---|---|
|
||||
| `state` | string | Estado nativo/mapeado no momento do erro. |
|
||||
| `code` | string | Código normalizado para o tema tratar com UI própria. |
|
||||
| `message` | string | Mensagem original limpa vinda do status/log/banner/proxy. |
|
||||
| `time` | number | Timestamp em milissegundos. |
|
||||
|
||||
Códigos conhecidos nesta versão:
|
||||
|
||||
| Código | Quando aparece | Uso recomendado no tema |
|
||||
|---|---|---|
|
||||
| `LOGIN_EXPIRED` | Mensagens contendo acesso expirado/vencido. | Mostrar aviso de renovação. |
|
||||
| `LOGIN_INVALID` | Falha de usuário/senha, HTTP 401 ou texto de login inválido. | Mostrar usuário/senha inválidos. |
|
||||
| `LOGIN_LIMIT` | Mensagens de limite/conexões excedidas. | Mostrar limite de conexões atingido. |
|
||||
| `PROXY_FORBIDDEN` | HTTP 403 ou `Forbidden`. | Mostrar proxy/bughost bloqueado. |
|
||||
| `PROXY_BAD_REQUEST` | HTTP 400 ou `Bad Request`. | Mostrar payload/proxy inválido. |
|
||||
| `PROXY_RATE_LIMITED` | HTTP 429 ou `Too Many Requests`. | Mostrar muitas tentativas/limite temporário. |
|
||||
| `PROXY_SERVER_ERROR` | HTTP 500/502, `Bad Gateway` ou erro interno. | Mostrar falha no proxy/servidor remoto. |
|
||||
| `AUTH_FAILED` | Falha de autenticação sem classificação mais específica. | Mostrar falha genérica de autenticação. |
|
||||
|
||||
Exemplo de uso direto:
|
||||
|
||||
```js
|
||||
function renderLastError() {
|
||||
const error = getLastConnectionError();
|
||||
if (!error.code) return;
|
||||
|
||||
const messages = {
|
||||
LOGIN_EXPIRED: 'Seu login expirou. Renove seu acesso.',
|
||||
LOGIN_INVALID: 'Usuário ou senha inválidos.',
|
||||
LOGIN_LIMIT: 'Limite de conexões atingido.',
|
||||
PROXY_FORBIDDEN: 'Proxy/bughost bloqueou a conexão.',
|
||||
PROXY_BAD_REQUEST: 'Payload ou proxy retornou Bad Request.',
|
||||
PROXY_RATE_LIMITED: 'Muitas tentativas. Tente novamente mais tarde.',
|
||||
PROXY_SERVER_ERROR: 'Proxy/servidor remoto retornou erro.',
|
||||
AUTH_FAILED: 'Falha na autenticação.'
|
||||
};
|
||||
|
||||
showError(messages[error.code] || error.message || 'Falha na conexão.');
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 APIs de consulta de usuário/conta
|
||||
|
||||
| API | Assinatura | Retorno | Finalidade |
|
||||
@@ -356,6 +440,27 @@ A porta padrão de proxy usada pelo tema existente é `6821`, mas o bridge em si
|
||||
const proxyAddress = `${DtGetLocalIP.execute()}:6821`;
|
||||
```
|
||||
|
||||
Nesta versão do patch, `DtStartHotSpotService.execute()` não inicia mais o socket diretamente pelo `ProxyServer`. Ele dispara o `ProxyService` com `ACTION_START`, para que o Android mostre uma notificação foreground persistente do proxy, por exemplo:
|
||||
|
||||
```txt
|
||||
Proxy ONLINE - 192.168.x.x:6821
|
||||
```
|
||||
|
||||
Ao chamar `DtStopHotSpotService.execute()`, o app envia `ACTION_STOP` para o mesmo serviço e remove a notificação.
|
||||
|
||||
Em Android 13+ o app precisa da permissão `POST_NOTIFICATIONS`. O `OnlineConfigWebActivity` tenta pedir essa permissão ao abrir e também antes de iniciar o proxy. Se o usuário negar, o proxy não deve ser considerado iniciado pelo tema. Sempre confirme o status depois do comando:
|
||||
|
||||
```js
|
||||
async function startLocalProxyAndRefresh() {
|
||||
DtStartHotSpotService.execute();
|
||||
|
||||
setTimeout(() => {
|
||||
const status = DtGetStatusHotSpotService.execute();
|
||||
renderProxyStatus(status);
|
||||
}, 500);
|
||||
}
|
||||
```
|
||||
|
||||
### 5.7 APIs de config visual/app
|
||||
|
||||
| API | Assinatura | Retorno | Finalidade |
|
||||
@@ -454,6 +559,50 @@ window.dtCheckUserModelListener = function(modelJson) {
|
||||
};
|
||||
```
|
||||
|
||||
### `window.dtLogsUpdatedListener = function(logsJson) {}`
|
||||
|
||||
Chamado quando o app adiciona um log visível para o tema. Também existe o alias com inicial maiúscula `window.DtLogsUpdatedListener`.
|
||||
|
||||
```js
|
||||
window.dtLogsUpdatedListener = function(logsJson) {
|
||||
let rows = [];
|
||||
try { rows = JSON.parse(logsJson || '[]'); } catch (e) {}
|
||||
|
||||
const text = rows.map(row => {
|
||||
const time = Object.keys(row)[0] || '';
|
||||
return `${time} ${row[time] || ''}`;
|
||||
}).join('\n');
|
||||
|
||||
renderLogs(text);
|
||||
};
|
||||
```
|
||||
|
||||
### `window.dtConnectionErrorListener = function(error) {}`
|
||||
|
||||
Chamado quando o app classifica um erro de conexão/autenticação/proxy. Também existem estes aliases:
|
||||
|
||||
```js
|
||||
window.DtConnectionErrorListener = function(error) {};
|
||||
window.dtAuthErrorListener = function(error) {};
|
||||
window.DtAuthErrorListener = function(error) {};
|
||||
```
|
||||
|
||||
O argumento já chega como objeto JavaScript, não como string JSON.
|
||||
|
||||
```js
|
||||
window.dtConnectionErrorListener = function(error) {
|
||||
if (!error || !error.code) return;
|
||||
|
||||
if (error.code === 'LOGIN_EXPIRED') {
|
||||
showError('Seu login expirou. Renove seu acesso.');
|
||||
} else if (error.code === 'PROXY_FORBIDDEN') {
|
||||
showError('Proxy/bughost bloqueou a conexão.');
|
||||
} else {
|
||||
showError(error.message || 'Falha na conexão.');
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. JSON de config retornado para o HTML
|
||||
@@ -568,7 +717,7 @@ Ele varre todos os elementos `input`, `textarea` e `select`, e classifica eles p
|
||||
|
||||
Ele detecta:
|
||||
|
||||
- Campos de UUID quando os metadados contêm `v2ray`, `uuid` ou `xray`.
|
||||
- Campos de UUID quando os metadados contêm `v2ray`, `uuid`, `xray`, `vmess` ou `vless`.
|
||||
- Campos de senha quando os metadados contêm `password`, `senha` ou `pass`.
|
||||
- Campos de usuário quando os metadados contêm `username`, `usuario`, `login` ou tokens parecidos com usuário.
|
||||
|
||||
@@ -595,31 +744,21 @@ HTML recomendado:
|
||||
</div>
|
||||
```
|
||||
|
||||
### Limitação importante desta versão
|
||||
### Detecção V2Ray/Xray/VMess/VLess nesta versão
|
||||
|
||||
Nesta versão do `VOIDPRO.zip`, a função injetada de visibilidade considera V2Ray/Xray somente quando `mode` começa com `v2ray` ou `xray`.
|
||||
No patch atual, a função injetada de visibilidade já considera `v2ray`, `xray`, `vmess` e `vless` no `mode` e também nos metadados do input.
|
||||
|
||||
Isto funciona:
|
||||
Estes formatos são detectados como perfis baseados em UUID:
|
||||
|
||||
```json
|
||||
{ "mode": "V2RAY" }
|
||||
```
|
||||
|
||||
Isto funciona:
|
||||
|
||||
```json
|
||||
{ "mode": "XRAY" }
|
||||
```
|
||||
|
||||
Estes podem não ser detectados pela função injetada, a não ser que o tema tenha sua própria lógica de visibilidade ou você aplique patch no Java:
|
||||
|
||||
```json
|
||||
{ "mode": "VMESS" }
|
||||
{ "mode": "VLESS" }
|
||||
{ "mode": "V2RAY - VMESS" }
|
||||
```
|
||||
|
||||
Para builds atuais, prefira este formato de perfil no catálogo para configs baseadas em UUID:
|
||||
Mesmo assim, o formato mais limpo para configs baseadas em UUID continua sendo:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -719,10 +858,23 @@ Exemplo:
|
||||
[
|
||||
{ "14:03:55": "Connecting" },
|
||||
{ "14:03:56": "Authenticating" },
|
||||
{ "14:03:57": "Server Message: welcome" }
|
||||
{ "14:03:57": "Server Message: welcome" },
|
||||
{ "14:03:58": "Proxy Status [HTTP_PROXY]: HTTP/1.1 101 Switching Protocols" },
|
||||
{ "14:04:01": "Proxy Status [SSH_DIRECT]: HTTP/1.1 302 Found" }
|
||||
]
|
||||
```
|
||||
|
||||
O patch faz o bridge mostrar também respostas HTTP/proxy relevantes para o tema, incluindo:
|
||||
|
||||
- `Proxy Status [HTTP_PROXY]: HTTP/1.1 101 ...`
|
||||
- `Proxy Status [HTTP_PROXY]: HTTP/1.1 302 ...`
|
||||
- `Proxy Status [SSH_DIRECT]: HTTP/1.1 101 ...`
|
||||
- `Proxy Status [SSH_DIRECT]: HTTP/1.1 302 ...`
|
||||
- `HTTP/1.1 400`, `401`, `403`, `404`, `429`, `500`, `502`
|
||||
- mensagens como `Unauthorized`, `Forbidden`, `Bad Request`, `Too Many Requests` e `Bad Gateway`
|
||||
|
||||
A diferença importante é o `SSH_DIRECT`: quando o campo de servidor SSH é usado como proxy/bughost e o servidor real está dentro do payload, o app agora faz uma leitura curta e segura da primeira resposta. Se vier HTTP, ele mostra o status para o HTML. Se vier banner SSH, ele preserva os bytes e não quebra o handshake.
|
||||
|
||||
Helper de renderização:
|
||||
|
||||
```js
|
||||
@@ -737,7 +889,23 @@ function readLogs() {
|
||||
}
|
||||
```
|
||||
|
||||
O buffer de logs nativo exposto ao HTML é limitado a entradas recentes de status e mensagens de banner do servidor. Ele não é o logcat/debug completo.
|
||||
Listener ao vivo:
|
||||
|
||||
```js
|
||||
window.dtLogsUpdatedListener = function(logsJson) {
|
||||
let rows = [];
|
||||
try { rows = JSON.parse(logsJson || '[]'); } catch (e) {}
|
||||
|
||||
const latest = rows.length ? Object.values(rows[rows.length - 1])[0] : '';
|
||||
if (latest.includes('Proxy Status [SSH_DIRECT]')) {
|
||||
showProxyStatus(latest);
|
||||
}
|
||||
|
||||
renderLogs(readLogs());
|
||||
};
|
||||
```
|
||||
|
||||
O buffer de logs nativo exposto ao HTML é limitado a entradas recentes de status, mensagens de banner do servidor e mensagens úteis de proxy. Ele não é o logcat/debug completo.
|
||||
|
||||
---
|
||||
|
||||
@@ -963,6 +1131,12 @@ if (!window.DtGetVpnState) {
|
||||
window.DtUuid = { get: () => '', set: (v) => console.log('uuid', v) };
|
||||
window.DtExecuteVpnStart = { execute: () => console.log('start') };
|
||||
window.DtExecuteVpnStop = { execute: () => console.log('stop') };
|
||||
window.DtGetLogs = { execute: () => JSON.stringify([]) };
|
||||
window.DtGetLastConnectionError = { execute: () => '{}' };
|
||||
window.DtGetConnectionError = window.DtGetLastConnectionError;
|
||||
window.DtGetStatusHotSpotService = { execute: () => 'STOPPED' };
|
||||
window.DtStartHotSpotService = { execute: () => console.log('proxy start') };
|
||||
window.DtStopHotSpotService = { execute: () => console.log('proxy stop') };
|
||||
}
|
||||
```
|
||||
|
||||
@@ -999,9 +1173,26 @@ Bom:
|
||||
usernameInput.value = cleanBridgeValue(DtUsername.get());
|
||||
```
|
||||
|
||||
### Erro: assumir que todos os modos V2Ray são detectados automaticamente pelo código de visibilidade injetado
|
||||
### Erro: não tratar erros classificados do bridge
|
||||
|
||||
Use `mode: "V2RAY"` no catálogo/settings para este build, ou adicione um helper de visibilidade no tema que também verifique `vmess` e `vless`.
|
||||
Ruim:
|
||||
|
||||
```js
|
||||
window.DtVpnStateListener = function(state) {
|
||||
if (state === 'AUTH_FAILED') alert('Falha');
|
||||
};
|
||||
```
|
||||
|
||||
Bom:
|
||||
|
||||
```js
|
||||
window.dtConnectionErrorListener = function(error) {
|
||||
if (!error || !error.code) return;
|
||||
showError(error.message || error.code);
|
||||
};
|
||||
```
|
||||
|
||||
Use `DtGetLastConnectionError.execute()` para recuperar o último erro quando a tela for recriada ou quando o tema carregar depois de uma falha.
|
||||
|
||||
### Erro: salvar autenticação somente no conectar
|
||||
|
||||
@@ -1117,6 +1308,26 @@ const OnlineBridge = {
|
||||
this.set('DtUsername', username || '');
|
||||
this.set('DtPassword', password || '');
|
||||
this.set('DtUuid', uuid || '');
|
||||
},
|
||||
|
||||
readLogs() {
|
||||
return this.jsonFromExec('DtGetLogs', []);
|
||||
},
|
||||
|
||||
getLastError() {
|
||||
return this.jsonFromExec('DtGetLastConnectionError', {});
|
||||
},
|
||||
|
||||
getProxyStatus() {
|
||||
return this.exec('DtGetStatusHotSpotService', 'STOPPED');
|
||||
},
|
||||
|
||||
startProxy() {
|
||||
this.command('DtStartHotSpotService');
|
||||
},
|
||||
|
||||
stopProxy() {
|
||||
this.command('DtStopHotSpotService');
|
||||
}
|
||||
};
|
||||
```
|
||||
@@ -1131,10 +1342,74 @@ Antes de publicar um tema, verifique:
|
||||
- Não mostra `Locked` para o usuário.
|
||||
- Consegue fazer parse seguro de JSON vazio ou inválido.
|
||||
- Escuta `DtVpnStateListener`.
|
||||
- Escuta `dtLogsUpdatedListener` se o tema mostra logs/proxy-status em tempo real.
|
||||
- Escuta `dtConnectionErrorListener` ou lê `DtGetLastConnectionError.execute()` para mostrar erro correto.
|
||||
- Chama `DtSetConfig.execute(id)` antes de iniciar um perfil selecionado.
|
||||
- Salva usuário/senha/UUID antes de conectar.
|
||||
- Trata `auth.username`, `auth.password` e `auth.v2ray_uuid`.
|
||||
- O campo UUID aparece para configs `mode: "V2RAY"` / `mode: "XRAY"`.
|
||||
- O campo UUID aparece para configs `mode: "V2RAY"`, `"XRAY"`, `"VMESS"` e `"VLESS"`.
|
||||
- Se usar proxy local, confirma `DtGetStatusHotSpotService.execute()` depois de chamar start/stop.
|
||||
- Se usar proxy local em Android 13+, considera que a notificação pode depender da permissão `POST_NOTIFICATIONS`.
|
||||
- Não depende de `DtGetPingResult` retornar ping real.
|
||||
- Não coloca código de produção abaixo do marcador de mock.
|
||||
- Usa APIs nativas de altura das barras ou CSS safe areas para a navegação inferior não ficar cortada.
|
||||
|
||||
---
|
||||
|
||||
## 21. Resumo dos bridges novos do patch V2/V3/V4
|
||||
|
||||
Esta versão do patch adiciona/atualiza estes pontos para temas HTML OnlineConfig:
|
||||
|
||||
| Item | Bridge/callback | O que muda para o tema |
|
||||
|---|---|---|
|
||||
| Último erro de conexão | `DtGetLastConnectionError.execute()` | Tema consegue saber se foi login expirado, login inválido, limite, proxy bloqueado, erro 400/403/429/500 etc. |
|
||||
| Alias de erro | `DtGetConnectionError.execute()` | Mesmo retorno de `DtGetLastConnectionError.execute()`. |
|
||||
| Helper limpo | `CakeApp.errors.getLast()` | Wrapper `CakeApp` para buscar o último erro. |
|
||||
| Callback de erro | `dtConnectionErrorListener(error)` | Tema recebe o erro ao vivo como objeto JS. |
|
||||
| Callback de auth/compatibilidade | `dtAuthErrorListener(error)` | Alias compatível para temas que tratam erro de autenticação separado. |
|
||||
| Callback de logs | `dtLogsUpdatedListener(logsJson)` | Tema recebe logs recentes sempre que uma mensagem visível é adicionada. |
|
||||
| Status de proxy HTTP | `DtGetLogs.execute()` | Logs agora incluem `Proxy Status [HTTP_PROXY]` e `Proxy Status [SSH_DIRECT]`. |
|
||||
| SSH_DIRECT com payload/proxy | logs + erro classificado | Mesmo em SSH direto, o app tenta detectar resposta HTTP inicial do proxy sem quebrar banner SSH. |
|
||||
| Proxy local foreground | `DtStartHotSpotService.execute()` | Inicia `ProxyService` com notificação foreground em vez de ligar apenas o socket interno. |
|
||||
| Permissão de notificação | abertura do `OnlineConfigWebActivity` e start do proxy | Android 13+ pede `POST_NOTIFICATIONS`; se negar, o tema deve confirmar o status do proxy. |
|
||||
| Detecção UUID | `CakeApp.applyAuthVisibility()` | Agora considera `v2ray`, `xray`, `vmess` e `vless`. |
|
||||
|
||||
Exemplo completo para tema tratar logs e erros:
|
||||
|
||||
```js
|
||||
function parseBridgeJson(raw, fallback) {
|
||||
try { return JSON.parse(raw || ''); } catch (e) { return fallback; }
|
||||
}
|
||||
|
||||
window.dtLogsUpdatedListener = function(logsJson) {
|
||||
const logs = parseBridgeJson(logsJson, []);
|
||||
const text = logs.map(row => {
|
||||
const time = Object.keys(row)[0] || '';
|
||||
return `${time} ${row[time] || ''}`;
|
||||
}).join('\n');
|
||||
|
||||
renderLogs(text);
|
||||
};
|
||||
|
||||
window.dtConnectionErrorListener = function(error) {
|
||||
if (!error || !error.code) return;
|
||||
|
||||
const messageByCode = {
|
||||
LOGIN_EXPIRED: 'Seu login expirou. Renove seu acesso.',
|
||||
LOGIN_INVALID: 'Usuário ou senha inválidos.',
|
||||
LOGIN_LIMIT: 'Limite de conexões atingido.',
|
||||
PROXY_FORBIDDEN: 'Proxy/bughost bloqueou a conexão.',
|
||||
PROXY_BAD_REQUEST: 'Payload ou proxy inválido.',
|
||||
PROXY_RATE_LIMITED: 'Muitas tentativas no proxy.',
|
||||
PROXY_SERVER_ERROR: 'Erro no proxy/servidor remoto.',
|
||||
AUTH_FAILED: 'Falha de autenticação.'
|
||||
};
|
||||
|
||||
renderError(messageByCode[error.code] || error.message || 'Falha na conexão.');
|
||||
};
|
||||
|
||||
function restoreLastErrorOnLoad() {
|
||||
const error = parseBridgeJson(DtGetLastConnectionError.execute(), {});
|
||||
if (error.code) window.dtConnectionErrorListener(error);
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user