diff --git a/README.md b/README.md index ed776041..f58fb755 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Core collection of Flogo contributions. This repository consists of activities, * [json](function/json): JSON * [number](function/number): Numbers * [string](function/string): Strings +* [crypto](function/crypto): Strings ## Installation diff --git a/function/crypto/aesDecrypt.go b/function/crypto/aesDecrypt.go new file mode 100644 index 00000000..fa6d8482 --- /dev/null +++ b/function/crypto/aesDecrypt.go @@ -0,0 +1,55 @@ +package crypto + +import ( + "fmt" + + "github.com/project-flogo/core/data" + "github.com/project-flogo/core/data/coerce" + "github.com/project-flogo/core/data/expression/function" +) + +func init() { + _ = function.Register(&aesDecryptFn{}) +} + +type aesDecryptFn struct { +} + +// Name returns the name of the function +func (aesDecryptFn) Name() string { + return "aesDecrypt" +} + +// Sig returns the function signature +func (aesDecryptFn) Sig() (paramTypes []data.Type, isVariadic bool) { + return []data.Type{data.TypeString, data.TypeString}, false +} + +// Eval executes the function +func (aesDecryptFn) Eval(params ...interface{}) (interface{}, error) { + + if logger.DebugEnabled() { + logger.Debugf("Entering function aesEncrypt ()") + } + + ciphertext, err := coerce.ToString(params[0]) + if err != nil { + return nil, fmt.Errorf("crypto.aesDecryptFn function first parameter [%+v] must be string", params[0]) + } + + key, err := coerce.ToString(params[1]) + if err != nil { + return nil, fmt.Errorf("crypto.aesDecryptFn function second parameter [%+v] must be string", params[1]) + } + + plaintext, err := aesDecrypt(ciphertext, []byte(key)) + if err != nil { + return nil, err + } + + if logger.DebugEnabled() { + logger.Debugf("Exiting function aesEncrypt (eval)") + } + + return string(plaintext), nil +} diff --git a/function/crypto/aesEncrypt.go b/function/crypto/aesEncrypt.go new file mode 100644 index 00000000..670b79c5 --- /dev/null +++ b/function/crypto/aesEncrypt.go @@ -0,0 +1,59 @@ +package crypto + +import ( + "fmt" + + "github.com/project-flogo/core/data" + "github.com/project-flogo/core/data/coerce" + "github.com/project-flogo/core/data/expression/function" + +) + +func init() { + _ = function.Register(&aesEncryptFn{}) +} + +type aesEncryptFn struct { +} + +// Name returns the name of the function +func (aesEncryptFn) Name() string { + return "aesEncrypt" +} + +// Sig returns the function signature +func (aesEncryptFn) Sig() (paramTypes []data.Type, isVariadic bool) { + return []data.Type{data.TypeString, data.TypeString}, false +} + +// Eval executes the function +func (aesEncryptFn) Eval(params ...interface{}) (interface{}, error) { + + + if logger.DebugEnabled() { + logger.Debugf("Entering function aesEncrypt ()") + } + + + plaintext, err := coerce.ToString(params[0]) + if err != nil { + return nil, fmt.Errorf("crypto.aesEncrypt function first parameter [%+v] must be string", params[0]) + } + + key, err := coerce.ToString(params[1]) + if err != nil { + return nil, fmt.Errorf("crypto.aesEncrypt function second parameter [%+v] must be string", params[1]) + } + + ciphertext, err := aesEncrypt([]byte(plaintext), []byte(key)) + if err != nil { + return nil, err + } + + + if logger.DebugEnabled() { + logger.Debugf("Exiting function aesEncrypt (eval)") + } + + return ciphertext, nil +} diff --git a/function/crypto/crypto.go b/function/crypto/crypto.go new file mode 100644 index 00000000..8cd6bf3d --- /dev/null +++ b/function/crypto/crypto.go @@ -0,0 +1,216 @@ +package crypto + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/sha512" + "crypto/x509" + "encoding/base64" + "encoding/hex" + "encoding/pem" + "errors" + "fmt" + "io" + + "github.com/project-flogo/core/support/log" +) + +var logger = log.RootLogger() + +// aesEncrypt encrypts data using AES (Advanced Encryption Standard) in Cipher Block Chaining (CBC) mode. +// It generates a random initialization vector (IV) and appends it to the ciphertext. +// The resulting ciphertext is then base64 encoded and returned as a string. +// +// Parameters: +// - data: A byte slice containing the data to be encrypted. +// - aesKey: A byte slice containing the AES key used for encryption. The key must be 16, 24, or 32 bytes long. +// +// Returns: +// - A string representing the base64 encoded AES-encrypted data. +// - An error if the AES key is invalid or if any other encryption error occurs. +func aesEncrypt(data []byte, aesKey []byte) (string, error) { + block, err := aes.NewCipher(aesKey) + if err != nil { + return "", err + } + ciphertext := make([]byte, aes.BlockSize+len(data)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return "", err + } + + stream := cipher.NewCFBEncrypter(block, iv) + stream.XORKeyStream(ciphertext[aes.BlockSize:], data) + + return base64.StdEncoding.EncodeToString(ciphertext), nil +} + + + + +// aesDecrypt decrypts a base64 encoded AES-encrypted data using the provided AES key. +// +// The function takes a base64 encoded string and a byte slice representing the AES key as input. +// It first decodes the base64 encoded string into a byte slice. +// Then, it creates a new cipher block using the provided AES key. +// If the length of the decoded data is less than the AES block size, it returns an error indicating that the ciphertext is too short. +// The initial vector (IV) is extracted from the beginning of the decoded data.//+ +// The remaining decoded data is then decrypted using the CFB (Cipher Feedback) mode of operation with the AES cipher block and IV. +// Finally, the decrypted data is returned as a byte slice.//+ +// +// Parameters: +// - data: A string representing the base64 encoded AES-encrypted data.//+ +// - aesKey: A byte slice containing the AES key used for decryption.//+ +// +// Returns: +// - A byte slice representing the decrypted data.//+ +// - An error if the AES key is invalid, the ciphertext is too short, or any other decryption error occurs.//+ +func aesDecrypt(data string, aesKey []byte) ([]byte, error) { + decoded, _ := base64.StdEncoding.DecodeString(data) + + block, err := aes.NewCipher(aesKey) + if err != nil { + return nil, err + } + + if len(decoded) < aes.BlockSize { + return nil, errors.New("ciphertext too short") + } + iv := decoded[:aes.BlockSize] + decoded = decoded[aes.BlockSize:] + + stream := cipher.NewCFBDecrypter(block, iv) + + stream.XORKeyStream(decoded, decoded) + + return []byte(fmt.Sprintf("%s", decoded)), nil +} + + + +// hmacValue generates a SHA512 HMAC (Hash-based Message Authentication Code) for the provided data using the given HMAC key. +// The HMAC is then encoded to base64 and returned as a string. +// +// This function uses the SHA512 hash function from the crypto/sha512 package and the HMAC function from the crypto/hmac package. +// The HMAC key is truncated to the length required by the SHA512 hash function (64 bytes). +// +// Parameters: +// - data: A byte slice containing the data for which the HMAC needs to be generated. +// - hmacKey: A byte slice containing the HMAC key used for authentication. +// +// Returns: +// - A string representing the base64 encoded SHA512 HMAC of the provided data. +func hmacValue(data []byte, hmacKey []byte) string { + h512 := hmac.New(sha512.New, hmacKey[:]) + io.WriteString(h512, string(data)) + hexDigest := fmt.Sprintf("%x", h512.Sum(nil)) + return base64.StdEncoding.EncodeToString([]byte(hexDigest)) +} + + +// Checksum generates a SHA256 checksum of the provided data and returns it as a hexadecimal string. +// +// The SHA256 algorithm is a cryptographic hash function that produces a 256-bit (32-byte) hash value. +// It is widely used for data integrity verification, such as checking if a file has been tampered with. +// +// Parameters: +// - data: A byte slice containing the data for which the checksum needs to be generated. +// +// Returns: +// - A string representing the SHA256 checksum of the provided data in hexadecimal format. +func checksum(data []byte) string { + h := sha256.New() + h.Write(data) + return hex.EncodeToString(h.Sum(nil)) +} + +// rsaEncrypt encrypts data using the provided RSA public key. +// It uses the RSAES-PKCS1-v1_5 encryption scheme from the RSA Cryptography +// Standard (PKCS#1) and returns the encrypted data as a byte slice. +// +// Parameters: +// - data: A byte slice containing the data to be encrypted. +// - publicKey: A byte slice containing the RSA public key in PEM format. +// +// Returns: +// - A byte slice representing the encrypted data. +// - An error if the public key is invalid or if the encryption process fails. +func rsaEncrypt(data []byte, publicKey []byte) ([]byte, error) { + block, _ := pem.Decode(publicKey) + if block == nil { + return nil, errors.New("Public Key Error") + } + + pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, err + } + pub := pubInterface.(*rsa.PublicKey) + return rsa.EncryptPKCS1v15(rand.Reader, pub, data) +} + + +// rsaDecrypt decrypts data using the provided RSA private key. +// It uses the RSAES-PKCS1-v1_5 encryption scheme from the RSA Cryptography +// Standard (PKCS#1) and returns the decrypted data as a byte slice. +// +// Parameters: +// - ciphertext: A byte slice containing the encrypted data to be decrypted. +// - privateKey: A byte slice containing the RSA private key in PEM format. +// +// Returns: +// - A byte slice representing the decrypted data. +// - An error if the private key is invalid or if the decryption process fails. +func rsaDecrypt(ciphertext []byte, privateKey []byte) ([]byte, error) { + block, _ := pem.Decode(privateKey) + if block == nil { + return nil, errors.New("Private Key Error") + } + priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext) +} + + + +// encodeBase64 encodes a byte slice to a base64 encoded string. +// +// This function takes a byte slice as input and uses the standard base64 encoding provided by the Go standard library. +// It returns the base64 encoded string. +// +// Parameters: +// - data: A byte slice containing the data to be encoded. +// +// Returns: +// - A string representing the base64 encoded data. +func encodeBase64(data []byte) string { + res := base64.StdEncoding.EncodeToString(data) + return res +} + + + +// decodeBase64 decodes a base64 encoded string to a byte slice. +// +// This function takes a base64 encoded string as input and uses the standard base64 decoding provided by the Go standard library. +// It returns the decoded byte slice and an error if any occurred during the decoding process. +// +// Parameters: +// - data: A string representing the base64 encoded data to be decoded. +// +// Returns: +// - A byte slice representing the decoded data. +// - An error if the decoding process fails. +func decodeBase64(data string) ([]byte, error) { + res, err := base64.StdEncoding.DecodeString(data) + if err != nil { + return nil, err + } + return res, nil +} diff --git a/function/crypto/crypto_test.go b/function/crypto/crypto_test.go new file mode 100644 index 00000000..6a7f0229 --- /dev/null +++ b/function/crypto/crypto_test.go @@ -0,0 +1,80 @@ +package crypto + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + key = "1234543444555666" + plaintext = "Hello, World!" + encryptedData = "g6Fj2gAwOKX9QpLyER/5yhLh8it7sw8wxOrlFe2o/AHDd+N/HequAMJXA2Pau2CwhXB68rRvoWmwZaukNK5L2zp3RWbUxd+UDaFroA==" + rsaEncryptedData = "nKVVuCY7bPzNvfCx+NCa/3QYiliinc2Jhuvf7ZQTc87ZvcDOWiQwvXfkicLLv9WqqjmvzxWGTqxeJvN9Gw9SzRUAadgeQapS4VRR5VoTYsIEs8ye9yyyWzeAf6tp1bsj6GclE3MozPYcC4GMeeyGsrVb1JReNboUxZYOYd5wdqAwwG9MJtaq7pO2rFE7vkP3TGBlP53DzjAttFTilGV/2IbvyRmGUZsuyrKc4nJt+wvzPUVulzMcnqD9wRBPkAJ66SnxK/floYeCLt7U006om+xr19R+JKjLtzO9SDy8YNsv5++jUYhKcjfcts3BSExqO+HhJ5inswr9uRsOvJrvPg==" + pubKey = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsGPLhjbq7qy4IP7C6g5S +698/QLgIcXhBsQ6ZbvjmVBkLE+gh4AImMUjtvcTL/783snb4irWvFlJSzfwWmF8b +V0+swnaxf1rddlAWwE8KrBkIVXFWa/kTQ/ma6Tc3WY3/rJnb3c81Mf9guG9d7zHc +VjvjnQN/GrRn4KX/YVeLtqrih342HncfqKmGfyRgD/hwY/oHdD/sjOEEXBVe1Jqi +bHGAHFzoNbAmE9XsZ/QQ9pQuZl6+o6iLeV5satXYWVQffJEf6b4x3ptJ5Vc204ni +QXgIwNyaBBp98cH6zvBNlZcRb5pqFLEXCmeXkDF1rxharVR8rOUX5JB2w7+oQ5yc +lQIDAQAB +-----END PUBLIC KEY-----` + privateKey = `-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAsGPLhjbq7qy4IP7C6g5S698/QLgIcXhBsQ6ZbvjmVBkLE+gh +4AImMUjtvcTL/783snb4irWvFlJSzfwWmF8bV0+swnaxf1rddlAWwE8KrBkIVXFW +a/kTQ/ma6Tc3WY3/rJnb3c81Mf9guG9d7zHcVjvjnQN/GrRn4KX/YVeLtqrih342 +HncfqKmGfyRgD/hwY/oHdD/sjOEEXBVe1JqibHGAHFzoNbAmE9XsZ/QQ9pQuZl6+ +o6iLeV5satXYWVQffJEf6b4x3ptJ5Vc204niQXgIwNyaBBp98cH6zvBNlZcRb5pq +FLEXCmeXkDF1rxharVR8rOUX5JB2w7+oQ5yclQIDAQABAoIBABoi/3JoytEI+NOy +zFEARFs9HlNJsb6Wki1ZO3UNHpwRhemyOOrHhr9AzjGTaqL/w5IHPPbYyxPkqO5q +zzJOzW9XmALMsapsXWp9nZFrZOpxXyHCBItFQgyNfN3X17TGbL83oTOx03EQJVXO +8r1RxxNkFmsarIfZeZb5IelbnpE3a/FFQTVCr2feXPXAeAxsnDmOd8fp+zNpczGy +oLk8GSuGvzlFb95bBXqo/ZNQYzmSUpKE7hKChLDTHzYfWj1XGnN3UpDuYzjiKdec +p+HA57GjnP7HxD4HFrq0P8eRCOmk5tOn3ovaEkZxcJblH/QkgdxFCyAWJOy6v1SP +G9QOYqECgYEA41NBJ5d0KlFnh+ZA/eD4tBtmUbl1viRiPiyAVHnE/RQeCnII9x6Z +P5knxbKBTKWeZWDKcTOIFZO5x5mCf2o0j8hGN/ImMChHCsDACCDMBcMMAXQimjba +jk4DGmiEtGNDgJUzL9t+CIOAf7hQxRwnmbJoLEUOrjTUinVJdgoKw4kCgYEAxqO+ +dFmDiLBksPVhc4GSw8rQCxRLZ3HjpR/Lzy0TN20McoceDe9/MTJ2eAAvZepfJljR +GoxKxBqHq9LQNsb3EzVkgKy6MahEnw2kgizoegSYgrcumN03X/kUWvYSKpc32Nvp +81gACw9b9FM0vD7H/5GwaNbyF62Uv243Vt0Pca0CgYAwtBCcg+Vef6xXwGwiOIXw +SIKGdd6VC0SFH5GrB5+9vQampEHpeAPLTWvo/lKXclBaVf9pe2nnfYvrCKed1spG +F9l7eQTXgnmeAyfhVe2AOoai9RfIxIHUxUAC82ujHjVDIjQiR7tb5ZitRHcBlAOj ++UY6Xd1EU4tJ0tEXWhVuSQKBgQChdXtba18k/ev6gpnBn3LCPto4Bzj7TnFxSJUL +Q2I5TSQu+3EMdr12KcRt6gic2JKawtrEr4AeQkpA+cxQmg0+ycl1ZfC6aEHO3vH2 +9bXJaG7m4Sq5Cib2lalb/mPpxpyYYriZGdB/LO7be76DvKwoKi2wKfcCFA+yQk4t +BuaEyQKBgQDQS/GEcfk08JRXcGdvvfTbdzzI3LWUplyPwJsaHDzUJaK9Uv91nprN +77cETQt4A3XWAluzB/oLYG2yt8qgL/jXN9XHpQw8TSCoKZ2v0mDHF3U8pd47ilEi +yTqUmux0Hw4KbKKyDLKgk2haJZ45pB7tpQh6xClC4UNOYjGvDsv4mA== +-----END RSA PRIVATE KEY-----` +) + +var encAes = &aesEncryptFn{} +var decAes = &aesDecryptFn{} +var encRsa = &rsaEncryptFn{} +var decRsa = &rsaDecryptFn{} +var hmacSha512 = &hmacFn{} + +func TestAesEncryptDecrypt(t *testing.T) { + encryptedValue, _ := encAes.Eval(plaintext, key) + fmt.Println(encryptedValue) + decryptedValue, _ := decAes.Eval(encryptedValue, key) + fmt.Println(decryptedValue) + assert.Equal(t, plaintext, decryptedValue) + +} + +func TestRsaEncryptDecrypt(t *testing.T) { + encryptedValue, _ := encRsa.Eval(plaintext, pubKey) + fmt.Println(encryptedValue) + decryptedValue, _ := decRsa.Eval(encryptedValue, privateKey) + fmt.Println(decryptedValue) + assert.Equal(t, plaintext, decryptedValue) + +} + +func TestHmacSha512(t *testing.T) { + hash, _ := hmacSha512.Eval(plaintext, pubKey) + fmt.Println(hash) +} diff --git a/function/crypto/descriptor.json b/function/crypto/descriptor.json new file mode 100644 index 00000000..09f43078 --- /dev/null +++ b/function/crypto/descriptor.json @@ -0,0 +1,130 @@ +{ + "name": "crypto", + "type": "flogo:function", + "version": "0.0.1a", + "title": "crypto", + "author": "Mark Mussett", + "description": "Provides cryptographic functionality for Flogo", + "functions": [ + { + "name": "hmac", + "description": "Generate a HMAC-SHA", + "example": "crypto.hmac(\"Hello, World!\",\"-----BEGIN PUBLIC KEY-----\") => \"9FznkZO1UM3oYl+Gpac0lii/+a/4o9rTLlCInfA=\"", + "args": [ + { + "name": "string", + "type": "string", + "description": "The string to generate the HMAC-SHA" + }, + { + "name": "key", + "type": "string", + "description": "The encryption key" + } + ], + "return": { + "name": "hmac", + "type": "string" + }, + "display": { + "visible": true + } + }, + { + "name": "aesEncrypt", + "description": "Encrypt a string using AES encryption", + "example": "crypto.aesEncrypt(\"Hello, World!\",\"1234543444555666\") => \"9FznkZO1UM3oYl+Gpac0lii/+a/4o9rTLlCInfA=\"", + "args": [ + { + "name": "plainText", + "type": "string", + "description": "The string to be encrypted" + }, + { + "name": "key", + "type": "string", + "description": "The encryption key" + } + ], + "return": { + "name": "cipherText", + "type": "string" + }, + "display": { + "visible": true + } + }, + { + "name": "aesDecrypt", + "description": "Decrypt a string using AES decryption", + "example": "crypto.aesDecrypt(\"9FznkZO1UM3oYl+Gpac0lii/+a/4o9rTLlCInfA=\",\"1234543444555666\") => \"Hello, World!\"", + "args": [ + { + "name": "cipherText", + "type": "string", + "description": "The string to be decrypted" + }, + { + "name": "key", + "type": "string", + "description": "The decryption key" + } + ], + "return": { + "name": "plainText", + "type": "string" + }, + "display": { + "visible": true + } + }, + { + "name": "rsaEncrypt", + "description": "Encrypt a string using RSA encryption", + "example": "crypto.rsaEncrypt()", + "args": [ + { + "name": "plainText", + "type": "string", + "description": "The string to be encrypted" + }, + { + "name": "publicKey", + "type": "string", + "description": "The encryption key" + } + ], + "return": { + "name": "cipherText", + "type": "string" + }, + "display": { + "visible": true + } + }, + { + "name": "rsaDecrypt", + "description": "Decrypt a string using RSA decryption", + "example": "crypto.rsaDecrypt()", + "args": [ + { + "name": "cipherText", + "type": "string", + "description": "The string to be decrypted" + }, + { + "name": "privateKey", + "type": "string", + "description": "The decryption key" + } + ], + "return": { + "name": "plainText", + "type": "string" + }, + "display": { + "visible": true + } + } + ] +} diff --git a/function/crypto/go.mod b/function/crypto/go.mod new file mode 100644 index 00000000..a588cd81 --- /dev/null +++ b/function/crypto/go.mod @@ -0,0 +1,18 @@ +module github.com/mmussett/flogo-extensions/crypto + +go 1.23.2 + +require ( + github.com/project-flogo/core v1.6.11 + github.com/stretchr/testify v1.9.0 +) + +require ( + github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.uber.org/atomic v1.6.0 // indirect + go.uber.org/multierr v1.5.0 // indirect + go.uber.org/zap v1.16.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/function/crypto/go.sum b/function/crypto/go.sum new file mode 100644 index 00000000..9c82037d --- /dev/null +++ b/function/crypto/go.sum @@ -0,0 +1,63 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195 h1:c4mLfegoDw6OhSJXTd2jUEQgZUQuJWtocudb97Qn9EM= +github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/project-flogo/core v1.6.11 h1:weM2YJOx+kCtbGasw5wdcNHoBCHATRXcRNmIyUD8rSw= +github.com/project-flogo/core v1.6.11/go.mod h1:gKJsSjm/+uczBquIBEvdR4bXn8S2az2kW6uvKvDLxUE= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/function/crypto/hmac.go b/function/crypto/hmac.go new file mode 100644 index 00000000..5d753075 --- /dev/null +++ b/function/crypto/hmac.go @@ -0,0 +1,54 @@ +package crypto + +import ( + "fmt" + + "github.com/project-flogo/core/data" + "github.com/project-flogo/core/data/coerce" + "github.com/project-flogo/core/data/expression/function" +) + +func init() { + _ = function.Register(&hmacFn{}) +} + +type hmacFn struct { +} + +// Name returns the name of the function +func (hmacFn) Name() string { + return "hmac" +} + +// Sig returns the function signature +func (hmacFn) Sig() (paramTypes []data.Type, isVariadic bool) { + return []data.Type{data.TypeString,data.TypeString}, false +} + +// Eval executes the function +func (hmacFn) Eval(params ...interface{}) (interface{}, error) { + + if logger.DebugEnabled() { + logger.Debugf("Entering function hmac(eval)") + } + + value, err := coerce.ToString(params[0]) + if err != nil { + return nil, fmt.Errorf("crypto.hmacFn function first parameter [%+v] must be string", params[0]) + } + + key, err := coerce.ToString(params[1]) + if err != nil { + return nil, fmt.Errorf("crypto.hmacFn function second parameter [%+v] must be string", params[1]) + } + + + hmac := hmacValue([]byte(value), []byte(key)) + + + if logger.DebugEnabled() { + logger.Debugf("Exiting function hmac(eval)") + } + + return hmac, nil +} diff --git a/function/crypto/rsaDecrypt.go b/function/crypto/rsaDecrypt.go new file mode 100644 index 00000000..2cd73033 --- /dev/null +++ b/function/crypto/rsaDecrypt.go @@ -0,0 +1,60 @@ +package crypto + +import ( + "fmt" + + "github.com/project-flogo/core/data" + "github.com/project-flogo/core/data/coerce" + "github.com/project-flogo/core/data/expression/function" +) + +func init() { + _ = function.Register(&rsaDecryptFn{}) +} + +type rsaDecryptFn struct { +} + +// Name returns the name of the function +func (rsaDecryptFn) Name() string { + return "rsaDecrypt" +} + +// Sig returns the function signature +func (rsaDecryptFn) Sig() (paramTypes []data.Type, isVariadic bool) { + return []data.Type{data.TypeString, data.TypeString}, false +} + +// Eval executes the function +func (rsaDecryptFn) Eval(params ...interface{}) (interface{}, error) { + + if logger.DebugEnabled() { + logger.Debugf("Entering function rsaDecrypt ()") + } + + ciphertextAsBase64, err := coerce.ToString(params[0]) + if err != nil { + return nil, fmt.Errorf("crypto.rsaDecrypt function first parameter [%+v] must be string", params[0]) + } + + key, err := coerce.ToString(params[1]) + if err != nil { + return nil, fmt.Errorf("crypto.rsaDecrypt function second parameter [%+v] must be string", params[1]) + } + + ciphertext, err := decodeBase64(ciphertextAsBase64) + if err!= nil { + return nil, err + } + + plaintext, err := rsaDecrypt(ciphertext, []byte(key)) + if err != nil { + return nil, err + } + + if logger.DebugEnabled() { + logger.Debugf("Exiting function rsaDecrypt()") + } + + return string(plaintext), nil +} diff --git a/function/crypto/rsaEncrypt.go b/function/crypto/rsaEncrypt.go new file mode 100644 index 00000000..218df391 --- /dev/null +++ b/function/crypto/rsaEncrypt.go @@ -0,0 +1,58 @@ +package crypto + +import ( + "fmt" + + "github.com/project-flogo/core/data" + "github.com/project-flogo/core/data/coerce" + "github.com/project-flogo/core/data/expression/function" +) + +func init() { + _ = function.Register(&rsaEncryptFn{}) +} + +type rsaEncryptFn struct { +} + +// Name returns the name of the function +func (rsaEncryptFn) Name() string { + return "rsaEncrypt" +} + +// Sig returns the function signature +func (rsaEncryptFn) Sig() (paramTypes []data.Type, isVariadic bool) { + return []data.Type{data.TypeString, data.TypeString}, false +} + +// Eval executes the function +func (rsaEncryptFn) Eval(params ...interface{}) (interface{}, error) { + + if logger.DebugEnabled() { + logger.Debugf("Entering function aesEncrypt()") + } + + plaintext, err := coerce.ToString(params[0]) + if err != nil { + return nil, fmt.Errorf("crypto.rsaEncrypt function first parameter [%+v] must be string", params[0]) + } + + key, err := coerce.ToString(params[1]) + if err != nil { + return nil, fmt.Errorf("crypto.rsaEncrypt function second parameter [%+v] must be string", params[1]) + } + + + ciphertext, err := rsaEncrypt([]byte(plaintext), []byte(key)) + if err != nil { + return nil, err + } + + if logger.DebugEnabled() { + logger.Debugf("Exiting function rsaEncrypt()") + } + + + encCiphertext := encodeBase64(ciphertext) + return encCiphertext, nil +} diff --git a/function/datetime/descriptor.json b/function/datetime/descriptor.json index 2a2d12b2..018f6e80 100755 --- a/function/datetime/descriptor.json +++ b/function/datetime/descriptor.json @@ -5,6 +5,19 @@ "title": "datetimeFunctions", "description": "datetimeFunctions", "functions": [ + { + "name": "timestamp", + "description": "Returns the time in milliseconds since the Unix epoch (Jan 1 1970 00:00:00)", + "example": "datetime.timestamp() => 1728752120000", + "args": [], + "return": { + "name": "timestamp", + "type": "string" + }, + "display": { + "visible": true + } + }, { "name": "add", "description": "Add the given number of years, months and days to the DateTime", diff --git a/function/datetime/timestamp.go b/function/datetime/timestamp.go new file mode 100644 index 00000000..b0e880e1 --- /dev/null +++ b/function/datetime/timestamp.go @@ -0,0 +1,33 @@ +package datetime + +import ( + "time" + + "github.com/project-flogo/core/data" + "github.com/project-flogo/core/data/expression/function" +) + +func init() { + _ = function.Register(&Timestamp{}) +} + +type Timestamp struct { +} + +// Name returns the name of the function +func (Timestamp) Name() string { + return "timestamp" +} + +// Sig returns the function signature +func (Timestamp) Sig() (paramTypes []data.Type, isVariadic bool) { + return []data.Type{}, false +} + +// Eval executes the function +func (Timestamp) Eval(params ...interface{}) (interface{}, error) { + + outputTimeInMillis := time.Now().UnixNano() / int64(time.Millisecond) + + return outputTimeInMillis, nil +} diff --git a/function/datetime/timestamp_test.go b/function/datetime/timestamp_test.go new file mode 100644 index 00000000..e48d5515 --- /dev/null +++ b/function/datetime/timestamp_test.go @@ -0,0 +1,23 @@ +package datetime + +import ( + "fmt" + "testing" + + "github.com/project-flogo/core/data/expression/function" + + "github.com/stretchr/testify/assert" +) + +func init() { + function.ResolveAliases() +} + +func TestGetTimestamp_Eval(t *testing.T) { + n := Timestamp{} + timestamp, err := n.Eval(nil) + fmt.Println(timestamp) + assert.Nil(t, err) + assert.NotNil(t, timestamp) + +}