mirror of https://github.com/allinssl/allinssl
commit
de385343a8
|
@ -0,0 +1,165 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LoginInfo struct {
|
||||
account string
|
||||
password string
|
||||
}
|
||||
type LoginResponse struct {
|
||||
Code string
|
||||
Message string
|
||||
Data string
|
||||
Success bool
|
||||
}
|
||||
|
||||
type HTTPSConfig struct {
|
||||
HTTPSStatus string `json:"https_status"`
|
||||
CertificateSource string `json:"certificate_source"`
|
||||
CertificateName string `json:"certificate_name"`
|
||||
CertificateValue string `json:"certificate_value"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
}
|
||||
|
||||
type DeployConfig struct {
|
||||
DomainID string `json:"doMainId"`
|
||||
HTTPS HTTPSConfig `json:"https"`
|
||||
}
|
||||
|
||||
func randomString(n int) string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = charset[rand.Intn(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
const baseUrl = "https://www.kuocaiyun.com/"
|
||||
|
||||
func login(loginInfo LoginInfo) (string, error) {
|
||||
loginUrl := baseUrl + "login/loginUser"
|
||||
formData := url.Values{}
|
||||
formData.Set("userAccount", loginInfo.account)
|
||||
formData.Set("userPwd", loginInfo.password)
|
||||
formData.Set("remember", "true")
|
||||
resp, err := http.Post(loginUrl, "application/x-www-form-urlencoded", strings.NewReader(formData.Encode()))
|
||||
const emptyString = ""
|
||||
if err != nil {
|
||||
outputError("请求失败", err)
|
||||
return emptyString, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return emptyString, errors.New("请求失败:" + string(rune(resp.StatusCode)))
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
if err != nil {
|
||||
outputError("关闭响应流失败", err)
|
||||
}
|
||||
}(resp.Body)
|
||||
// 读取响应体
|
||||
var loginResp LoginResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&loginResp); err != nil {
|
||||
outputError("解析登录请求结果失败", err)
|
||||
return emptyString, err
|
||||
}
|
||||
if !loginResp.Success || loginResp.Data == "" {
|
||||
return emptyString, errors.New("登录请求失败:" + loginResp.Message)
|
||||
}
|
||||
return loginResp.Data, nil
|
||||
}
|
||||
|
||||
func deployCert(token string, domainId string, certKey string, certValue string) (map[string]interface{}, error) {
|
||||
deployUrl := baseUrl + "CdnDomainHttps/httpsConfiguration"
|
||||
params := DeployConfig{
|
||||
DomainID: domainId,
|
||||
HTTPS: HTTPSConfig{
|
||||
HTTPSStatus: "on",
|
||||
CertificateSource: "0",
|
||||
CertificateName: "cert_" + randomString(13),
|
||||
CertificateValue: certValue,
|
||||
PrivateKey: certKey,
|
||||
},
|
||||
}
|
||||
// 序列化参数
|
||||
jsonData, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("JSON序列化失败: %v", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", deployUrl, strings.NewReader(string(jsonData)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Cookie", "kuocai_cdn_token="+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("HTTP请求失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 解析响应
|
||||
var result map[string]interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return nil, fmt.Errorf("响应解析失败: %v", err)
|
||||
}
|
||||
if !result["success"].(bool) {
|
||||
return result, fmt.Errorf("更新证书失败")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func Upload(cfg map[string]any) (*Response, error) {
|
||||
if cfg == nil {
|
||||
return nil, fmt.Errorf("config cannot be nil")
|
||||
}
|
||||
certStr, ok := cfg["cert"].(string)
|
||||
if !ok || certStr == "" {
|
||||
return nil, fmt.Errorf("cert is required and must be a string")
|
||||
}
|
||||
keyStr, ok := cfg["key"].(string)
|
||||
if !ok || keyStr == "" {
|
||||
return nil, fmt.Errorf("key is required and must be a string")
|
||||
}
|
||||
username, ok := cfg["username"].(string)
|
||||
if !ok || username == "" {
|
||||
return nil, fmt.Errorf("username is required and must be a string")
|
||||
}
|
||||
password, ok := cfg["password"].(string)
|
||||
if !ok || password == "" {
|
||||
return nil, fmt.Errorf("password is required and must be a string")
|
||||
}
|
||||
domainId, ok := cfg["domainId"].(string)
|
||||
if !ok || domainId == "" {
|
||||
return nil, fmt.Errorf("domainId is required and must be a string")
|
||||
}
|
||||
token, err := login(LoginInfo{account: username, password: password})
|
||||
if err != nil || token == "" {
|
||||
return nil, fmt.Errorf("fetch token failed, err %v", err)
|
||||
}
|
||||
res, err := deployCert(token, domainId, keyStr, certStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Response{
|
||||
Status: "success",
|
||||
Message: "success",
|
||||
Result: res,
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type ActionInfo struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Params map[string]any `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
type Request struct {
|
||||
Action string `json:"action"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Result map[string]interface{} `json:"result"`
|
||||
}
|
||||
|
||||
var pluginMeta = map[string]interface{}{
|
||||
"name": "kuocai",
|
||||
"description": "部署到括彩云",
|
||||
"version": "1.0.0",
|
||||
"author": "coclyun",
|
||||
"config": map[string]interface{}{
|
||||
"username": "括彩云账号",
|
||||
"password": "括彩云密码",
|
||||
},
|
||||
"actions": []ActionInfo{
|
||||
{
|
||||
Name: "upload",
|
||||
Description: "部署到括彩云",
|
||||
Params: map[string]any{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func outputJSON(resp *Response) {
|
||||
_ = json.NewEncoder(os.Stdout).Encode(resp)
|
||||
}
|
||||
|
||||
func outputError(msg string, err error) {
|
||||
outputJSON(&Response{
|
||||
Status: "error",
|
||||
Message: fmt.Sprintf("%s: %v", msg, err),
|
||||
})
|
||||
}
|
||||
|
||||
func main() {
|
||||
var req Request
|
||||
input, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
outputError("读取输入失败", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(input, &req); err != nil {
|
||||
outputError("解析请求失败", err)
|
||||
return
|
||||
}
|
||||
|
||||
switch req.Action {
|
||||
case "get_metadata":
|
||||
outputJSON(&Response{
|
||||
Status: "success",
|
||||
Message: "插件信息",
|
||||
Result: pluginMeta,
|
||||
})
|
||||
case "list_actions":
|
||||
outputJSON(&Response{
|
||||
Status: "success",
|
||||
Message: "支持的动作",
|
||||
Result: map[string]interface{}{"actions": pluginMeta["actions"]},
|
||||
})
|
||||
case "upload":
|
||||
rep, err := Upload(req.Params)
|
||||
if err != nil {
|
||||
outputError("CDN 部署失败", err)
|
||||
return
|
||||
}
|
||||
outputJSON(rep)
|
||||
|
||||
default:
|
||||
outputJSON(&Response{
|
||||
Status: "error",
|
||||
Message: "未知 action: " + req.Action,
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue