diff --git a/.env.sample b/.env.sample index 761be55..a21674b 100644 --- a/.env.sample +++ b/.env.sample @@ -3,4 +3,8 @@ BASEURL_DISCOVERY="https:///v2" # Space and Time Discovery API Endpoi USERID="" # UserID required for authentication and authorization JOINCODE="" # Space and Time Join Code which can be got from the SxT release team SCHEME="ed25519" # The key scheme or algorithm required for key generation -PREFIX="" # Optional Prefix Parameter for signature generation \ No newline at end of file + +# TEST +TEST_USER= +TEST_USER_PRIVKEY= +TEST_USER_PUBKEY= \ No newline at end of file diff --git a/README.md b/README.md index 589f01a..3cd0ffb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# go-sxt-sdk (v.0.0.7) +# go-sxt-sdk (v.0.0.8) Golang SDK for Space and Time Gateway (go version >= 1.18) @@ -87,7 +87,7 @@ The generated `AccessToken` is valid for 25 minutes and the `refreshToken` for 3 ```go // New Authentication. // Generates new accessToken, refreshToken, privateKey, and publicKey -func authenticate()(accessToken, refreshToken string, privateKey ed25519.PrivateKey, publicKey ed25519.PublicKey){ +func Authenticate()(accessToken, refreshToken string, privateKey ed25519.PrivateKey, publicKey ed25519.PublicKey){ // Read userId, joinCode from .env file userId, _ := helpers.ReadUserId() diff --git a/helpers/readenvironment.go b/helpers/readenvironment.go index 9a92b86..4ea80e3 100644 --- a/helpers/readenvironment.go +++ b/helpers/readenvironment.go @@ -3,91 +3,81 @@ package helpers import ( "log" "os" - "path/filepath" "github.com/joho/godotenv" ) // Read User Id from Environment func ReadUserId() (value string, ok bool){ - err := godotenv.Load(filepath.Join("./", ".env")) - if err != nil { - log.Fatal(err.Error()) - } value, ok = os.LookupEnv("USERID") - if !ok { - log.Fatal("USERID not set in environment") + envFile, _ := godotenv.Read(".env") + value = envFile["USERID"] + + if value == ""{ + log.Fatal("USERID not set in environment") + } } - return value, ok + + return value, true } // Read Join Code from Environment func ReadJoinCode() (value string, ok bool){ - - err := godotenv.Load(filepath.Join("./", ".env")) - if err != nil { - log.Fatal(err.Error()) - } - - value, ok = os.LookupEnv("JOINCODE") - if !ok { - log.Fatal("JOINCODE not set in environment") - } + envFile, _ := godotenv.Read(".env") + value = envFile["JOINCODE"] - return value, ok + if value == ""{ + log.Fatal("JOINCODE not set in environment") + } + } + + return value, true } // Read API End Point Discovery from Environment func ReadEndPointDiscovery() (value string, ok bool){ - - err := godotenv.Load(filepath.Join("./", ".env")) - if err != nil { - log.Fatal(err.Error()) - } - - value, ok = os.LookupEnv("BASEURL_DISCOVERY") - if !ok { - log.Fatal("Discovery BASEURL not set in environment") + envFile, _ := godotenv.Read(".env") + value = envFile["BASEURL_DISCOVERY"] + + if value == ""{ + log.Fatal("BASEURL_DISCOVERY not set in environment") + } } - return value, ok + return value, true } // Read API End Point Others in General from Environment func ReadEndPointGeneral() (value string, ok bool){ - err := godotenv.Load(filepath.Join("./", ".env")) - if err != nil { - log.Fatal(err.Error()) - } - - value, ok = os.LookupEnv("BASEURL_GENERAL") - if !ok { - log.Fatal("General BASEURL not set in environment") + envFile, _ := godotenv.Read(".env") + value = envFile["BASEURL_GENERAL"] + + if value == ""{ + log.Fatal("BASEURL_GENERAL not set in environment") + } } - return value, ok + + return value, true } // Read Scheme from Environment func ReadScheme() (value string, ok bool){ - - err := godotenv.Load(filepath.Join("./", ".env")) - if err != nil { - log.Fatal(err.Error()) - } - - value, ok = os.LookupEnv("SCHEME") - if !ok { - log.Fatal("SCHEME not set in environment") + envFile, _ := godotenv.Read(".env") + value = envFile["SCHEME"] + + if value == ""{ + log.Fatal("SCHEME not set in environment") + } } - return value, ok + return value, true } \ No newline at end of file diff --git a/main.go b/main.go index c78d90e..43ebb64 100644 --- a/main.go +++ b/main.go @@ -2,20 +2,15 @@ package main import ( "crypto/ed25519" - "encoding/base64" - "encoding/json" "flag" "fmt" "log" "os" "github.com/spaceandtimelabs/SxT-Go-SDK/authentication" - "github.com/spaceandtimelabs/SxT-Go-SDK/authorization" - "github.com/spaceandtimelabs/SxT-Go-SDK/discovery" "github.com/spaceandtimelabs/SxT-Go-SDK/helpers" - "github.com/spaceandtimelabs/SxT-Go-SDK/sqlcore" - "github.com/spaceandtimelabs/SxT-Go-SDK/sqlview" "github.com/spaceandtimelabs/SxT-Go-SDK/storage" + "github.com/spaceandtimelabs/SxT-Go-SDK/utils" ) // Check the command line arguments @@ -29,85 +24,7 @@ func isFlagPassed(name string) int { return count } -// New Authentication. -// This method generates new accessToken, refreshToken, privateKey, and publicKey -func authenticate(inputUserId, inputPublicKey, inputPrivateKey string) (accessToken, refreshToken string, privateKey ed25519.PrivateKey, publicKey ed25519.PublicKey) { - /************************************* - // AUTHENTICATION APIS - *************************************/ - - userId, _ := helpers.ReadUserId() - joinCode, _ := helpers.ReadJoinCode() - - var pubkey ed25519.PublicKey - var privkey ed25519.PrivateKey - var e error - - var authCodeStruct authentication.AuthCodeStruct - var tokenStruct authentication.TokenStruct - var sessionStruct storage.FileSessionStruct - var sessionStatus bool - - if inputUserId != "" && inputPublicKey != "" && inputPrivateKey != "" { - pubkey, e = base64.StdEncoding.DecodeString(inputPublicKey) - if e != nil { - log.Fatal("base64 std encoded public key expected") - } - - privkey, e = base64.StdEncoding.DecodeString(inputPrivateKey) - if e != nil { - log.Fatal("base64 std encoded private key expected") - } - - // Key compatibility - if len(privkey) == len(pubkey) { - var tmpPvtKey []byte - for idx := range privkey { - tmpPvtKey = append(tmpPvtKey, privkey[idx]) - } - - for idx := range pubkey { - tmpPvtKey = append(tmpPvtKey, pubkey[idx]) - } - privkey = tmpPvtKey - } - - userId = inputUserId - } else { - sessionStruct, sessionStatus = storage.FileReadSession(userId) - - if !sessionStatus { - // Generate Private and Public keys - pubkey, privkey = helpers.CreateKey() - } else { - pubkey = sessionStruct.PublicKey - privkey = sessionStruct.PrivateKey - } - } - - // Get auth code - authCode := authentication.GenerateAuthCode(userId, joinCode) - json.Unmarshal([]byte(authCode), &authCodeStruct) - - // Get Keys - encodedSignature, base64PublicKey := authentication.GenerateKeys(authCodeStruct.AuthCode, pubkey, privkey) - - // Get Token - tokenJson := authentication.GenerateToken(userId, authCodeStruct.AuthCode, encodedSignature, base64PublicKey) - json.Unmarshal([]byte(tokenJson), &tokenStruct) - - // fmt.Println(userId, tokenStruct.AccessToken, tokenStruct.RefreshToken, privkey, pubkey) - - writeStatus := storage.FileWriteSession(userId, tokenStruct.AccessToken, tokenStruct.RefreshToken, privkey, pubkey) - if !writeStatus { - log.Fatal("Invalid login. Change login credentials") - } - - // Logout - // authentication.Logout() - return tokenStruct.AccessToken, tokenStruct.RefreshToken, privkey, publicKey -} // Main function func main() { @@ -121,9 +38,6 @@ func main() { var publicKey ed25519.PublicKey var accessToken string - var sxtBiscuitCapabilities []authorization.SxTBiscuitStruct - - inputUserid := flag.String("userid", "", "(Optional) SxT userid. But if provided, the remaining values are required") inputPubKey := flag.String("pubkey", "", "(Optional) Standard base64 encoded public key. But if provided, the remaining values are required") @@ -146,8 +60,8 @@ func main() { if isFlagPassed("userid")+isFlagPassed("pubkey")+isFlagPassed("privkey") == 3 { if len(*inputUserid) > 0 || len(*inputPubKey) > 0 || len(*inputPrivKey) > 0 { - accessToken, _, privateKey, publicKey = authenticate(*inputUserid, *inputPubKey, *inputPrivKey) - fmt.Println("=== Existing Login from user input ===") + accessToken, _, privateKey, publicKey, _ = utils.Authenticate(*inputUserid, *inputPubKey, *inputPrivKey) + fmt.Println("=== Existing Login from user input ===", accessToken) } else { fmt.Println("=== Empty input values. Stopping program ===") @@ -160,7 +74,7 @@ func main() { if !status { emptyString := "" - accessToken, _, privateKey, publicKey = authenticate(emptyString, emptyString, emptyString) + accessToken, _, privateKey, publicKey, _ = utils.Authenticate(emptyString, emptyString, emptyString) fmt.Println("=== New Login. Creating new session ===") } else { @@ -186,7 +100,7 @@ func main() { } else { fmt.Println("=== Invalid session on session.txt file. Issuing new token ===") emptyString := "" - accessToken, _, privateKey, publicKey = authenticate(emptyString, emptyString, emptyString) + accessToken, _, privateKey, publicKey, _ = utils.Authenticate(emptyString, emptyString, emptyString) } } else { fmt.Println("=== Login using session.txt file ===") @@ -202,152 +116,9 @@ func main() { /* AUTH BLOCK ENDS */ - /************************************* - // SXT Biscuit - *************************************/ - - // Operation values can include - /* - SQL operations: - DDL: for operating on database objects & schema (e.g. table, view) - ddl_create : SQL CREATE command - ddl_alter : SQL ALTER command - ddl_drop : SQL DROP command - - DML: for performing data manipulation - dml_insert : SQL INSERT command - dml_update : SQL UPDATE command - dml_merge : DQL MERGE command - dml_delete : SQL DELETE command - - DQL: for performing queries - dql_select : SQL SELECT command - - Kafka ICM operations: - kafka_icm_create : ICM create - kafka_icm_read : ICM read - kafka_icm_update : ICM update - kafka_icm_delete : ICM delete - - For wildcards, use *, like - authorization.SxTBiscuitStruct{Operation: "*", Resource: "eth.TESTTABLE106"} - - */ - sxtBiscuitCapabilities = append(sxtBiscuitCapabilities, authorization.SxTBiscuitStruct{Operation: "dql_select", Resource: "eth.testtable106"}) - sxtBiscuitCapabilities = append(sxtBiscuitCapabilities, authorization.SxTBiscuitStruct{Operation: "dml_insert", Resource: "eth.testtable106"}) - sxtBiscuitCapabilities = append(sxtBiscuitCapabilities, authorization.SxTBiscuitStruct{Operation: "dml_update", Resource: "eth.testtable106"}) - sxtBiscuitCapabilities = append(sxtBiscuitCapabilities, authorization.SxTBiscuitStruct{Operation: "dml_delete", Resource: "eth.testtable106"}) - sxtBiscuitCapabilities = append(sxtBiscuitCapabilities, authorization.SxTBiscuitStruct{Operation: "ddl_create", Resource: "eth.testtable106"}) - - biscuit, _ := authorization.CreateBiscuitToken(sxtBiscuitCapabilities, &privateKey) - - // Set some constant values - // Create multiple biscuits - mb := []string{biscuit} - originApp := "TEST" - - - /************************************* - // SQL CORE - *************************************/ - - // DDL - // Create a new schema - // This wont work as ETH already exists. Write your own - sqlcore.CreateSchema("CREATE SCHEMA ETH", originApp, mb) - - // DDL - // Only for create queries - // For ALTER and DROP, use sqlcore.DDL() - sqlcore.CreateTable("CREATE TABLE ETH.TESTTABLE106 (id INT PRIMARY KEY, test VARCHAR)", "ALL", originApp, mb, publicKey) - - - - // DML - // use the sqlcore.DML to write insert, update, delete, and merge queries - resources := []string{"ETH.TESTTABLE106"} - sqlcore.DML("insert into ETH.TESTTABLE106 values(5, 'x5')", originApp, mb, resources) - - // DQL - // Select operations - // If rowCount is 0, then fetches all data without limit - d, e, s := sqlcore.DQL("select * from ETH.TESTTABLE106", originApp, mb, resources, 0) - if !s { - log.Println(e) - } else { - log.Println(d) - } - - // DDL - // Only for ALTER and DROP queries - // For Create table queries, use sqlcore.CreateTable() - // For this to work, you will need to provide permissions in biscuit first - sqlcore.DDL("DROP TABLE ETH.TESTTABLE106", originApp, mb ) - - /************************************* - // SQL VIEW - *************************************/ - - // Create parameters to pass to view requests - // Optional param for sqlview.Create(). Not required if viewText param doesnt contain any paramter - var parametersRequest []sqlview.ParametersRequest - // parametersRequest = append(parametersRequest, sqlview.ParametersRequest{Name: "count", Type: "integer"}) - - // CREATE VIEW - sqlview.Create("ETH.TESTTABLE106", "testview61", "select count(id) as x from ETH.TESTTABLE106", "Test description", true, parametersRequest) - - // EXECUTE VIEW - sqlview.Execute("testview61", parametersRequest) - - // UPDATE VIEW - sqlview.Update("ETH.TESTTABLE106", "testview61", "select count(id) as x from ETH.TESTTABLE106", "Test description", true, parametersRequest) - - // DELETE VIEW - sqlview.Delete("testview61") - - /************************************* - // DISCOVERY APIS - *************************************/ - - // List Schemas - discovery.ListSchemas("ALL", "") - - // List Tables in a given schema - // Possible scope values - - // 1. ALL = all resources, - // 2. PUBLIC = non-permissioned tables, - // 3. PRIVATE = tables created by the requesting user - // 4. SUBSCRIPTION = include all resources the requesting user can see - // Note: schema and table names are case sensitive. Upper cased - discovery.ListTables("ETH", "ALL", "") - - // List Columns for a given table in schema - // Note: schema and table names are case sensitive. Upper cased - discovery.ListColumns("ETH", "TESTTABLE106") - - // List table index for a given table in schema - // Note: schema and table names are case sensitive. Upper cased - discovery.ListTableIndex("ETH", "TESTTABLE106") - - // List table primary key for a given table in schema - // Note: schema and table names are case sensitive. Upper cased - discovery.ListTablePrimaryKey("ETH", "TESTTABLE106") - - // List table relations for a schema and scope - // Note: schema and table names are case sensitive. Upper cased - discovery.ListTableRelations("ETH", "PRIVATE") - - // List table primary key references for a table and a schema - // Note: schema and table names are case sensitive. Upper cased - discovery.ListPrimaryKeyReferences("ETH", "TESTTABLE106", "TEST") - - // List foreign key references for a table, column and a schema - // Note: schema and table names are case sensitive. Upper cased - discovery.ListForeignKeyReferences("ETH", "TESTTABLE106", "TEST") - - // List views for a view name for a owner - // Second parameter can be "", "true" or "false". It accepts a string and not a boolean - // Note: schema and table names are case sensitive. Upper cased - discovery.ListViews("SOME_VIEW_NAME", "") + // Call SQL functions + utils.SQLAPIs(privateKey, publicKey) + utils.DiscoveryAPIs() + } diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..d100980 --- /dev/null +++ b/main_test.go @@ -0,0 +1,61 @@ +package main + +import ( + "crypto/ed25519" + "os" + "testing" + + "github.com/spaceandtimelabs/SxT-Go-SDK/utils" +) + +var userId, privKeyB64, pubKeyB64 string +var privKey ed25519.PrivateKey +var pubKey ed25519.PublicKey + +// Test Authentication +func TestAuthentication(t *testing.T){ + userId, ok := os.LookupEnv("TEST_TRIAL_USERID") + if !ok { + t.Error("TEST_TRIAL_USERID not set in env") + } + + privKeyB64, ok = os.LookupEnv("TEST_TRIAL_PRIVKEY") + if !ok { + t.Error("TEST_TRIAL_PRIVKEY not set in env") + } + + pubKeyB64, ok = os.LookupEnv("TEST_TRIAL_PUBKEY") + if !ok { + t.Error("TEST_TRIAL_PUBKEY not set in env") + } + + _, _, privKeyBytes, pubKeyBytes, err := utils.Authenticate(userId, pubKeyB64, privKeyB64) + + if err != nil { + t.Errorf("Autentication error %q", err) + } + + pubKey = pubKeyBytes + privKey = privKeyBytes + +} + +// Test SQL APIs +func TestSQLAPIs(t *testing.T){ + err := utils.SQLAPIs(privKey, pubKey) + // Intentionally skip errors as we dont want to modify any records + // This will always throw error + if err == nil { + t.Errorf("SQL API error %q", err) + } +} + + + +// Test Discovery APIs +func TestDiscoveryAPIs(t *testing.T){ + err := utils.DiscoveryAPIs() + if err != nil { + t.Errorf("Discovery APIs error %q", err) + } +} \ No newline at end of file diff --git a/sqlcore/ddl_test.go b/sqlcore/ddl_test.go deleted file mode 100644 index 8a25c6a..0000000 --- a/sqlcore/ddl_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package sqlcore - -import ( - "flag" - "fmt" - "path/filepath" - "testing" - - "github.com/joho/godotenv" -) - - -func init() { - if flag.Lookup("test.v") == nil { - fmt.Println("normal run") - } else { - fmt.Println("run under go test") - } -} -func TestCreateSchema(t *testing.T){ - - err := godotenv.Load(filepath.Join("../", ".env.test")) - if err != nil { - t.Log("Error: ", err) - } - - x := []string{} - errMsg, status := DDL("CREATE SCHEMA ETHEREUM", "TEST", x) - if !status { - t.Log(errMsg) - t.Fail() - } - // want := 10 - - // if got != want { - // t.Errorf("got %q, wanted %q", got, want) - // } -} \ No newline at end of file diff --git a/sqlview/sqlview.go b/sqlview/sqlview.go deleted file mode 100644 index 5116753..0000000 --- a/sqlview/sqlview.go +++ /dev/null @@ -1,213 +0,0 @@ -package sqlview - -import ( - "bytes" - "encoding/json" - "io" - "net/http" - "net/url" - "os" - - "github.com/spaceandtimelabs/SxT-Go-SDK/helpers" -) - -type ParametersRequest struct { - Name string `json:"Name"` - Type string `json:"Type"` -} - -// Create sql view -// parameterRequest is optional -func Create(resourceId, viewName, viewText, description string, publish bool, parametersRequest []ParametersRequest) (output, errMsg string, status bool) { - tokenEndPoint := helpers.GetSqlEndpoint("views") - - re, r := helpers.CheckUpperCaseResource(resourceId) - if !r { - return "", re, r - } - - var postBody []byte - if len(parametersRequest) > 0 { - pr, _ := json.Marshal(parametersRequest) - - postBody, _ = json.Marshal(map[string]interface{}{ - "viewName": viewName, - "viewText": viewText, - "resourceId": resourceId, - "description": description, - "publish": publish, - "parametersRequest": string(pr), - }) - } else { - postBody, _ = json.Marshal(map[string]interface{}{ - "viewName": viewName, - "viewText": viewText, - "resourceId": resourceId, - "description": description, - "publish": publish, - }) - } - - client := http.Client{} - responseBody := bytes.NewBuffer(postBody) - - req, err := http.NewRequest("POST", tokenEndPoint, responseBody) - if err != nil { - return "", err.Error(), false - } - - req.Header.Add("Authorization", "Bearer "+os.Getenv("accessToken")) - req.Header.Add("Content-Type", "application/json") - req.Header.Add("Accept", "application/json") - - res, err := client.Do(req) - if err != nil { - return "", err.Error(), false - } - - defer res.Body.Close() - body, err := io.ReadAll(res.Body) - if err != nil { - return "", err.Error(), false - } - - if res.StatusCode != 201 { - return "", string(body), false - } - - return string(body), "", true -} - -// Execute a view -// parameterRequest is optional -func Execute(viewName string, parametersRequest []ParametersRequest) (errMsg string, status bool) { - tokenEndPoint := helpers.GetSqlEndpoint("views") + "/" + url.QueryEscape(viewName) - - paramString := "" - - if len(parametersRequest) > 0 { - for _, param := range parametersRequest { - paramString += param.Name + "=" + param.Type + "&" - } - paramString = paramString[:len(paramString)-1] - - tokenEndPoint += "?params=" + paramString - } - - client := http.Client{} - req, err := http.NewRequest("GET", tokenEndPoint, nil) - if err != nil { - return err.Error(), false - } - - req.Header.Add("Accept", "application/json") - req.Header.Add("Authorization", "Bearer "+os.Getenv("accessToken")) - - res, err := client.Do(req) - if err != nil { - return err.Error(), false - } - - defer res.Body.Close() - _, err = io.ReadAll(res.Body) - if err != nil { - return err.Error(), false - } - - return "", true -} - -// Update sql view -// parameterRequest is optional -func Update(resourceId, viewName, viewText, description string, publish bool, parametersRequest []ParametersRequest) (output, errMsg string, status bool) { - tokenEndPoint := helpers.GetSqlEndpoint("views") + "/" + viewName - - re, r := helpers.CheckUpperCaseResource(resourceId) - if !r { - return "", re, r - } - - var postBody []byte - if len(parametersRequest) > 0 { - pr, _ := json.Marshal(parametersRequest) - - postBody, _ = json.Marshal(map[string]interface{}{ - "viewName": viewName, - "viewText": viewText, - "resourceId": resourceId, - "description": description, - "publish": publish, - "parametersRequest": string(pr), - }) - } else { - postBody, _ = json.Marshal(map[string]interface{}{ - "viewName": viewName, - "viewText": viewText, - "resourceId": resourceId, - "description": description, - "publish": publish, - }) - } - - client := http.Client{} - responseBody := bytes.NewBuffer(postBody) - - req, err := http.NewRequest("PUT", tokenEndPoint, responseBody) - if err != nil { - return "", err.Error(), false - } - - req.Header.Add("Authorization", "Bearer "+os.Getenv("accessToken")) - req.Header.Add("Content-Type", "application/json") - req.Header.Add("Accept", "application/json") - - res, err := client.Do(req) - if err != nil { - return "", err.Error(), false - } - - defer res.Body.Close() - body, err := io.ReadAll(res.Body) - if err != nil { - return "", err.Error(), false - } - - if res.StatusCode != 204 { - return "", string(body), false - } - - return string(body), "", true -} - -// Delete sql view -// parameterRequest is optional -func Delete(viewName string) (output, errMsg string, status bool) { - tokenEndPoint := helpers.GetSqlEndpoint("views") + "/" + viewName - - client := http.Client{} - - req, err := http.NewRequest("DELETE", tokenEndPoint, nil) - if err != nil { - return "", err.Error(), false - } - - req.Header.Add("Authorization", "Bearer "+os.Getenv("accessToken")) - req.Header.Add("Accept", "application/json") - - res, err := client.Do(req) - if err != nil { - return "", err.Error(), false - } - - defer res.Body.Close() - body, err := io.ReadAll(res.Body) - if err != nil { - return "", err.Error(), false - } - - if res.StatusCode != 204 { - return "", string(body), false - } - - return string(body), "", true -} diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000..9fd6c69 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,275 @@ +package utils + +import ( + "crypto/ed25519" + "encoding/base64" + "encoding/json" + "errors" + "log" + + "github.com/spaceandtimelabs/SxT-Go-SDK/authentication" + "github.com/spaceandtimelabs/SxT-Go-SDK/authorization" + "github.com/spaceandtimelabs/SxT-Go-SDK/discovery" + "github.com/spaceandtimelabs/SxT-Go-SDK/helpers" + "github.com/spaceandtimelabs/SxT-Go-SDK/sqlcore" + "github.com/spaceandtimelabs/SxT-Go-SDK/storage" +) + +// New Authentication. +// This method generates new accessToken, refreshToken, privateKey, and publicKey +func Authenticate(inputUserId, inputPublicKey, inputPrivateKey string) ( accessToken, refreshToken string, privateKey ed25519.PrivateKey, publicKey ed25519.PublicKey, err error) { + + /************************************* + // AUTHENTICATION APIS + *************************************/ + + userId, _ := helpers.ReadUserId() + joinCode, _ := helpers.ReadJoinCode() + + var pubkey ed25519.PublicKey + var privkey ed25519.PrivateKey + var e error + + var authCodeStruct authentication.AuthCodeStruct + var tokenStruct authentication.TokenStruct + var sessionStruct storage.FileSessionStruct + var sessionStatus bool + + if inputUserId != "" && inputPublicKey != "" && inputPrivateKey != "" { + pubkey, e = base64.StdEncoding.DecodeString(inputPublicKey) + if e != nil { + log.Fatal("base64 std encoded public key expected") + return "", "", nil, nil, errors.New("base64 std encoded public key expected") + } + + privkey, e = base64.StdEncoding.DecodeString(inputPrivateKey) + if e != nil { + log.Fatal("base64 std encoded private key expected") + return "", "", nil, nil, errors.New("base64 std encoded private key expected") + } + + // Key compatibility + if len(privkey) == len(pubkey) { + var tmpPvtKey []byte + for idx := range privkey { + tmpPvtKey = append(tmpPvtKey, privkey[idx]) + } + + for idx := range pubkey { + tmpPvtKey = append(tmpPvtKey, pubkey[idx]) + } + privkey = tmpPvtKey + } + + userId = inputUserId + } else { + sessionStruct, sessionStatus = storage.FileReadSession(userId) + + if !sessionStatus { + // Generate Private and Public keys + pubkey, privkey = helpers.CreateKey() + } else { + pubkey = sessionStruct.PublicKey + privkey = sessionStruct.PrivateKey + } + } + + // Get auth code + authCode := authentication.GenerateAuthCode(userId, joinCode) + json.Unmarshal([]byte(authCode), &authCodeStruct) + + // Get Keys + encodedSignature, base64PublicKey := authentication.GenerateKeys(authCodeStruct.AuthCode, pubkey, privkey) + + // Get Token + tokenJson := authentication.GenerateToken(userId, authCodeStruct.AuthCode, encodedSignature, base64PublicKey) + json.Unmarshal([]byte(tokenJson), &tokenStruct) + + // fmt.Println(userId, tokenStruct.AccessToken, tokenStruct.RefreshToken, privkey, pubkey) + + writeStatus := storage.FileWriteSession(userId, tokenStruct.AccessToken, tokenStruct.RefreshToken, privkey, pubkey) + if !writeStatus { + // log.Fatal("Invalid login. Change login credentials") + return "", "", nil, nil, errors.New("invalid login. Change login credentials") + } + + // Logout + // authentication.Logout() + return tokenStruct.AccessToken, tokenStruct.RefreshToken, privkey, publicKey, nil +} + +// SQL APIs +func SQLAPIs(privateKey ed25519.PrivateKey, publicKey ed25519.PublicKey) (err error){ + + var sxtBiscuitCapabilities []authorization.SxTBiscuitStruct + + /************************************* + // SXT Biscuit + *************************************/ + + // Operation values can include + /* + SQL operations: + DDL: for operating on database objects & schema (e.g. table, view) + ddl_create : SQL CREATE command + ddl_alter : SQL ALTER command + ddl_drop : SQL DROP command + + DML: for performing data manipulation + dml_insert : SQL INSERT command + dml_update : SQL UPDATE command + dml_merge : DQL MERGE command + dml_delete : SQL DELETE command + + DQL: for performing queries + dql_select : SQL SELECT command + + Kafka ICM operations: + kafka_icm_create : ICM create + kafka_icm_read : ICM read + kafka_icm_update : ICM update + kafka_icm_delete : ICM delete + + For wildcards, use *, like + authorization.SxTBiscuitStruct{Operation: "*", Resource: "eth.TESTTABLE106"} + + */ + sxtBiscuitCapabilities = append(sxtBiscuitCapabilities, authorization.SxTBiscuitStruct{Operation: "dql_select", Resource: "eth.testtable106"}) + sxtBiscuitCapabilities = append(sxtBiscuitCapabilities, authorization.SxTBiscuitStruct{Operation: "dml_insert", Resource: "eth.testtable106"}) + sxtBiscuitCapabilities = append(sxtBiscuitCapabilities, authorization.SxTBiscuitStruct{Operation: "dml_update", Resource: "eth.testtable106"}) + sxtBiscuitCapabilities = append(sxtBiscuitCapabilities, authorization.SxTBiscuitStruct{Operation: "dml_delete", Resource: "eth.testtable106"}) + sxtBiscuitCapabilities = append(sxtBiscuitCapabilities, authorization.SxTBiscuitStruct{Operation: "ddl_create", Resource: "eth.testtable106"}) + + biscuit, _ := authorization.CreateBiscuitToken(sxtBiscuitCapabilities, &privateKey) + + // Set some constant values + // Create multiple biscuits + mb := []string{biscuit} + originApp := "TEST" + + /************************************* + // SQL CORE + *************************************/ + + // DDL + // Create a new schema + // This wont work as ETH already exists. Write your own + errMsg, status := sqlcore.CreateSchema("CREATE SCHEMA ETH", originApp, mb) + if !status { + return errors.New(errMsg) + } + + // DDL + // Only for create queries + // For ALTER and DROP, use sqlcore.DDL() + sqlcore.CreateTable("CREATE TABLE ETH.TESTTABLE106 (id INT PRIMARY KEY, test VARCHAR)", "ALL", originApp, mb, publicKey) + if !status { + return errors.New(errMsg) + } + + // DML + // use the sqlcore.DML to write insert, update, delete, and merge queries + resources := []string{"ETH.TESTTABLE106"} + sqlcore.DML("insert into ETH.TESTTABLE106 values(5, 'x5')", originApp, mb, resources) + if !status { + return errors.New(errMsg) + } + + // DQL + // Select operations + // If rowCount is 0, then fetches all data without limit + _, errMsg, status = sqlcore.DQL("select * from ETH.TESTTABLE106", originApp, mb, resources, 0) + if !status { + return errors.New(errMsg) + } + + // DDL + // Only for ALTER and DROP queries + // For Create table queries, use sqlcore.CreateTable() + // For this to work, you will need to provide permissions in biscuit first + errMsg, status = sqlcore.DDL("DROP TABLE ETH.TESTTABLE106", originApp, mb ) + if !status { + return errors.New(errMsg) + } + + return nil +} + + +// Discovery APIs +func DiscoveryAPIs()(err error){ + + /************************************* + // DISCOVERY APIS + *************************************/ + + // List Schemas + _, errMsg, status := discovery.ListSchemas("ALL", "") + if !status { + return errors.New(errMsg) + } + + // List Tables in a given schema + // Possible scope values - + // 1. ALL = all resources, + // 2. PUBLIC = non-permissioned tables, + // 3. PRIVATE = tables created by the requesting user + // 4. SUBSCRIPTION = include all resources the requesting user can see + // Note: schema and table names are case sensitive. Upper cased + _, errMsg, status = discovery.ListTables("ETH", "ALL", "") + if !status { + return errors.New(errMsg) + } + + // List Columns for a given table in schema + // Note: schema and table names are case sensitive. Upper cased + _, errMsg, status = discovery.ListColumns("ETH", "TESTTABLE106") + if !status { + return errors.New(errMsg) + } + + // List table index for a given table in schema + // Note: schema and table names are case sensitive. Upper cased + _, errMsg, status = discovery.ListTableIndex("ETH", "TESTTABLE106") + if !status { + return errors.New(errMsg) + } + + // List table primary key for a given table in schema + // Note: schema and table names are case sensitive. Upper cased + _, errMsg, status = discovery.ListTablePrimaryKey("ETH", "TESTTABLE106") + if !status { + return errors.New(errMsg) + } + + // List table relations for a schema and scope + // Note: schema and table names are case sensitive. Upper cased + _, errMsg, status = discovery.ListTableRelations("ETH", "PRIVATE") + if !status { + return errors.New(errMsg) + } + + // List table primary key references for a table and a schema + // Note: schema and table names are case sensitive. Upper cased + _, errMsg, status = discovery.ListPrimaryKeyReferences("ETH", "TESTTABLE106", "TEST") + if !status { + return errors.New(errMsg) + } + + // List foreign key references for a table, column and a schema + // Note: schema and table names are case sensitive. Upper cased + _, errMsg, status = discovery.ListForeignKeyReferences("ETH", "TESTTABLE106", "TEST") + if !status { + return errors.New(errMsg) + } + + // List views for a view name for a owner + // Second parameter can be "", "true" or "false". It accepts a string and not a boolean + // Note: schema and table names are case sensitive. Upper cased + _, errMsg, status = discovery.ListViews("SOME_VIEW_NAME", "") + if !status { + return errors.New(errMsg) + } + + return nil +} \ No newline at end of file