mirror of
https://github.com/xiaoyaDev/xiaoya-alist.git
synced 2026-10-16 21:50:48 +08:00
fix: aliyun tvtoken connector
This commit is contained in:
@@ -1,15 +1,21 @@
|
||||
FROM golang:1.22-alpine3.20 as builder
|
||||
FROM python:3.12-alpine3.20
|
||||
|
||||
WORKDIR /app/
|
||||
ENV TZ=Asia/Shanghai
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN go build
|
||||
|
||||
FROM alpine:3.20
|
||||
|
||||
COPY --from=builder --chmod=755 /app/aliyuntvtoken_connector /aliyuntvtoken_connector
|
||||
RUN set -ex && \
|
||||
apk add --no-cache \
|
||||
bash \
|
||||
tzdata && \
|
||||
python3 -m pip install --no-cache-dir --upgrade pip && \
|
||||
pip install --no-cache-dir -r /app/requirements.txt && \
|
||||
rm -rf \
|
||||
/root/.cache \
|
||||
/tmp/*
|
||||
|
||||
EXPOSE 34278
|
||||
|
||||
ENTRYPOINT ["/aliyuntvtoken_connector"]
|
||||
ENTRYPOINT [ "python3", "/app/main.py" ]
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
module aliyuntvtoken_connector
|
||||
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/tidwall/gjson v1.17.3
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
)
|
||||
@@ -1,26 +0,0 @@
|
||||
github.com/cossacklabs/acra v0.0.0-20240710145658-5ce84537e918 h1:qB2I/aGWRmaoZ4kFdn2+BKhlGcL5mFRTmN9fBynj+NI=
|
||||
github.com/cossacklabs/acra v0.0.0-20240710145658-5ce84537e918/go.mod h1:x514dvzz+Gyq3u7G4C/aZgamU3ryUj78iVhmIUxdkMs=
|
||||
github.com/cossacklabs/themis/gothemis v0.14.0 h1:b+LU09HBcmhmGP444gz7P64Nfrd7b/Sj1s+9Ibt4PkU=
|
||||
github.com/cossacklabs/themis/gothemis v0.14.0/go.mod h1:6fvSguI8fMmChlgdG0cZywirhtTsRmp+/PsCWLDUID8=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/tidwall/gjson v1.14.2 h1:6BBkirS0rAHjumnjHF6qgy5d2YAJ1TLIaFE2lzfOLqo=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
|
||||
github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
@@ -1,108 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
TokenType string `json:"token_type"`
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
}
|
||||
|
||||
func decrypt_AES256_CBC_PKCS7(ciphertext, key, iv string) (string, error) {
|
||||
decoded_ciphertext, _ := base64.StdEncoding.DecodeString(ciphertext)
|
||||
ivBytes, _ := hex.DecodeString(iv)
|
||||
key = key[:32]
|
||||
key = key + strings.Repeat("\x00", 32-len(key))
|
||||
block, err := aes.NewCipher([]byte(key))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(decoded_ciphertext) < aes.BlockSize {
|
||||
return "", errors.New("ciphertext too short")
|
||||
}
|
||||
cbc := cipher.NewCBCDecrypter(block, ivBytes)
|
||||
cbc.CryptBlocks(decoded_ciphertext, decoded_ciphertext)
|
||||
var unpad = func(ciphertext []byte) ([]byte, error) {
|
||||
padding := ciphertext[len(ciphertext)-1]
|
||||
if int(padding) > len(ciphertext) {
|
||||
return nil, errors.New("padding is invalid")
|
||||
}
|
||||
for i := 0; i < int(padding); i++ {
|
||||
if ciphertext[len(ciphertext)-i-1] != padding {
|
||||
return nil, errors.New("padding is invalid")
|
||||
}
|
||||
}
|
||||
return ciphertext[:len(ciphertext)-int(padding)], nil
|
||||
}
|
||||
unpadded_data, err := unpad(decoded_ciphertext)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(unpadded_data), nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/oauth/alipan/token", func(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
refresh_token := r.FormValue("refresh_token")
|
||||
if refresh_token == "" {
|
||||
var body map[string]interface{}
|
||||
err := json.NewDecoder(r.Body).Decode(&body)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if val, ok := body["refresh_token"]; ok {
|
||||
refresh_token = val.(string)
|
||||
}
|
||||
}
|
||||
reqBodyJson := `{"refresh_token": "` + refresh_token + `"}`
|
||||
|
||||
resp, err := http.Post("http://api.extscreen.com/aliyundrive/v2/token", "application/json", strings.NewReader(reqBodyJson))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, _ := io.ReadAll(resp.Body)
|
||||
if gjson.Get(string(respBody), "code").Int() == 200 {
|
||||
ciphertext := gjson.Get(string(respBody), "data.ciphertext").String()
|
||||
iv := gjson.Get(string(respBody), "data.iv").String()
|
||||
|
||||
key := "^(i/x>>5(ebyhumz*i1wkpk^orIs^Na."
|
||||
|
||||
token_data, _ := decrypt_AES256_CBC_PKCS7(ciphertext, key, iv)
|
||||
|
||||
var token Token
|
||||
json.Unmarshal([]byte(token_data), &token)
|
||||
fmt.Println(token)
|
||||
json.NewEncoder(w).Encode(token)
|
||||
} else {
|
||||
json.NewEncoder(w).Encode(string(respBody))
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("Running on 34278")
|
||||
err := http.ListenAndServe(":34278", nil)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
from flask import Flask, request, Response
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util.Padding import unpad
|
||||
import json
|
||||
import base64
|
||||
import requests
|
||||
import requests
|
||||
import json
|
||||
import uuid
|
||||
import hashlib
|
||||
import base64
|
||||
import random
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
headers = {
|
||||
"token": "6733b42e28cdba32",
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; U; Android 9; zh-cn; SM-S908E Build/TP1A.220624.014) AppleWebKit/533.1 (KHTML, like Gecko) Mobile Safari/533.1',
|
||||
'Host': 'api.extscreen.com'
|
||||
}
|
||||
|
||||
|
||||
def h(char_array, modifier):
|
||||
unique_chars = list(dict.fromkeys(char_array))
|
||||
numeric_modifier = int(modifier[7:])
|
||||
transformed_string = "".join([chr(abs(ord(c) - (numeric_modifier % 127) - 1) + 33 if abs(ord(c) - (numeric_modifier % 127) - 1) < 33 else
|
||||
abs(ord(c) - (numeric_modifier % 127) - 1)) for c in unique_chars])
|
||||
return transformed_string
|
||||
|
||||
|
||||
def decrypt(ciphertext, iv, t, unique_id, wifimac):
|
||||
try:
|
||||
key = generate_key(t, unique_id, wifimac)
|
||||
cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv = bytes.fromhex(iv))
|
||||
decrypted = unpad(cipher.decrypt(base64.b64decode(ciphertext)), AES.block_size)
|
||||
dec = decrypted.decode('utf-8')
|
||||
return dec
|
||||
except Exception as error:
|
||||
print("Decryption failed", error)
|
||||
raise error
|
||||
|
||||
|
||||
def get_params(t, unique_id, wifimac):
|
||||
params = {
|
||||
'akv': '2.8.1496',
|
||||
'apv': '1.3.6',
|
||||
'b': 'OnePlus',
|
||||
'd': unique_id,
|
||||
'm': 'PJX110',
|
||||
'mac': '',
|
||||
'n': 'PJX110',
|
||||
't': t,
|
||||
'wifiMac': wifimac,
|
||||
}
|
||||
return params
|
||||
|
||||
|
||||
def generate_key(t, unique_id, wifimac):
|
||||
params = get_params(t, unique_id, wifimac)
|
||||
sorted_keys = sorted(params.keys())
|
||||
concatenated_params = "".join([params[key] for key in sorted_keys if key != "t"])
|
||||
hashed_key = h(list(concatenated_params), t)
|
||||
return hashlib.md5(hashed_key.encode('utf-8')).hexdigest()
|
||||
|
||||
|
||||
@app.route('/oauth/alipan/token', methods=['POST'])
|
||||
def oauth_token():
|
||||
data = request.get_json()
|
||||
refresh_token = data.get('refresh_token', None)
|
||||
if not refresh_token:
|
||||
return Response(json.dumps({"error": "No refresh_token provided"}), status=400, mimetype='application/json')
|
||||
|
||||
req_body = {
|
||||
"refresh_token": refresh_token
|
||||
}
|
||||
|
||||
timestamp = str(requests.get('http://api.extscreen.com/timestamp').json()['data']['timestamp'])
|
||||
unique_id = uuid.uuid4().hex
|
||||
wifimac = str(random.randint(10**11, 10**12 - 1))
|
||||
|
||||
resp = requests.post("http://api.extscreen.com/aliyundrive/v3/token", data=req_body, headers={**get_params(timestamp, unique_id, wifimac), **headers})
|
||||
if resp.status_code == 200:
|
||||
resp_data = resp.json()
|
||||
ciphertext = resp_data["data"]["ciphertext"]
|
||||
iv = resp_data["data"]["iv"]
|
||||
|
||||
token_data = decrypt(ciphertext, iv, timestamp, unique_id, wifimac)
|
||||
token = json.loads(token_data)
|
||||
return Response(json.dumps(token), status=200, mimetype='application/json')
|
||||
else:
|
||||
return Response(resp.content, status=resp.status_code, mimetype='application/json')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, port=34278)
|
||||
@@ -0,0 +1,3 @@
|
||||
flask
|
||||
requests
|
||||
pycryptodome
|
||||
Reference in New Issue
Block a user