server: 平台抽象层+bilibili、服务端加密凭据库、角色中间件;web: 精简页面/路由、macOS 客户端(Swift)与多份方案文档;移除误入库的编译产物
This commit is contained in:
@@ -2,11 +2,14 @@ package pairing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -69,11 +72,27 @@ func AutoPair(server, email, password, deviceName, pubKeyB64 string) (uint64, er
|
||||
|
||||
// PairWithCode 凭配对码注册设备,返回服务器分配的设备 ID
|
||||
func PairWithCode(server, pairCode, deviceName, osName, version, pubKeyB64 string) (uint64, error) {
|
||||
pairCode = strings.ToUpper(strings.TrimSpace(pairCode))
|
||||
deviceName = strings.TrimSpace(deviceName)
|
||||
if deviceName == "" {
|
||||
deviceName = "macOS Agent"
|
||||
}
|
||||
pubKeyB64 = strings.TrimSpace(pubKeyB64)
|
||||
if pubKeyB64 == "" {
|
||||
return 0, fmt.Errorf("本机设备公钥为空,请重启客户端后重试")
|
||||
}
|
||||
pubKey, keyErr := base64.StdEncoding.DecodeString(pubKeyB64)
|
||||
if keyErr != nil || len(pubKey) != ed25519.PublicKeySize {
|
||||
return 0, fmt.Errorf("本机设备公钥格式错误,请重启客户端后重试")
|
||||
}
|
||||
code, raw, err := httpJSON("POST", server+"/api/v1/agent/pair", "", ginH{
|
||||
"code": pairCode, "deviceName": deviceName, "os": osName, "version": version, "publicKey": pubKeyB64,
|
||||
})
|
||||
if err != nil || code != 200 {
|
||||
return 0, fmt.Errorf("pair failed: %s", string(raw))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("配对请求失败:%w", err)
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
return 0, fmt.Errorf("%s", responseMessage(raw, "配对失败"))
|
||||
}
|
||||
id, _ := strconv.ParseUint(field(raw, "deviceId"), 10, 64)
|
||||
if id == 0 {
|
||||
@@ -81,3 +100,17 @@ func PairWithCode(server, pairCode, deviceName, osName, version, pubKeyB64 strin
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func responseMessage(raw []byte, fallback string) string {
|
||||
var envelope struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &envelope); err == nil && strings.TrimSpace(envelope.Message) != "" {
|
||||
return envelope.Message
|
||||
}
|
||||
if text := strings.TrimSpace(string(raw)); text != "" {
|
||||
return text
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package pairing
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPairWithCodeSendsNormalizedPayload(t *testing.T) {
|
||||
pub, _, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/api/v1/agent/pair" || r.Method != http.MethodPost {
|
||||
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
|
||||
}
|
||||
var body struct {
|
||||
Code string `json:"code"`
|
||||
DeviceName string `json:"deviceName"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if body.Code != "AB23CD" || body.DeviceName != "macOS Agent" {
|
||||
t.Fatalf("payload was not normalized: %+v", body)
|
||||
}
|
||||
decoded, err := base64.StdEncoding.DecodeString(body.PublicKey)
|
||||
if err != nil || len(decoded) != ed25519.PublicKeySize {
|
||||
t.Fatalf("invalid public key: %q", body.PublicKey)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"code":0,"message":"ok","data":{"deviceId":42}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
id, err := PairWithCode(server.URL, " ab23cd ", "", "core", "0.3.0", base64.StdEncoding.EncodeToString(pub))
|
||||
if err != nil || id != 42 {
|
||||
t.Fatalf("PairWithCode() = %d, %v", id, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPairWithCodeRejectsMissingPublicKey(t *testing.T) {
|
||||
_, err := PairWithCode("http://127.0.0.1:1", "AB23CD", "Mac", "core", "0.3.0", "")
|
||||
if err == nil || !strings.Contains(err.Error(), "公钥") {
|
||||
t.Fatalf("expected actionable public key error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPairWithCodePreservesServerMessage(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
_, _ = w.Write([]byte(`{"code":1001,"data":null,"message":"设备公钥格式不合法"}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
pub, _, _ := ed25519.GenerateKey(rand.Reader)
|
||||
_, err := PairWithCode(server.URL, "AB23CD", "Mac", "core", "0.3.0", base64.StdEncoding.EncodeToString(pub))
|
||||
if err == nil || !strings.Contains(err.Error(), "设备公钥格式不合法") {
|
||||
t.Fatalf("expected server message, got %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user