Skip to content

Commit

Permalink
Merge pull request #2 from saasus-platform/feature/v1
Browse files Browse the repository at this point in the history
release v1
  • Loading branch information
silent-bayline authored Oct 21, 2023
2 parents 11a5a12 + 391f2a0 commit e30e855
Show file tree
Hide file tree
Showing 26 changed files with 9,170 additions and 167 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
51 changes: 0 additions & 51 deletions callback/callback.go

This file was deleted.

101 changes: 70 additions & 31 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,86 @@ import (
"strings"
"time"

"github.com/saasus-platform/saasus-sdk-go/generated/authapi"
"github.com/saasus-platform/saasus-sdk-go/ctxlib"
)

func WithSaasusSigV1() authapi.RequestEditorFn {
return func(ctx context.Context, req *http.Request) error {
secret := os.Getenv("SAASUS_SECRET_KEY")
apiKey := os.Getenv("SAASUS_API_KEY")
saasID := os.Getenv("SAASUS_SAAS_ID")
literal := "SAASUSSIGV1"
// SetSigV1 sets the signature to the request header.
//
// ref: https://docs.saasus.io/reference/getting-started-with-your-api
func SetSigV1(req *http.Request) error {
secret := os.Getenv("SAASUS_SECRET_KEY")
apiKey := os.Getenv("SAASUS_API_KEY")
saasID := os.Getenv("SAASUS_SAAS_ID")
literal := "SAASUSSIGV1"

if secret == "" || apiKey == "" || saasID == "" {
return fmt.Errorf("invalid request: SAASUS_SECRET_KEY, SAASUS_API_KEY, SAASUS_SAAS_ID are required")
}
if secret == "" || apiKey == "" || saasID == "" {
return fmt.Errorf("invalid request: SAASUS_SECRET_KEY, SAASUS_API_KEY, SAASUS_SAAS_ID are required")
}

signatureHmac := hmac.New(sha256.New, []byte(secret))
sigV1 := &sigV1{
nowStr: time.Now().UTC().Format("200601021504"),
secret: secret,
apiKey: apiKey,
literal: literal,
saasID: saasID,
httpMethod: req.Method,
httpURL: req.URL.String(),
httpRequestBody: req.Body,
}

now := time.Now().UTC().Format("200601021504")
signatureHmac.Write([]byte(now))
signatureHmac.Write([]byte(apiKey))
signatureHmac.Write([]byte(strings.ToUpper(req.Method))) // HTTP method
sig, err := sigV1.generate()
if err != nil {
return err
}
req.Body = sigV1.httpRequestBody

hostURI := strings.Split(req.URL.String(), "//")
if len(hostURI) < 2 {
return fmt.Errorf("invalid URL format")
}
req.Header.Set("Authorization", sig)
return nil
}

type sigV1 struct {
nowStr string
secret string
apiKey string
literal string
saasID string
httpMethod string
httpURL string
httpRequestBody io.ReadCloser
}

func (s *sigV1) generate() (string, error) {
signatureHmac := hmac.New(sha256.New, []byte(s.secret))
signatureHmac.Write([]byte(s.nowStr))
signatureHmac.Write([]byte(s.apiKey))
signatureHmac.Write([]byte(strings.ToUpper(s.httpMethod)))

hostURI := strings.Split(s.httpURL, "//")
if len(hostURI) < 2 {
return "", fmt.Errorf("invalid URL format")
}

signatureHmac.Write([]byte(hostURI[1])) // host+URI
signatureHmac.Write([]byte(hostURI[1]))

if req.Body != nil {
bodyBytes, err := io.ReadAll(req.Body)
if err != nil {
return err
}
signatureHmac.Write(bodyBytes)
// Restore the io.ReadCloser to its original state
req.Body = io.NopCloser(bytes.NewReader(bodyBytes))
if s.httpRequestBody != nil {
bodyBytes, err := io.ReadAll(s.httpRequestBody)
if err != nil {
return "", err
}
signatureHmac.Write(bodyBytes)
s.httpRequestBody = io.NopCloser(bytes.NewReader(bodyBytes))
}

authorization := fmt.Sprintf("%s Sig=%s, SaaSID=%s, APIKey=%s", literal, hex.EncodeToString(signatureHmac.Sum(nil)), saasID, apiKey)
req.Header.Set("Authorization", authorization)
sig := fmt.Sprintf("%s Sig=%s, SaaSID=%s, APIKey=%s", s.literal, hex.EncodeToString(signatureHmac.Sum(nil)), s.saasID, s.apiKey)
return sig, nil
}

return nil
// SetReferer sets the referer to the request header if existed.
func SetReferer(ctx context.Context, req *http.Request) {
referer, ok := ctx.Value(ctxlib.RefererKey).(string)
if !ok {
return
}

req.Header.Set("Referer", referer)
}
79 changes: 79 additions & 0 deletions client/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package client

import (
"bytes"
"io"
"testing"

"github.com/go-playground/assert/v2"
)

func Test_sigV1_generate(t *testing.T) {
type fields struct {
nowStr string
secret string
apiKey string
literal string
saasID string
httpMethod string
httpURL string
httpRequestBody io.ReadCloser
}
tests := []struct {
name string
fields fields
want string
wantErr bool
}{
{
name: "success_GET",
fields: fields{
nowStr: "202109011234",
secret: "secret",
apiKey: "apiKey",
literal: "SAASUSSIGV1",
saasID: "saasID",
httpMethod: "GET",
httpURL: "https://api.saasus.io/v1/auth/userinfo",
httpRequestBody: nil,
},
want: "SAASUSSIGV1 Sig=a041e74fb58621f9e2e25453573b6009a93f457a33df970a7d8a5637a593708b, SaaSID=saasID, APIKey=apiKey",
wantErr: false,
},
{
name: "success_POST",
fields: fields{
nowStr: "202109011234",
secret: "secret",
apiKey: "apiKey",
literal: "SAASUSSIGV1",
saasID: "saasID",
httpMethod: "POST",
httpURL: "https://api.saasus.io/v1/auth/userinfo",
httpRequestBody: io.NopCloser(bytes.NewReader([]byte("hello world"))),
},
want: "SAASUSSIGV1 Sig=a23ee22c670a2e7756a7bad8bc2847196783e1e2576b0d999f6d1b6ccbf5e3fa, SaaSID=saasID, APIKey=apiKey",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &sigV1{
nowStr: tt.fields.nowStr,
secret: tt.fields.secret,
apiKey: tt.fields.apiKey,
literal: tt.fields.literal,
saasID: tt.fields.saasID,
httpMethod: tt.fields.httpMethod,
httpURL: tt.fields.httpURL,
httpRequestBody: tt.fields.httpRequestBody,
}
got, err := s.generate()
if (err != nil) != tt.wantErr {
t.Errorf("sigV1.generate() error = %v, wantErr %v", err, tt.wantErr)
return
}
assert.Equal(t, got, tt.want)
})
}
}
8 changes: 8 additions & 0 deletions ctxlib/ctxlib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ctxlib

type CtxKey string

var (
UserInfoKey CtxKey = "userInfo"
RefererKey CtxKey = "referer"
)
4 changes: 2 additions & 2 deletions generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ fi
PACKAGE_NAME=$1
FILE_NAME=$2

oapi-codegen -generate types -package "${PACKAGE_NAME}api" "$FILE_NAME" > "generated/${PACKAGE_NAME}/types.gen.go"
oapi-codegen -generate client -package "${PACKAGE_NAME}api" "$FILE_NAME" > "generated/${PACKAGE_NAME}/client.gen.go"
oapi-codegen -generate types -package "${PACKAGE_NAME}api" "$FILE_NAME" > "generated/${PACKAGE_NAME}api/types.gen.go"
oapi-codegen -generate client -package "${PACKAGE_NAME}api" "$FILE_NAME" > "generated/${PACKAGE_NAME}api/client.gen.go"
Loading

0 comments on commit e30e855

Please sign in to comment.