Skip to content

使用其他语言实现密钥刷新服务

CubeWhy edited this page Oct 20, 2024 · 10 revisions

注意事项

  1. WebSocket 服务务必不要使用 🇨🇳中国(不包括🇭🇰港🇲🇴澳🇹🇼台) IP进行连接, 否则您的共享账户可能会面临封锁
  2. 务必使用自由的Online实现, 否则您的共享账户可能会面临封锁
  3. 如果你要在本地搭建服务端, 建议您在您的应用程序内实现Dns解析器
  4. 不要泄露密钥
  5. 操作不当导致的封禁后果自负

步骤

VapeGateway实现起来很简单, 几乎是人人都可以实现. 它分为以下几个部分

  • 刷新账户
  • 加密
  • 响应密钥刷新请求
  • 响应心跳包

刷新共享账户

Example: VapeAccountServiceImpl.java#L157

注意: Body不是Json

你需要向 http://www.vape.gg/auth.php 发送一个POST请求,并携带如下Header (hwid替换成真实的HWID)

User-Agent: Agent_<hwid>
Content-Type: application/x-www-form-urlencoded

Body: email=manthe@example.com&password=fuckyoumanthe&hwid=<manthe's hwid>&v=v3&t=true

Param Description Example Value
email 邮箱或者是用户名 manthe@example.com
password 密码 password
hwid 设备码,请求时和官网配置的一致即可 FUMANTHE
v Vape类型,v3是伪装成v4, 通常情况不需要修改 v3
t 不清楚 true

如果凭证正确, 会返回一个33位的Token, 否则是错误码

错误码

您需要在服务端中进行判断并返回给母服务端,对应的字符串见 状态码

Code Description
1 凭证错误
102 账户被封禁
1006 IP被封禁 (Cloudflare)
一段HTML代码 Cloudflare 验证码,可能是没配置User-Agent导致的

HttpClient

POST http://www.vape.gg/auth.php
User-Agent: Agent_HWID
Content-Type: application/x-www-form-urlencoded

email=example@example.com&password=example&hwid=HWID&v=v3&t=true

实现加密算法

警告: 可能会修改的内容

Example: CryptoUtil.java

丁真服务端使用AES/CBC/PKCS5Padding来进行加密

生成密钥

密钥是一个32位的byteArray, 建议使用base64存储

可以使用如下OpenSSL指令快速生成密钥

# encode with Base64
openssl rand -base64 32
# decoded
openssl rand 32 > vape.key

计算IV

遇到困难? ChatGPT

请使用其他语言实现下述代码

    public byte[] getInitializationVector(SecretKey secretKey) {
        byte[] iv = new byte[16]; // 128-bit IV
        System.arraycopy(secretKey.getEncoded(), 0, iv, 0, iv.length);
        return iv;
    }

加密解密

遇到困难? ChatGPT

请使用其他语言实现下述代码

    public String encrypt(@NotNull String plaintext, SecretKey key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        IvParameterSpec ivParams = new IvParameterSpec(getInitializationVector(key));
        cipher.init(Cipher.ENCRYPT_MODE, key, ivParams);
        byte[] encrypted = cipher.doFinal(plaintext.getBytes());
        return Base64.getEncoder().encodeToString(encrypted);
    }

    public String decrypt(String ciphertext, SecretKey key) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        IvParameterSpec ivParams = new IvParameterSpec(getInitializationVector(key));
        cipher.init(Cipher.DECRYPT_MODE, key, ivParams);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
        return new String(decrypted);
    }

验证加密密钥

Example: GatewayFilter.java#L22

对传入的请求头 X-Gateway-Secret 进行解密, 如果解密成功且结果为Hello World即为正确, 否则拒绝连接

实现接口

Example: GatewayController.java

你需要先实现验证加密密钥

丁真服务端会向密钥刷新服务的 /gateway/token 发送一个GET请求, 密钥刷新服务需要刷新共享账户, 刷新成功后需要将Token加密并返回给母服务端

Response:

{
    "token": "<encrypted token>",
    "status": "<status>",
    "coldDown": {
        "time": 0
    }
}
Key Description
token auth.php返回的Token (加密的)
status 状态码
coldDown.time 注入冷却结束时间, Unix时间戳,精确到毫秒

HttpClient

GET http://localhost:8080/gateway/token
X-Gateway-Secret: <encrypted-text>

状态码

Example: VapeAuthorizeDTO.java#L16

返回值见 错误码

Status Description
OK 正确的密钥
SERVLET_ERROR 服务端错误
NO_ACCOUNT 所有的账户都在冷却
INCORRECT 账户密码错误
BANNED 账户被封禁 (102)
CLOUDFLARE IP被封禁(1006)

响应心跳包

Example: GatewayController.java#L51

主控服务端会隔一段时间(通常是30min)向被控发送心跳包, 您的服务端通常只需要返回服务器的信息就可以完成响应

要完成这个相应, 您的服务端需要干如下事情

  1. 验证密钥
  2. 返回数据

返回心跳数据

Method: GET

Uri: /gateway/heartbeat

Response

{
    "time": 0,
    "coldDown": {
        "time": 0
    },
    "implementation": "example/example-gateway"
}
Key Description
time 密钥刷新服务器的时间戳
coldDown.time 注入冷却到期时间
implementation 服务端实现名称

HttpClient

GET http://localhost:8080/gateway/heartbeat
X-Gateway-Secret: <encrypted-text>

进阶

您还可以使用数据库来存储共享账户的信息, 同时, 代理池可能也可以绕过IP封锁.