11package service
22
33import (
4+ "bytes"
5+ "crypto/aes"
6+ "encoding/base64"
7+ "fmt"
8+ "strconv"
9+ "strings"
10+ "time"
11+
412 "github.com/jumpserver/koko/pkg/jms-sdk-go/httplib"
513 "github.com/jumpserver/koko/pkg/jms-sdk-go/model"
614)
@@ -33,6 +41,10 @@ func (u *UserClient) SetOption(setters ...UserClientOption) {
3341 }
3442}
3543
44+ const (
45+ svcHeader = "X-JMS-SVC"
46+ )
47+
3648func (u * UserClient ) GetAPIToken () (resp AuthResponse , err error ) {
3749 data := map [string ]string {
3850 "username" : u .Opts .Username ,
@@ -41,6 +53,15 @@ func (u *UserClient) GetAPIToken() (resp AuthResponse, err error) {
4153 "remote_addr" : u .Opts .RemoteAddr ,
4254 "login_type" : u .Opts .LoginType ,
4355 }
56+ ak := u .Opts .signKey
57+ // 移除 Secret 中的 "-", 保证长度为 32
58+ secretKey := strings .ReplaceAll (ak .Secret , "-" , "" )
59+ encryptKey , err := GenerateEncryptKey (secretKey )
60+ if err != nil {
61+ return resp , err
62+ }
63+ signKey := fmt .Sprintf ("%s:%s" , ak .ID , encryptKey )
64+ u .client .SetHeader (svcHeader , fmt .Sprintf ("Sign %s" , signKey ))
4465 _ , err = u .client .Post (UserTokenAuthURL , data , & resp )
4566 return
4667}
@@ -129,11 +150,70 @@ func UserClientHttpClient(con *httplib.Client) UserClientOption {
129150 }
130151}
131152
153+ func UserClientSvcSignKey (key model.AccessKey ) UserClientOption {
154+ return func (args * UserClientOptions ) {
155+ args .signKey = key
156+ }
157+ }
158+
159+ func GenerateEncryptKey (key string ) (string , error ) {
160+ seconds := time .Now ().Unix ()
161+ value := strconv .FormatUint (uint64 (seconds ), 10 )
162+ return EncryptECB (value , key )
163+ }
164+
132165type UserClientOptions struct {
133166 Username string
134167 Password string
135168 PublicKey string
136169 RemoteAddr string
137170 LoginType string
138171 client * httplib.Client
172+
173+ signKey model.AccessKey
174+ }
175+
176+ func EncryptECB (plaintext string , key string ) (string , error ) {
177+ block , err := aes .NewCipher ([]byte (key ))
178+ if err != nil {
179+ return "" , err
180+ }
181+ newPlaintext := make ([]byte , 0 , len (plaintext ))
182+ newPlaintext = append (newPlaintext , []byte (plaintext )... )
183+ if len (newPlaintext )% aes .BlockSize != 0 {
184+ padding := aes .BlockSize - len (plaintext )% aes .BlockSize
185+ newPlaintext = append (newPlaintext , bytes .Repeat ([]byte {byte (0x00 )}, padding )... )
186+ }
187+
188+ ciphertext := make ([]byte , len (newPlaintext ))
189+ for i := 0 ; i < len (newPlaintext ); i += aes .BlockSize {
190+ block .Encrypt (ciphertext [i :i + aes .BlockSize ], newPlaintext [i :i + aes .BlockSize ])
191+ }
192+ ret := base64 .StdEncoding .EncodeToString (ciphertext )
193+ return ret , nil
194+ }
195+
196+ func DecryptECB (ciphertext string , key string ) (string , error ) {
197+ ret , err := base64 .StdEncoding .DecodeString (ciphertext )
198+ if err != nil {
199+ return "" , err
200+ }
201+ block , err := aes .NewCipher ([]byte (key ))
202+ if err != nil {
203+ return "" , err
204+ }
205+
206+ if len (ret )% aes .BlockSize != 0 {
207+ return "" , fmt .Errorf ("ciphertext is not a multiple of the block size" )
208+ }
209+ plaintext := make ([]byte , len (ret ))
210+ for i := 0 ; i < len (ret ); i += aes .BlockSize {
211+ block .Decrypt (plaintext [i :i + aes .BlockSize ], ret [i :i + aes .BlockSize ])
212+ }
213+
214+ // 移除 Zero 填充
215+ for len (plaintext ) > 0 && plaintext [len (plaintext )- 1 ] == 0x00 {
216+ plaintext = plaintext [:len (plaintext )- 1 ]
217+ }
218+ return string (plaintext ), nil
139219}
0 commit comments