From 7a695c239ee4f1a0af74c4a6b854bc81d958d70b Mon Sep 17 00:00:00 2001 From: Rajon Ahmed Date: Fri, 19 Jun 2026 13:12:27 +0800 Subject: [PATCH] upd: helper utility updated --- .../visible/service/helper/cipher/cipher.go | 729 ++++++++++++++++++ .../visible/service/helper/codec/codec.go | 627 +++++++++++++++ .../service/helper/datetime/datetime.go | 275 +++++++ .../service/helper/filesystem/filesystem.go | 692 +++++++++++++++++ essential/visible/service/helper/hash/hash.go | 511 ++++++++++++ essential/visible/service/helper/key/key.go | 345 +++++++++ essential/visible/service/helper/log/log.go | 219 ++++++ .../visible/service/helper/marker/marker.go | 421 ++++++++++ .../service/helper/progress/progress.go | 392 ++++++++++ .../service/helper/retriever/retriever.go | 410 ++++++++++ .../visible/service/helper/status/status.go | 81 ++ go.mod | 2 + go.sum | 2 + 13 files changed, 4706 insertions(+) create mode 100644 go.sum diff --git a/essential/visible/service/helper/cipher/cipher.go b/essential/visible/service/helper/cipher/cipher.go index e69de29..092fae1 100644 --- a/essential/visible/service/helper/cipher/cipher.go +++ b/essential/visible/service/helper/cipher/cipher.go @@ -0,0 +1,729 @@ +package cipher + +import ( + "bytes" + "crypto/aes" + cryptocipher "crypto/cipher" + "crypto/rand" + "crypto/sha256" + "encoding/json" + "errors" + "io" + "os" + "path/filepath" +) + +const ( + obrimCipherTypeEncryptStandard = "encrypt-standard" + obrimCipherTypeEncryptSalted = "encrypt-salted" + obrimCipherTypeDecryptStandard = "decrypt-standard" + obrimCipherTypeDecryptSalted = "decrypt-salted" + + obrimCipherAlgorithm = "AES-256" + + obrimCipherFormatSignature = "OBRIMCIPHER" + obrimCipherFormatVersion = "1" + + obrimCipherSaltLength = 32 + obrimCipherNonceLength = 12 + + ObrimCipherCodeSuccessEncryptStandard = "SUCCESS_ENCRYPT_STANDARD" + ObrimCipherCodeSuccessEncryptSalted = "SUCCESS_ENCRYPT_SALTED" + ObrimCipherCodeSuccessDecryptStandard = "SUCCESS_DECRYPT_STANDARD" + ObrimCipherCodeSuccessDecryptSalted = "SUCCESS_DECRYPT_SALTED" + + ObrimCipherCodeFailedInvalidType = "FAILED_INVALID_TYPE" + ObrimCipherCodeFailedInvalidConfig = "FAILED_INVALID_CONFIGURATION" + ObrimCipherCodeFailedInvalidKey = "FAILED_INVALID_KEY" + ObrimCipherCodeFailedInvalidInputPath = "FAILED_INVALID_INPUT_PATH" + ObrimCipherCodeFailedInvalidOutputPath = "FAILED_INVALID_OUTPUT_PATH" + ObrimCipherCodeFailedInputAccess = "FAILED_INPUT_ACCESS" + ObrimCipherCodeFailedOutputWrite = "FAILED_OUTPUT_WRITE" + ObrimCipherCodeFailedEncryption = "FAILED_ENCRYPTION" + ObrimCipherCodeFailedDecryption = "FAILED_DECRYPTION" + ObrimCipherCodeFailedSaltGeneration = "FAILED_SALT_GENERATION" + ObrimCipherCodeFailedSignatureValidation = "FAILED_SIGNATURE_VALIDATION" + ObrimCipherCodeFailedVersionValidation = "FAILED_VERSION_VALIDATION" + ObrimCipherCodeFailedSaltExtraction = "FAILED_SALT_EXTRACTION" + ObrimCipherCodeFailedPayloadExtraction = "FAILED_PAYLOAD_EXTRACTION" +) + +// ObrimCipherConfig defines utility configuration. +type ObrimCipherConfig struct { + Key string `json:"key"` + Input string `json:"input"` + Output string `json:"output"` +} + +// ObrimCipherResponse defines standardized utility response. +type ObrimCipherResponse struct { + Status bool `json:"status"` + Code string `json:"code"` + Payload map[string]any `json:"payload"` +} + +// obrimCipherHeader defines encrypted file metadata. +type obrimCipherHeader struct { + Signature string + Version string +} + +// ObrimCipher executes encryption and decryption workflows. +func ObrimCipher( + cipherType string, + config map[string]any, +) map[string]any { + if !obrimCipherValidateType(cipherType) { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedInvalidType, + nil, + ) + } + + if !obrimCipherValidateConfig(config) { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedInvalidConfig, + nil, + ) + } + + key := config["key"].(string) + + if !obrimCipherValidateKey(key) { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedInvalidKey, + nil, + ) + } + + inputPath, inputOk := obrimCipherResolvePath( + config["input"].(string), + ) + + if !inputOk { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedInvalidInputPath, + nil, + ) + } + + outputPath, outputOk := obrimCipherResolvePath( + config["output"].(string), + ) + + if !outputOk { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedInvalidOutputPath, + nil, + ) + } + + inputData, readErr := obrimCipherReadInput(inputPath) + if readErr != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedInputAccess, + nil, + ) + } + + switch cipherType { + case obrimCipherTypeEncryptStandard: + return obrimCipherEncryptStandard( + key, + inputPath, + outputPath, + inputData, + ) + + case obrimCipherTypeEncryptSalted: + return obrimCipherEncryptSalted( + key, + inputPath, + outputPath, + inputData, + ) + + case obrimCipherTypeDecryptStandard: + return obrimCipherDecryptStandard( + key, + inputPath, + outputPath, + inputData, + ) + + case obrimCipherTypeDecryptSalted: + return obrimCipherDecryptSalted( + key, + inputPath, + outputPath, + inputData, + ) + } + + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedInvalidType, + nil, + ) +} + +// obrimCipherValidateType validates operation type. +func obrimCipherValidateType(cipherType string) bool { + switch cipherType { + case obrimCipherTypeEncryptStandard: + return true + + case obrimCipherTypeEncryptSalted: + return true + + case obrimCipherTypeDecryptStandard: + return true + + case obrimCipherTypeDecryptSalted: + return true + + default: + return false + } +} + +// obrimCipherValidateConfig validates configuration. +func obrimCipherValidateConfig(config map[string]any) bool { + if config == nil { + return false + } + + keyValue, keyExists := config["key"] + if !keyExists { + return false + } + + inputValue, inputExists := config["input"] + if !inputExists { + return false + } + + outputValue, outputExists := config["output"] + if !outputExists { + return false + } + + key, keyOk := keyValue.(string) + if !keyOk || key == "" { + return false + } + + input, inputOk := inputValue.(string) + if !inputOk || input == "" { + return false + } + + output, outputOk := outputValue.(string) + if !outputOk || output == "" { + return false + } + + return true +} + +// obrimCipherValidateKey validates AES-256 key requirements. +func obrimCipherValidateKey(key string) bool { + return len([]byte(key)) == 32 +} + +// obrimCipherResolvePath resolves a path to absolute form. +func obrimCipherResolvePath(path string) (string, bool) { + resolvedPath, err := filepath.Abs(path) + if err != nil { + return "", false + } + + return resolvedPath, true +} + +// obrimCipherReadInput reads source file content. +func obrimCipherReadInput(path string) ([]byte, error) { + return os.ReadFile(path) +} + +// obrimCipherWriteOutput writes processed output safely. +func obrimCipherWriteOutput( + path string, + data []byte, +) error { + var directory = filepath.Dir(path) + + if err := os.MkdirAll(directory, 0755); err != nil { + return err + } + + var temporaryFile, createErr = os.CreateTemp( + directory, + ".obrim-cipher-*", + ) + + if createErr != nil { + return createErr + } + + var temporaryPath = temporaryFile.Name() + + defer func() { + _ = temporaryFile.Close() + }() + + if _, err := temporaryFile.Write(data); err != nil { + _ = os.Remove(temporaryPath) + return err + } + + if err := temporaryFile.Sync(); err != nil { + _ = os.Remove(temporaryPath) + return err + } + + if err := temporaryFile.Close(); err != nil { + _ = os.Remove(temporaryPath) + return err + } + + return os.Rename(temporaryPath, path) +} + +// obrimCipherBuildResponse builds standardized responses. +func obrimCipherBuildResponse( + status bool, + code string, + payload map[string]any, +) map[string]any { + return map[string]any{ + "status": status, + "code": code, + "payload": payload, + } +} + +// obrimCipherEncryptStandard encrypts data without salt metadata. +func obrimCipherEncryptStandard( + key string, + inputPath string, + outputPath string, + inputData []byte, +) map[string]any { + encryptedData, err := obrimCipherEncryptAES( + []byte(key), + inputData, + ) + + if err != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedEncryption, + nil, + ) + } + + if err := obrimCipherWriteOutput( + outputPath, + encryptedData, + ); err != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedOutputWrite, + nil, + ) + } + + return obrimCipherBuildResponse( + true, + ObrimCipherCodeSuccessEncryptStandard, + map[string]any{ + "operation": obrimCipherTypeEncryptStandard, + "algorithm": obrimCipherAlgorithm, + "inputPath": inputPath, + "outputPath": outputPath, + }, + ) +} + +// obrimCipherGenerateSalt generates a cryptographic salt. +func obrimCipherGenerateSalt() ([]byte, error) { + var salt = make([]byte, obrimCipherSaltLength) + + _, err := io.ReadFull(rand.Reader, salt) + + return salt, err +} + +// obrimCipherBuildHeader builds encrypted file header. +func obrimCipherBuildHeader() []byte { + var buffer bytes.Buffer + + buffer.WriteString(obrimCipherFormatSignature) + buffer.WriteByte(0) + + buffer.WriteString(obrimCipherFormatVersion) + buffer.WriteByte(0) + + return buffer.Bytes() +} + +// obrimCipherEncryptSalted encrypts data with embedded salt metadata. +func obrimCipherEncryptSalted( + key string, + inputPath string, + outputPath string, + inputData []byte, +) map[string]any { + salt, saltErr := obrimCipherGenerateSalt() + + if saltErr != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedSaltGeneration, + nil, + ) + } + + var derivedKey = sha256.Sum256( + append([]byte(key), salt...), + ) + + encryptedData, err := obrimCipherEncryptAES( + derivedKey[:], + inputData, + ) + + if err != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedEncryption, + nil, + ) + } + + var header = obrimCipherBuildHeader() + + var outputData []byte + outputData = append(outputData, header...) + outputData = append(outputData, salt...) + outputData = append(outputData, encryptedData...) + + if err := obrimCipherWriteOutput( + outputPath, + outputData, + ); err != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedOutputWrite, + nil, + ) + } + + return obrimCipherBuildResponse( + true, + ObrimCipherCodeSuccessEncryptSalted, + map[string]any{ + "operation": obrimCipherTypeEncryptSalted, + "algorithm": obrimCipherAlgorithm, + "format": obrimCipherFormatSignature, + "version": obrimCipherFormatVersion, + "inputPath": inputPath, + "outputPath": outputPath, + }, + ) +} + +// obrimCipherDecryptStandard decrypts AES-256 encrypted data. +func obrimCipherDecryptStandard( + key string, + inputPath string, + outputPath string, + inputData []byte, +) map[string]any { + decryptedData, err := obrimCipherDecryptAES( + []byte(key), + inputData, + ) + + if err != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedDecryption, + nil, + ) + } + + if err := obrimCipherWriteOutput( + outputPath, + decryptedData, + ); err != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedOutputWrite, + nil, + ) + } + + return obrimCipherBuildResponse( + true, + ObrimCipherCodeSuccessDecryptStandard, + map[string]any{ + "operation": obrimCipherTypeDecryptStandard, + "algorithm": obrimCipherAlgorithm, + "inputPath": inputPath, + "outputPath": outputPath, + }, + ) +} + +// obrimCipherParseHeader parses encrypted metadata. +func obrimCipherParseHeader( + data []byte, +) (obrimCipherHeader, int, error) { + var signatureBytes = []byte(obrimCipherFormatSignature) + + if len(data) < len(signatureBytes)+1 { + return obrimCipherHeader{}, 0, errors.New("signature") + } + + if !bytes.Equal( + data[:len(signatureBytes)], + signatureBytes, + ) { + return obrimCipherHeader{}, 0, errors.New("signature") + } + + var offset = len(signatureBytes) + + if data[offset] != 0 { + return obrimCipherHeader{}, 0, errors.New("signature") + } + + offset++ + + var versionBytes = []byte(obrimCipherFormatVersion) + + if len(data) < offset+len(versionBytes)+1 { + return obrimCipherHeader{}, 0, errors.New("version") + } + + if !bytes.Equal( + data[offset:offset+len(versionBytes)], + versionBytes, + ) { + return obrimCipherHeader{}, 0, errors.New("version") + } + + offset += len(versionBytes) + + if data[offset] != 0 { + return obrimCipherHeader{}, 0, errors.New("version") + } + + offset++ + + return obrimCipherHeader{ + Signature: obrimCipherFormatSignature, + Version: obrimCipherFormatVersion, + }, offset, nil +} + +// obrimCipherExtractSalt extracts embedded salt. +func obrimCipherExtractSalt( + data []byte, + offset int, +) ([]byte, error) { + if len(data) < offset+obrimCipherSaltLength { + return nil, errors.New("salt") + } + + return data[offset : offset+obrimCipherSaltLength], nil +} + +// obrimCipherExtractPayload extracts encrypted payload. +func obrimCipherExtractPayload( + data []byte, + offset int, +) ([]byte, error) { + var payloadOffset = offset + obrimCipherSaltLength + + if len(data) <= payloadOffset { + return nil, errors.New("payload") + } + + return data[payloadOffset:], nil +} + +// obrimCipherDecryptSalted decrypts AES-256 encrypted data using extracted salt. +func obrimCipherDecryptSalted( + key string, + inputPath string, + outputPath string, + inputData []byte, +) map[string]any { + header, offset, headerErr := obrimCipherParseHeader( + inputData, + ) + + if headerErr != nil { + if headerErr.Error() == "signature" { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedSignatureValidation, + nil, + ) + } + + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedVersionValidation, + nil, + ) + } + + salt, saltErr := obrimCipherExtractSalt( + inputData, + offset, + ) + + if saltErr != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedSaltExtraction, + nil, + ) + } + + payload, payloadErr := obrimCipherExtractPayload( + inputData, + offset, + ) + + if payloadErr != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedPayloadExtraction, + nil, + ) + } + + var derivedKey = sha256.Sum256( + append([]byte(key), salt...), + ) + + decryptedData, decryptErr := obrimCipherDecryptAES( + derivedKey[:], + payload, + ) + + if decryptErr != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedDecryption, + nil, + ) + } + + if err := obrimCipherWriteOutput( + outputPath, + decryptedData, + ); err != nil { + return obrimCipherBuildResponse( + false, + ObrimCipherCodeFailedOutputWrite, + nil, + ) + } + + return obrimCipherBuildResponse( + true, + ObrimCipherCodeSuccessDecryptSalted, + map[string]any{ + "operation": obrimCipherTypeDecryptSalted, + "algorithm": obrimCipherAlgorithm, + "format": header.Signature, + "version": header.Version, + "inputPath": inputPath, + "outputPath": outputPath, + }, + ) +} + +// obrimCipherEncryptAES performs AES-256 encryption. +func obrimCipherEncryptAES( + key []byte, + data []byte, +) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cryptocipher.NewGCM(block) + if err != nil { + return nil, err + } + + var nonce = make([]byte, obrimCipherNonceLength) + + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + + var encryptedData = gcm.Seal( + nil, + nonce, + data, + nil, + ) + + var result []byte + result = append(result, nonce...) + result = append(result, encryptedData...) + + return result, nil +} + +// obrimCipherDecryptAES performs AES-256 decryption. +func obrimCipherDecryptAES( + key []byte, + data []byte, +) ([]byte, error) { + if len(data) < obrimCipherNonceLength { + return nil, errors.New("invalid payload") + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cryptocipher.NewGCM(block) + if err != nil { + return nil, err + } + + var nonce = data[:obrimCipherNonceLength] + var payload = data[obrimCipherNonceLength:] + + return gcm.Open( + nil, + nonce, + payload, + nil, + ) +} + +// obrimCipherMarshalResponse marshals response data. +func obrimCipherMarshalResponse( + response ObrimCipherResponse, +) ([]byte, error) { + return json.Marshal(response) +} diff --git a/essential/visible/service/helper/codec/codec.go b/essential/visible/service/helper/codec/codec.go index e69de29..c04a96a 100644 --- a/essential/visible/service/helper/codec/codec.go +++ b/essential/visible/service/helper/codec/codec.go @@ -0,0 +1,627 @@ +package codec + +import ( + "encoding/base32" + "encoding/base64" + "encoding/hex" + "errors" + "fmt" + "math/big" + "strconv" + "strings" + + "github.com/sqids/sqids-go" +) + +const ( + obrimCodecTypeEncode = "encode" + obrimCodecTypeDecode = "decode" + + obrimCodecFormatBase8 = "base8" + obrimCodecFormatBase10 = "base10" + obrimCodecFormatBase16 = "base16" + obrimCodecFormatBase32 = "base32" + obrimCodecFormatBase64 = "base64" + obrimCodecFormatSqids = "sqids" + + obrimCodecCaseLower = "lower" + obrimCodecCaseUpper = "upper" + + ObrimCodecCodeSuccessEncode = "SUCCESS_ENCODE" + ObrimCodecCodeSuccessDecode = "SUCCESS_DECODE" + + ObrimCodecCodeFailedValidation = "FAILED_VALIDATION" + ObrimCodecCodeFailedUnsupportedType = "FAILED_UNSUPPORTED_TYPE" + ObrimCodecCodeFailedUnsupportedFormat = "FAILED_UNSUPPORTED_FORMAT" + ObrimCodecCodeFailedMissingConfiguration = "FAILED_MISSING_CONFIGURATION" + ObrimCodecCodeFailedInvalidConfiguration = "FAILED_INVALID_CONFIGURATION" + ObrimCodecCodeFailedOperation = "FAILED_OPERATION" +) + +// ObrimCodecResponse defines the standardized utility response. +type ObrimCodecResponse struct { + Status bool `json:"status"` + Code string `json:"code"` + Payload map[string]any `json:"payload"` +} + +// obrimCodecConfiguration stores validated codec configuration. +type obrimCodecConfiguration struct { + Format string + Data any + Charset string + Salt string + Case string + Length int +} + +// ObrimCodec validates configuration, dispatches codec operations, and returns structured results. +func ObrimCodec(codecType string, config map[string]any) map[string]any { + validatedConfig, code := obrimCodecValidation(codecType, config) + if code != "" { + return obrimCodecBuildResponse(false, code, nil) + } + + value, err := obrimCodecDispatch(codecType, validatedConfig) + if err != nil { + return obrimCodecBuildResponse( + false, + ObrimCodecCodeFailedOperation, + nil, + ) + } + + var successCode string + + switch codecType { + case obrimCodecTypeEncode: + successCode = ObrimCodecCodeSuccessEncode + + case obrimCodecTypeDecode: + successCode = ObrimCodecCodeSuccessDecode + } + + return obrimCodecBuildResponse( + true, + successCode, + map[string]any{ + "operation": codecType, + "format": validatedConfig.Format, + "value": value, + }, + ) +} + +// obrimCodecValidation validates required parameters, supported operations, formats, and parameter types. +func obrimCodecValidation( + codecType string, + config map[string]any, +) (*obrimCodecConfiguration, string) { + if config == nil { + return nil, ObrimCodecCodeFailedMissingConfiguration + } + + switch codecType { + case obrimCodecTypeEncode: + case obrimCodecTypeDecode: + default: + return nil, ObrimCodecCodeFailedUnsupportedType + } + + formatValue, exists := config["format"] + if !exists { + return nil, ObrimCodecCodeFailedMissingConfiguration + } + + format, ok := formatValue.(string) + if !ok || strings.TrimSpace(format) == "" { + return nil, ObrimCodecCodeFailedInvalidConfiguration + } + + switch format { + case obrimCodecFormatBase8: + case obrimCodecFormatBase10: + case obrimCodecFormatBase16: + case obrimCodecFormatBase32: + case obrimCodecFormatBase64: + case obrimCodecFormatSqids: + default: + return nil, ObrimCodecCodeFailedUnsupportedFormat + } + + dataValue, exists := config["data"] + if !exists { + return nil, ObrimCodecCodeFailedMissingConfiguration + } + + switch dataValue.(type) { + case string: + case []byte: + default: + return nil, ObrimCodecCodeFailedInvalidConfiguration + } + + charsetValue, exists := config["charset"] + if !exists { + return nil, ObrimCodecCodeFailedMissingConfiguration + } + + charset, ok := charsetValue.(string) + if !ok { + return nil, ObrimCodecCodeFailedInvalidConfiguration + } + + saltValue, exists := config["salt"] + if !exists { + return nil, ObrimCodecCodeFailedMissingConfiguration + } + + salt, ok := saltValue.(string) + if !ok { + return nil, ObrimCodecCodeFailedInvalidConfiguration + } + + var validatedConfig = &obrimCodecConfiguration{ + Format: format, + Data: dataValue, + Charset: charset, + Salt: salt, + } + + if format == obrimCodecFormatSqids { + lengthValue, exists := config["length"] + if !exists { + return nil, ObrimCodecCodeFailedMissingConfiguration + } + + switch value := lengthValue.(type) { + case int: + validatedConfig.Length = value + + case int8: + validatedConfig.Length = int(value) + + case int16: + validatedConfig.Length = int(value) + + case int32: + validatedConfig.Length = int(value) + + case int64: + validatedConfig.Length = int(value) + + case float64: + validatedConfig.Length = int(value) + + default: + return nil, ObrimCodecCodeFailedInvalidConfiguration + } + + if validatedConfig.Length < 0 { + return nil, ObrimCodecCodeFailedInvalidConfiguration + } + } else { + caseValue, exists := config["case"] + if !exists { + return nil, ObrimCodecCodeFailedMissingConfiguration + } + + caseRule, ok := caseValue.(string) + if !ok { + return nil, ObrimCodecCodeFailedInvalidConfiguration + } + + switch caseRule { + case obrimCodecCaseLower: + case obrimCodecCaseUpper: + default: + return nil, ObrimCodecCodeFailedInvalidConfiguration + } + + validatedConfig.Case = caseRule + } + + return validatedConfig, "" +} + +// obrimCodecDispatch routes validated requests to the appropriate codec implementation. +func obrimCodecDispatch( + codecType string, + config *obrimCodecConfiguration, +) (string, error) { + switch codecType { + case obrimCodecTypeEncode: + switch config.Format { + case obrimCodecFormatBase8: + return obrimCodecEncodeBase8(config) + + case obrimCodecFormatBase10: + return obrimCodecEncodeBase10(config) + + case obrimCodecFormatBase16: + return obrimCodecEncodeBase16(config) + + case obrimCodecFormatBase32: + return obrimCodecEncodeBase32(config) + + case obrimCodecFormatBase64: + return obrimCodecEncodeBase64(config) + + case obrimCodecFormatSqids: + return obrimCodecEncodeSqids(config) + } + + case obrimCodecTypeDecode: + switch config.Format { + case obrimCodecFormatBase8: + return obrimCodecDecodeBase8(config) + + case obrimCodecFormatBase10: + return obrimCodecDecodeBase10(config) + + case obrimCodecFormatBase16: + return obrimCodecDecodeBase16(config) + + case obrimCodecFormatBase32: + return obrimCodecDecodeBase32(config) + + case obrimCodecFormatBase64: + return obrimCodecDecodeBase64(config) + + case obrimCodecFormatSqids: + return obrimCodecDecodeSqids(config) + } + } + + return "", obrimCodecError("unsupported dispatch") +} + +// obrimCodecBuildResponse builds a standard response. +func obrimCodecBuildResponse( + status bool, + code string, + payload map[string]any, +) map[string]any { + return map[string]any{ + "status": status, + "code": code, + "payload": payload, + } +} + +// obrimCodecNormalizeInput converts supported input types into string form. +func obrimCodecNormalizeInput(data any) string { + switch value := data.(type) { + case string: + return value + + case []byte: + return string(value) + + default: + return "" + } +} + +// obrimCodecApplyTransform applies charset and salt transformations. +func obrimCodecApplyTransform( + value string, + charset string, + salt string, +) string { + return charset + salt + value +} + +// obrimCodecReverseTransform reverses charset and salt transformations. +func obrimCodecReverseTransform( + value string, + charset string, + salt string, +) string { + var prefix = charset + salt + + return strings.TrimPrefix(value, prefix) +} + +// obrimCodecApplyCase applies output casing. +func obrimCodecApplyCase( + value string, + caseRule string, +) string { + switch caseRule { + case obrimCodecCaseUpper: + return strings.ToUpper(value) + + default: + return strings.ToLower(value) + } +} + +// obrimCodecEncodeBase8 encodes data using Base8 encoding. +func obrimCodecEncodeBase8( + config *obrimCodecConfiguration, +) (string, error) { + var input = obrimCodecApplyTransform( + obrimCodecNormalizeInput(config.Data), + config.Charset, + config.Salt, + ) + + var builder strings.Builder + + for _, value := range []byte(input) { + builder.WriteString(fmt.Sprintf("%03o", value)) + } + + return obrimCodecApplyCase( + builder.String(), + config.Case, + ), nil +} + +// obrimCodecDecodeBase8 decodes Base8 encoded data. +func obrimCodecDecodeBase8( + config *obrimCodecConfiguration, +) (string, error) { + var input = strings.ToLower( + obrimCodecNormalizeInput(config.Data), + ) + + if len(input)%3 != 0 { + return "", obrimCodecError("invalid base8 data") + } + + var output []byte + + for index := 0; index < len(input); index += 3 { + value, err := strconv.ParseUint( + input[index:index+3], + 8, + 8, + ) + if err != nil { + return "", err + } + + output = append(output, byte(value)) + } + + return obrimCodecReverseTransform( + string(output), + config.Charset, + config.Salt, + ), nil +} + +// obrimCodecEncodeBase10 encodes data using Base10 encoding. +func obrimCodecEncodeBase10( + config *obrimCodecConfiguration, +) (string, error) { + var input = obrimCodecApplyTransform( + obrimCodecNormalizeInput(config.Data), + config.Charset, + config.Salt, + ) + + var value = new(big.Int).SetBytes([]byte(input)) + + return obrimCodecApplyCase( + value.Text(10), + config.Case, + ), nil +} + +// obrimCodecDecodeBase10 decodes Base10 encoded data. +func obrimCodecDecodeBase10( + config *obrimCodecConfiguration, +) (string, error) { + var value = new(big.Int) + + if _, ok := value.SetString( + obrimCodecNormalizeInput(config.Data), + 10, + ); !ok { + return "", obrimCodecError("invalid base10 data") + } + + return obrimCodecReverseTransform( + string(value.Bytes()), + config.Charset, + config.Salt, + ), nil +} + +// obrimCodecEncodeBase16 encodes data using Base16 encoding. +func obrimCodecEncodeBase16( + config *obrimCodecConfiguration, +) (string, error) { + var input = obrimCodecApplyTransform( + obrimCodecNormalizeInput(config.Data), + config.Charset, + config.Salt, + ) + + var output = hex.EncodeToString([]byte(input)) + + return obrimCodecApplyCase( + output, + config.Case, + ), nil +} + +// obrimCodecDecodeBase16 decodes Base16 encoded data. +func obrimCodecDecodeBase16( + config *obrimCodecConfiguration, +) (string, error) { + var output, err = hex.DecodeString( + obrimCodecNormalizeInput(config.Data), + ) + if err != nil { + return "", err + } + + return obrimCodecReverseTransform( + string(output), + config.Charset, + config.Salt, + ), nil +} + +// obrimCodecEncodeBase32 encodes data using Base32 encoding. +func obrimCodecEncodeBase32( + config *obrimCodecConfiguration, +) (string, error) { + var input = obrimCodecApplyTransform( + obrimCodecNormalizeInput(config.Data), + config.Charset, + config.Salt, + ) + + var output = base32.StdEncoding.EncodeToString( + []byte(input), + ) + + return obrimCodecApplyCase( + output, + config.Case, + ), nil +} + +// obrimCodecDecodeBase32 decodes Base32 encoded data. +func obrimCodecDecodeBase32( + config *obrimCodecConfiguration, +) (string, error) { + var output, err = base32.StdEncoding.DecodeString( + strings.ToUpper( + obrimCodecNormalizeInput(config.Data), + ), + ) + if err != nil { + return "", err + } + + return obrimCodecReverseTransform( + string(output), + config.Charset, + config.Salt, + ), nil +} + +// obrimCodecEncodeBase64 encodes data using Base64 encoding. +func obrimCodecEncodeBase64( + config *obrimCodecConfiguration, +) (string, error) { + var input = obrimCodecApplyTransform( + obrimCodecNormalizeInput(config.Data), + config.Charset, + config.Salt, + ) + + var output = base64.StdEncoding.EncodeToString( + []byte(input), + ) + + return obrimCodecApplyCase( + output, + config.Case, + ), nil +} + +// obrimCodecDecodeBase64 decodes Base64 encoded data. +func obrimCodecDecodeBase64( + config *obrimCodecConfiguration, +) (string, error) { + var output, err = base64.StdEncoding.DecodeString( + obrimCodecNormalizeInput(config.Data), + ) + if err != nil { + return "", err + } + + return obrimCodecReverseTransform( + string(output), + config.Charset, + config.Salt, + ), nil +} + +// obrimCodecEncodeSqids encodes data using Sqids encoding with minimum length enforcement. +func obrimCodecEncodeSqids( + config *obrimCodecConfiguration, +) (string, error) { + var input = obrimCodecApplyTransform( + obrimCodecNormalizeInput(config.Data), + config.Charset, + config.Salt, + ) + + var numbers = make([]uint64, 0, len(input)) + + for _, value := range []byte(input) { + numbers = append(numbers, uint64(value)) + } + + if len(numbers) == 0 { + return "", obrimCodecError("empty sqids input") + } + + var sqidsInstance, err = sqids.New( + sqids.Options{ + Alphabet: config.Charset, + MinLength: uint8(config.Length), + }, + ) + if err != nil { + return "", err + } + + return sqidsInstance.Encode(numbers) +} + +// obrimCodecDecodeSqids decodes Sqids encoded data using deterministic length validation. +func obrimCodecDecodeSqids( + config *obrimCodecConfiguration, +) (string, error) { + var sqidsInstance, err = sqids.New( + sqids.Options{ + Alphabet: config.Charset, + MinLength: uint8(config.Length), + }, + ) + if err != nil { + return "", err + } + + var numbers = sqidsInstance.Decode( + obrimCodecNormalizeInput(config.Data), + ) + + if len(numbers) == 0 { + return "", obrimCodecError( + "invalid or empty sqids data", + ) + } + + var output = make([]byte, 0, len(numbers)) + + for _, value := range numbers { + if value > 255 { + return "", obrimCodecError( + "decoded sqids value exceeds byte range", + ) + } + + output = append(output, byte(value)) + } + + return obrimCodecReverseTransform( + string(output), + config.Charset, + config.Salt, + ), nil +} + +// obrimCodecError formats internal errors. +func obrimCodecError(message string) error { + return errors.New(message) +} diff --git a/essential/visible/service/helper/datetime/datetime.go b/essential/visible/service/helper/datetime/datetime.go index e69de29..d4f4c45 100644 --- a/essential/visible/service/helper/datetime/datetime.go +++ b/essential/visible/service/helper/datetime/datetime.go @@ -0,0 +1,275 @@ +package datetime + +import ( + "encoding/binary" + "fmt" + "log" + "net" + "strconv" + "time" +) + +const ( + obrimDatetimeTypeLocal = "local" + obrimDatetimeTypeTrusted = "trusted" + + ObrimDatetimeCodeSuccessRetrieved = "SUCCESS_DATETIME_RETRIEVED" + + ObrimDatetimeCodeFailedInvalidType = "FAILED_INVALID_TYPE" + ObrimDatetimeCodeFailedInvalidFormat = "FAILED_INVALID_FORMAT" + ObrimDatetimeCodeFailedTrustedTimeRetrieval = "FAILED_TRUSTED_TIME_RETRIEVAL" +) + +const obrimDatetimeTrustedNtpPool = "pool.ntp.org:123" + +// ObrimDatetimePayload defines the success payload structure. +type ObrimDatetimePayload struct { + Value string `json:"value"` +} + +// ObrimDatetimeResponse defines the utility response structure. +type ObrimDatetimeResponse struct { + Status bool `json:"status"` + Code string `json:"code"` + Payload *ObrimDatetimePayload `json:"payload"` +} + +// obrimDatetimePatternMap stores framework-supported format mappings. +var obrimDatetimePatternMap = map[string]string{ + "yyyy-MM-dd": "2006-01-02", + "MMM dd, yyyy": "Jan 02, 2006", + "MMMM dd, yyyy": "January 02, 2006", + "EEE, MMM dd, yyyy": "Mon, Jan 02, 2006", + "EEE, MMMM dd, yyyy": "Mon, January 02, 2006", + "EEEE, MMM dd, yyyy": "Monday, Jan 02, 2006", + "EEEE, MMMM dd, yyyy": "Monday, January 02, 2006", + "HH:mm:ss": "15:04:05", + "hh:mm:ss a": "03:04:05 PM", + "yyyy-MM-dd HH:mm:ss": "2006-01-02 15:04:05", + "yyyy-MM-dd HH:mm:ss z": "2006-01-02 15:04:05 MST", + "yyyy-MM-dd'T'HH:mm:ssXXX": time.RFC3339, +} + +// ObrimDatetime retrieves and formats current date and time. +func ObrimDatetime( + datetimeType string, + config map[string]any, +) map[string]any { + log.Println("[datetime] initialization started") + + format, code := obrimDatetimeValidate(datetimeType, config) + if code != "" { + log.Printf("[datetime] validation failed: %s", code) + + return obrimDatetimeResponse( + false, + code, + "", + ) + } + + var datetimeValue time.Time + var err error + + switch datetimeType { + case obrimDatetimeTypeLocal: + datetimeValue = obrimDatetimeLocal() + + case obrimDatetimeTypeTrusted: + datetimeValue, err = obrimDatetimeTrusted() + if err != nil { + log.Printf( + "[datetime] trusted time retrieval failed: %v", + err, + ) + + return obrimDatetimeResponse( + false, + ObrimDatetimeCodeFailedTrustedTimeRetrieval, + "", + ) + } + } + + formattedValue := obrimDatetimeFormatApply( + datetimeValue, + format, + ) + + log.Println("[datetime] datetime retrieved successfully") + + return obrimDatetimeResponse( + true, + ObrimDatetimeCodeSuccessRetrieved, + formattedValue, + ) +} + +// obrimDatetimeValidate validates utility inputs. +func obrimDatetimeValidate( + datetimeType string, + config map[string]any, +) (string, string) { + switch datetimeType { + case obrimDatetimeTypeLocal: + case obrimDatetimeTypeTrusted: + default: + return "", ObrimDatetimeCodeFailedInvalidType + } + + formatValue, exists := config["format"] + if !exists { + return "", ObrimDatetimeCodeFailedInvalidFormat + } + + format, ok := formatValue.(string) + if !ok || format == "" { + return "", ObrimDatetimeCodeFailedInvalidFormat + } + + if !obrimDatetimePatternValidate(format) { + return "", ObrimDatetimeCodeFailedInvalidFormat + } + + return format, "" +} + +// obrimDatetimePatternValidate validates supported patterns. +func obrimDatetimePatternValidate(pattern string) bool { + switch pattern { + case "timestampsec": + return true + + case "timestampmil": + return true + } + + _, exists := obrimDatetimePatternMap[pattern] + + return exists +} + +// obrimDatetimePatternResolve resolves pattern mappings. +func obrimDatetimePatternResolve( + pattern string, +) (string, bool) { + layout, exists := obrimDatetimePatternMap[pattern] + + return layout, exists +} + +// obrimDatetimeFormatApply formats datetime values. +func obrimDatetimeFormatApply( + datetimeValue time.Time, + pattern string, +) string { + switch pattern { + case "timestampsec": + return strconv.FormatInt( + datetimeValue.Unix(), + 10, + ) + + case "timestampmil": + return strconv.FormatInt( + datetimeValue.UnixMilli(), + 10, + ) + } + + layout, _ := obrimDatetimePatternResolve(pattern) + + return datetimeValue.Format(layout) +} + +// obrimDatetimeResponse builds utility responses. +func obrimDatetimeResponse( + status bool, + code string, + value string, +) map[string]any { + if !status { + return map[string]any{ + "status": false, + "code": code, + "payload": nil, + } + } + + return map[string]any{ + "status": true, + "code": code, + "payload": map[string]any{ + "value": value, + }, + } +} + +// obrimDatetimeLocal retrieves host system time. +func obrimDatetimeLocal() time.Time { + return time.Now() +} + +// obrimDatetimeTrusted retrieves trusted NTP time. +func obrimDatetimeTrusted() (time.Time, error) { + return obrimDatetimeTrustedSync() +} + +// obrimDatetimeTrustedSync synchronizes trusted time from NTP. +func obrimDatetimeTrustedSync() (time.Time, error) { + connection, err := net.DialTimeout( + "udp", + obrimDatetimeTrustedNtpPool, + 5*time.Second, + ) + if err != nil { + return time.Time{}, err + } + + defer connection.Close() + + var request = make([]byte, 48) + + request[0] = 0x1B + + if _, err = connection.Write(request); err != nil { + return time.Time{}, err + } + + if err = connection.SetDeadline( + time.Now().Add(5 * time.Second), + ); err != nil { + return time.Time{}, err + } + + var response = make([]byte, 48) + + if _, err = connection.Read(response); err != nil { + return time.Time{}, err + } + + var ntpSeconds = binary.BigEndian.Uint32( + response[40:44], + ) + + var ntpFraction = binary.BigEndian.Uint32( + response[44:48], + ) + + const ntpEpochOffset = 2208988800 + + var unixSeconds = int64(ntpSeconds) - ntpEpochOffset + + var nanoseconds = (int64(ntpFraction) * 1e9) >> 32 + + if unixSeconds < 0 { + return time.Time{}, fmt.Errorf( + "invalid ntp timestamp", + ) + } + + return time.Unix( + unixSeconds, + nanoseconds, + ).UTC(), nil +} diff --git a/essential/visible/service/helper/filesystem/filesystem.go b/essential/visible/service/helper/filesystem/filesystem.go index e69de29..07a8b54 100644 --- a/essential/visible/service/helper/filesystem/filesystem.go +++ b/essential/visible/service/helper/filesystem/filesystem.go @@ -0,0 +1,692 @@ +package filesystem + +import ( + "os" + "os/user" + "path/filepath" + "sort" + "strconv" + "strings" + "time" +) + +const ( + obrimFilesystemTypeList = "list" + obrimFilesystemTypeCheck = "check" + obrimFilesystemTypeCreate = "create" + obrimFilesystemTypeDelete = "delete" + obrimFilesystemTypePermission = "permission" + + obrimFilesystemEntityFile = "file" + obrimFilesystemEntityDirectory = "directory" + + obrimFilesystemStrategyUser = "user" + obrimFilesystemStrategyCustom = "custom" + + obrimFilesystemModeRead = "read" + obrimFilesystemModeWrite = "write" + + obrimFilesystemCodeSuccessList = "SUCCESS_LIST" + obrimFilesystemCodeSuccessCheck = "SUCCESS_CHECK" + obrimFilesystemCodeSuccessCreate = "SUCCESS_CREATE" + obrimFilesystemCodeSuccessDelete = "SUCCESS_DELETE" + obrimFilesystemCodeSuccessPermission = "SUCCESS_PERMISSION" + + obrimFilesystemCodeFailedUnsupportedType = "FAILED_UNSUPPORTED_TYPE" + obrimFilesystemCodeFailedMissingConfig = "FAILED_MISSING_CONFIGURATION" + obrimFilesystemCodeFailedInvalidConfig = "FAILED_INVALID_CONFIGURATION" + obrimFilesystemCodeFailedUnsupportedConfig = "FAILED_UNSUPPORTED_CONFIGURATION" + obrimFilesystemCodeFailedPathResolution = "FAILED_PATH_RESOLUTION" + obrimFilesystemCodeFailedExecution = "FAILED_EXECUTION" + obrimFilesystemCodeFailedPermission = "FAILED_PERMISSION" + obrimFilesystemCodeFailedEntityNotFound = "FAILED_ENTITY_NOT_FOUND" + obrimFilesystemCodeFailedUnsupportedEntity = "FAILED_UNSUPPORTED_ENTITY" + obrimFilesystemCodeFailedInvalidPermission = "FAILED_INVALID_PERMISSION" +) + +var obrimFilesystemSupportedKeys = map[string]map[string]bool{ + obrimFilesystemTypeList: { + "entity": true, + "strategy": true, + "base": true, + "name": true, + "recursive": true, + "include_hidden": true, + "sort_by": true, + "sort_order": true, + "filter_pattern": true, + "follow_symlink": true, + "absolute_path": true, + }, + obrimFilesystemTypeCheck: { + "entity": true, + "strategy": true, + "base": true, + "name": true, + "readable": true, + "writable": true, + }, + obrimFilesystemTypeCreate: { + "entity": true, + "strategy": true, + "base": true, + "name": true, + "hidden": true, + }, + obrimFilesystemTypeDelete: { + "entity": true, + "strategy": true, + "base": true, + "name": true, + "recursive": true, + }, + obrimFilesystemTypePermission: { + "strategy": true, + "base": true, + "name": true, + "mode": true, + "permission": true, + }, +} + +// ObrimFilesystem executes filesystem operations. +func ObrimFilesystem(operationType string, config map[string]any) map[string]any { + if code := obrimFilesystemValidate(operationType, config); code != "" { + return map[string]any{ + "status": false, + "code": code, + "payload": nil, + } + } + + switch operationType { + case obrimFilesystemTypeList: + return obrimFilesystemList(config) + + case obrimFilesystemTypeCheck: + return obrimFilesystemCheck(config) + + case obrimFilesystemTypeCreate: + return obrimFilesystemCreate(config) + + case obrimFilesystemTypeDelete: + return obrimFilesystemDelete(config) + + case obrimFilesystemTypePermission: + return obrimFilesystemPermission(config) + } + + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedUnsupportedType, + "payload": nil, + } +} + +// obrimFilesystemValidate validates operation inputs. +func obrimFilesystemValidate(operationType string, config map[string]any) string { + if config == nil { + return obrimFilesystemCodeFailedMissingConfig + } + + if _, exists := obrimFilesystemSupportedKeys[operationType]; !exists { + return obrimFilesystemCodeFailedUnsupportedType + } + + for key := range config { + if !obrimFilesystemSupportedKeys[operationType][key] { + return obrimFilesystemCodeFailedUnsupportedConfig + } + } + + switch operationType { + case obrimFilesystemTypeCreate, + obrimFilesystemTypeDelete: + entity, _ := config["entity"].(string) + + if entity != obrimFilesystemEntityFile && + entity != obrimFilesystemEntityDirectory { + return obrimFilesystemCodeFailedUnsupportedEntity + } + } + + return "" +} + +// obrimFilesystemResolve resolves and normalizes paths. +func obrimFilesystemResolve(config map[string]any) (string, error) { + var basePath string + + strategy, _ := config["strategy"].(string) + + switch strategy { + case "", obrimFilesystemStrategyUser: + homePath, err := os.UserHomeDir() + if err != nil { + currentUser, userErr := user.Current() + if userErr != nil { + return "", err + } + + homePath = currentUser.HomeDir + } + + basePath = homePath + + case obrimFilesystemStrategyCustom: + basePath, _ = config["base"].(string) + + default: + return "", os.ErrInvalid + } + + name, _ := config["name"].(string) + + resolvedPath := filepath.Clean(filepath.Join(basePath, name)) + + return filepath.Abs(resolvedPath) +} + +// obrimFilesystemPayload builds standardized payloads. +func obrimFilesystemPayload(payload map[string]any) map[string]any { + return payload +} + +// obrimFilesystemEntityType determines entity type. +func obrimFilesystemEntityType(path string) string { + info, err := os.Stat(path) + if err != nil { + return "" + } + + if info.IsDir() { + return obrimFilesystemEntityDirectory + } + + return obrimFilesystemEntityFile +} + +// obrimFilesystemPermissionValidate validates permission values. +func obrimFilesystemPermissionValidate(permission string) bool { + if permission == "" { + return false + } + + _, err := strconv.ParseUint(permission, 8, 32) + + return err == nil +} + +// obrimFilesystemList executes listing operations. +func obrimFilesystemList(config map[string]any) map[string]any { + basePath, err := obrimFilesystemResolve(config) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedPathResolution, + "payload": nil, + } + } + + entries, err := obrimFilesystemListTraverse(basePath, config) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedExecution, + "payload": nil, + } + } + + entries = obrimFilesystemListFilter(entries, config) + obrimFilesystemListSort(entries, config) + + return map[string]any{ + "status": true, + "code": obrimFilesystemCodeSuccessList, + "payload": obrimFilesystemPayload(map[string]any{ + "entries": entries, + "total": len(entries), + "recursive": config["recursive"] == true, + "base_path": basePath, + }), + } +} + +// obrimFilesystemListTraverse traverses filesystem entities. +func obrimFilesystemListTraverse(basePath string, config map[string]any) ([]map[string]any, error) { + var entries []map[string]any + + recursive, _ := config["recursive"].(bool) + includeHidden, _ := config["include_hidden"].(bool) + absolutePath, _ := config["absolute_path"].(bool) + + walkFunction := func(path string, info os.FileInfo, walkErr error) error { + if walkErr != nil { + return walkErr + } + + if path == basePath { + return nil + } + + if !includeHidden && strings.HasPrefix(info.Name(), ".") { + if info.IsDir() { + return filepath.SkipDir + } + + return nil + } + + entryPath := path + + if !absolutePath { + entryPath = info.Name() + } + + entries = append(entries, map[string]any{ + "name": info.Name(), + "path": entryPath, + "entity": obrimFilesystemEntityType(path), + "size": info.Size(), + "modified": info.ModTime().UTC().Format(time.RFC3339), + }) + + if !recursive && info.IsDir() { + return filepath.SkipDir + } + + return nil + } + + err := filepath.Walk(basePath, walkFunction) + + return entries, err +} + +// obrimFilesystemListFilter filters listing results. +func obrimFilesystemListFilter(entries []map[string]any, config map[string]any) []map[string]any { + var filtered []map[string]any + + entity, _ := config["entity"].(string) + pattern, _ := config["filter_pattern"].(string) + + for _, entry := range entries { + if entity != "" && entry["entity"] != entity { + continue + } + + if pattern != "" { + matched, _ := filepath.Match(pattern, entry["name"].(string)) + + if !matched { + continue + } + } + + filtered = append(filtered, entry) + } + + return filtered +} + +// obrimFilesystemListSort sorts listing results. +func obrimFilesystemListSort(entries []map[string]any, config map[string]any) { + sortBy, _ := config["sort_by"].(string) + sortOrder, _ := config["sort_order"].(string) + + sort.Slice(entries, func(i, j int) bool { + var result bool + + switch sortBy { + case "size": + result = entries[i]["size"].(int64) < entries[j]["size"].(int64) + + case "modified": + result = entries[i]["modified"].(string) < entries[j]["modified"].(string) + + default: + result = entries[i]["name"].(string) < entries[j]["name"].(string) + } + + if sortOrder == "desc" { + return !result + } + + return result + }) +} + +// obrimFilesystemCheck executes validation operations. +func obrimFilesystemCheck(config map[string]any) map[string]any { + path, err := obrimFilesystemResolve(config) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedPathResolution, + "payload": nil, + } + } + + _, statErr := os.Stat(path) + + exists := statErr == nil + entity := "" + + if exists { + entity = obrimFilesystemEntityType(path) + } + + readable := false + writable := false + + if exists { + readable, writable = obrimFilesystemCheckAccess(path) + } + + return map[string]any{ + "status": true, + "code": obrimFilesystemCodeSuccessCheck, + "payload": map[string]any{ + "path": path, + "exists": exists, + "entity": entity, + "readable": readable, + "writable": writable, + }, + } +} + +// obrimFilesystemCheckAccess verifies accessibility. +func obrimFilesystemCheckAccess(path string) (bool, bool) { + readable := true + writable := true + + readFile, readErr := os.Open(path) + if readErr != nil { + readable = false + } else { + _ = readFile.Close() + } + + writeFile, writeErr := os.OpenFile(path, os.O_WRONLY, 0) + if writeErr != nil { + writable = false + } else { + _ = writeFile.Close() + } + + return readable, writable +} + +// obrimFilesystemCreate executes creation operations. +func obrimFilesystemCreate(config map[string]any) map[string]any { + entity := config["entity"].(string) + + switch entity { + case obrimFilesystemEntityFile: + return obrimFilesystemCreateFile(config) + + case obrimFilesystemEntityDirectory: + return obrimFilesystemCreateDirectory(config) + } + + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedUnsupportedEntity, + "payload": nil, + } +} + +// obrimFilesystemCreateFile creates a file. +func obrimFilesystemCreateFile(config map[string]any) map[string]any { + path, err := obrimFilesystemResolve(config) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedPathResolution, + "payload": nil, + } + } + + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedExecution, + "payload": nil, + } + } + + file, err := os.Create(path) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedExecution, + "payload": nil, + } + } + + _ = file.Close() + + return map[string]any{ + "status": true, + "code": obrimFilesystemCodeSuccessCreate, + "payload": map[string]any{ + "path": path, + "entity": obrimFilesystemEntityFile, + "hidden": config["hidden"] == true, + "created": true, + }, + } +} + +// obrimFilesystemCreateDirectory creates a directory. +func obrimFilesystemCreateDirectory(config map[string]any) map[string]any { + path, err := obrimFilesystemResolve(config) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedPathResolution, + "payload": nil, + } + } + + if err := os.MkdirAll(path, 0755); err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedExecution, + "payload": nil, + } + } + + return map[string]any{ + "status": true, + "code": obrimFilesystemCodeSuccessCreate, + "payload": map[string]any{ + "path": path, + "entity": obrimFilesystemEntityDirectory, + "hidden": config["hidden"] == true, + "created": true, + }, + } +} + +// obrimFilesystemDelete executes deletion operations. +func obrimFilesystemDelete(config map[string]any) map[string]any { + entity := config["entity"].(string) + + switch entity { + case obrimFilesystemEntityFile: + return obrimFilesystemDeleteFile(config) + + case obrimFilesystemEntityDirectory: + return obrimFilesystemDeleteDirectory(config) + } + + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedUnsupportedEntity, + "payload": nil, + } +} + +// obrimFilesystemDeleteFile deletes a file. +func obrimFilesystemDeleteFile(config map[string]any) map[string]any { + path, err := obrimFilesystemResolve(config) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedPathResolution, + "payload": nil, + } + } + + if err := os.Remove(path); err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedExecution, + "payload": nil, + } + } + + return map[string]any{ + "status": true, + "code": obrimFilesystemCodeSuccessDelete, + "payload": map[string]any{ + "path": path, + "entity": obrimFilesystemEntityFile, + "deleted": true, + }, + } +} + +// obrimFilesystemDeleteDirectory deletes a directory. +func obrimFilesystemDeleteDirectory(config map[string]any) map[string]any { + path, err := obrimFilesystemResolve(config) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedPathResolution, + "payload": nil, + } + } + + recursive, _ := config["recursive"].(bool) + + if recursive { + err = os.RemoveAll(path) + } else { + err = os.Remove(path) + } + + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedExecution, + "payload": nil, + } + } + + return map[string]any{ + "status": true, + "code": obrimFilesystemCodeSuccessDelete, + "payload": map[string]any{ + "path": path, + "entity": obrimFilesystemEntityDirectory, + "deleted": true, + }, + } +} + +// obrimFilesystemPermission executes permission operations. +func obrimFilesystemPermission(config map[string]any) map[string]any { + mode, _ := config["mode"].(string) + + switch mode { + case "", obrimFilesystemModeRead: + return obrimFilesystemPermissionRead(config) + + case obrimFilesystemModeWrite: + return obrimFilesystemPermissionWrite(config) + } + + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedInvalidConfig, + "payload": nil, + } +} + +// obrimFilesystemPermissionRead retrieves permissions. +func obrimFilesystemPermissionRead(config map[string]any) map[string]any { + path, err := obrimFilesystemResolve(config) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedPathResolution, + "payload": nil, + } + } + + info, err := os.Stat(path) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedEntityNotFound, + "payload": nil, + } + } + + return map[string]any{ + "status": true, + "code": obrimFilesystemCodeSuccessPermission, + "payload": map[string]any{ + "path": path, + "permission": info.Mode().Perm().String(), + "mode": obrimFilesystemModeRead, + "updated": false, + }, + } +} + +// obrimFilesystemPermissionWrite updates permissions. +func obrimFilesystemPermissionWrite(config map[string]any) map[string]any { + path, err := obrimFilesystemResolve(config) + if err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedPathResolution, + "payload": nil, + } + } + + permission, _ := config["permission"].(string) + + if !obrimFilesystemPermissionValidate(permission) { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedInvalidPermission, + "payload": nil, + } + } + + value, _ := strconv.ParseUint(permission, 8, 32) + + if err := os.Chmod(path, os.FileMode(value)); err != nil { + return map[string]any{ + "status": false, + "code": obrimFilesystemCodeFailedPermission, + "payload": nil, + } + } + + return map[string]any{ + "status": true, + "code": obrimFilesystemCodeSuccessPermission, + "payload": map[string]any{ + "path": path, + "permission": permission, + "mode": obrimFilesystemModeWrite, + "updated": true, + }, + } +} diff --git a/essential/visible/service/helper/hash/hash.go b/essential/visible/service/helper/hash/hash.go index e69de29..f79baec 100644 --- a/essential/visible/service/helper/hash/hash.go +++ b/essential/visible/service/helper/hash/hash.go @@ -0,0 +1,511 @@ +package hash + +import ( + "crypto/rand" + "crypto/sha256" + "crypto/sha512" + "encoding/hex" +) + +const ( + obrimHashTypeCalculate = "calculate" + obrimHashTypeCompare = "compare" + + obrimHashModeStandard = "standard" + obrimHashModeSalted = "salted" + + obrimHashAlgorithmSHA256 = "sha256" + obrimHashAlgorithmSHA512 = "sha512" + obrimHashAlgorithmSaltedSHA256 = "salted_sha256" + obrimHashAlgorithmSaltedSHA512 = "salted_sha512" + + ObrimHashCodeSuccessHashGenerated = "SUCCESS_HASH_GENERATED" + ObrimHashCodeSuccessHashCompared = "SUCCESS_HASH_COMPARED" + + ObrimHashCodeFailedUnsupportedType = "FAILED_UNSUPPORTED_TYPE" + ObrimHashCodeFailedUnsupportedMode = "FAILED_UNSUPPORTED_MODE" + ObrimHashCodeFailedUnsupportedAlgorithm = "FAILED_UNSUPPORTED_ALGORITHM" + ObrimHashCodeFailedUnsupportedConfigKey = "FAILED_UNSUPPORTED_CONFIG_KEY" + ObrimHashCodeFailedMissingMode = "FAILED_MISSING_MODE" + ObrimHashCodeFailedMissingAlgorithm = "FAILED_MISSING_ALGORITHM" + ObrimHashCodeFailedMissingValue = "FAILED_MISSING_VALUE" + ObrimHashCodeFailedMissingHash = "FAILED_MISSING_HASH" + ObrimHashCodeFailedMissingSalt = "FAILED_MISSING_SALT" + ObrimHashCodeFailedInvalidConfig = "FAILED_INVALID_CONFIGURATION" + ObrimHashCodeFailedSaltNotAllowed = "FAILED_SALT_NOT_ALLOWED" + ObrimHashCodeFailedHashGeneration = "FAILED_HASH_GENERATION" + ObrimHashCodeFailedSaltGeneration = "FAILED_SALT_GENERATION" +) + +// ObrimHashResponse defines the standard utility response. +type ObrimHashResponse struct { + Status bool `json:"status"` + Code string `json:"code"` + Payload any `json:"payload"` +} + +// ObrimHashConfig defines utility configuration. +type ObrimHashConfig struct { + Mode string + Algorithm string + Value string + Hash string + Salt string +} + +// ObrimHashCalculateStandardPayload defines calculate standard payload. +type ObrimHashCalculateStandardPayload struct { + Algorithm string `json:"algorithm"` + Hash string `json:"hash"` +} + +// ObrimHashCalculateSaltedPayload defines calculate salted payload. +type ObrimHashCalculateSaltedPayload struct { + Algorithm string `json:"algorithm"` + Hash string `json:"hash"` + Salt string `json:"salt"` +} + +// ObrimHashCompareStandardPayload defines compare standard payload. +type ObrimHashCompareStandardPayload struct { + Algorithm string `json:"algorithm"` + Matched bool `json:"matched"` + Hash string `json:"hash"` +} + +// ObrimHashCompareSaltedPayload defines compare salted payload. +type ObrimHashCompareSaltedPayload struct { + Algorithm string `json:"algorithm"` + Matched bool `json:"matched"` + Hash string `json:"hash"` + Salt string `json:"salt"` +} + +// obrimHashAllowedConfigKeys stores supported configuration keys. +var obrimHashAllowedConfigKeys = map[string]struct{}{ + "mode": {}, + "algorithm": {}, + "value": {}, + "hash": {}, + "salt": {}, +} + +// ObrimHash processes hash generation and verification requests. +func ObrimHash( + hashType string, + config map[string]any, +) map[string]any { + if !obrimHashValidateType(hashType) { + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedUnsupportedType, + ) + } + + hashConfig, errorCode := obrimHashValidateConfig( + hashType, + config, + ) + if errorCode != "" { + return obrimHashBuildErrorPayload(errorCode) + } + + if !obrimHashValidateMode(hashConfig.Mode) { + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedUnsupportedMode, + ) + } + + if !obrimHashValidateAlgorithm( + hashConfig.Mode, + hashConfig.Algorithm, + ) { + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedUnsupportedAlgorithm, + ) + } + + switch hashType { + case obrimHashTypeCalculate: + return obrimHashCalculate(hashConfig) + + case obrimHashTypeCompare: + return obrimHashCompare(hashConfig) + + default: + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedUnsupportedType, + ) + } +} + +// obrimHashValidateType validates operation type. +func obrimHashValidateType(hashType string) bool { + switch hashType { + case obrimHashTypeCalculate: + return true + + case obrimHashTypeCompare: + return true + + default: + return false + } +} + +// obrimHashValidateMode validates hashing mode. +func obrimHashValidateMode(mode string) bool { + switch mode { + case obrimHashModeStandard: + return true + + case obrimHashModeSalted: + return true + + default: + return false + } +} + +// obrimHashValidateAlgorithm validates hashing algorithm selection. +func obrimHashValidateAlgorithm( + mode string, + algorithm string, +) bool { + switch mode { + case obrimHashModeStandard: + switch algorithm { + case obrimHashAlgorithmSHA256: + return true + + case obrimHashAlgorithmSHA512: + return true + } + + case obrimHashModeSalted: + switch algorithm { + case obrimHashAlgorithmSaltedSHA256: + return true + + case obrimHashAlgorithmSaltedSHA512: + return true + } + } + + return false +} + +// obrimHashValidateConfig validates configuration keys and values. +func obrimHashValidateConfig( + hashType string, + config map[string]any, +) (ObrimHashConfig, string) { + var hashConfig ObrimHashConfig + + if config == nil { + return hashConfig, ObrimHashCodeFailedInvalidConfig + } + + for key := range config { + if _, exists := obrimHashAllowedConfigKeys[key]; !exists { + return hashConfig, ObrimHashCodeFailedUnsupportedConfigKey + } + } + + modeValue, ok := config["mode"].(string) + if !ok || modeValue == "" { + return hashConfig, ObrimHashCodeFailedMissingMode + } + + algorithmValue, ok := config["algorithm"].(string) + if !ok || algorithmValue == "" { + return hashConfig, ObrimHashCodeFailedMissingAlgorithm + } + + valueValue, ok := config["value"].(string) + if !ok || valueValue == "" { + return hashConfig, ObrimHashCodeFailedMissingValue + } + + hashConfig.Mode = modeValue + hashConfig.Algorithm = algorithmValue + hashConfig.Value = valueValue + + if hashValue, exists := config["hash"]; exists { + hashText, ok := hashValue.(string) + if !ok { + return hashConfig, ObrimHashCodeFailedInvalidConfig + } + + hashConfig.Hash = hashText + } + + if saltValue, exists := config["salt"]; exists { + saltText, ok := saltValue.(string) + if !ok { + return hashConfig, ObrimHashCodeFailedInvalidConfig + } + + hashConfig.Salt = saltText + } + + switch hashType { + case obrimHashTypeCalculate: + if hashConfig.Mode == obrimHashModeStandard && + hashConfig.Salt != "" { + return hashConfig, ObrimHashCodeFailedSaltNotAllowed + } + + case obrimHashTypeCompare: + if hashConfig.Hash == "" { + return hashConfig, ObrimHashCodeFailedMissingHash + } + + if hashConfig.Mode == obrimHashModeStandard && + hashConfig.Salt != "" { + return hashConfig, ObrimHashCodeFailedSaltNotAllowed + } + + if hashConfig.Mode == obrimHashModeSalted && + hashConfig.Salt == "" { + return hashConfig, ObrimHashCodeFailedMissingSalt + } + } + + return hashConfig, "" +} + +// obrimHashGenerateHash executes the selected hashing algorithm. +func obrimHashGenerateHash( + algorithm string, + value string, + salt string, +) (string, bool) { + switch algorithm { + case obrimHashAlgorithmSHA256: + sum := sha256.Sum256([]byte(value)) + return hex.EncodeToString(sum[:]), true + + case obrimHashAlgorithmSHA512: + sum := sha512.Sum512([]byte(value)) + return hex.EncodeToString(sum[:]), true + + case obrimHashAlgorithmSaltedSHA256: + sum := sha256.Sum256([]byte(value + salt)) + return hex.EncodeToString(sum[:]), true + + case obrimHashAlgorithmSaltedSHA512: + sum := sha512.Sum512([]byte(value + salt)) + return hex.EncodeToString(sum[:]), true + + default: + return "", false + } +} + +// obrimHashCalculate processes hash generation requests. +func obrimHashCalculate( + config ObrimHashConfig, +) map[string]any { + switch config.Mode { + case obrimHashModeStandard: + return obrimHashCalculateStandard(config) + + case obrimHashModeSalted: + return obrimHashCalculateSalted(config) + + default: + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedUnsupportedMode, + ) + } +} + +// obrimHashCalculateStandard generates a deterministic hash. +func obrimHashCalculateStandard( + config ObrimHashConfig, +) map[string]any { + hashValue, success := obrimHashGenerateHash( + config.Algorithm, + config.Value, + "", + ) + if !success { + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedHashGeneration, + ) + } + + payload := ObrimHashCalculateStandardPayload{ + Algorithm: config.Algorithm, + Hash: hashValue, + } + + return obrimHashBuildSuccessPayload( + ObrimHashCodeSuccessHashGenerated, + payload, + ) +} + +// obrimHashCalculateSalted generates a salted hash and salt pair. +func obrimHashCalculateSalted( + config ObrimHashConfig, +) map[string]any { + var activeSalt string + + activeSalt = config.Salt + + if activeSalt == "" { + generatedSalt, success := obrimHashGenerateSalt() + if !success { + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedSaltGeneration, + ) + } + + activeSalt = generatedSalt + } + + hashValue, success := obrimHashGenerateHash( + config.Algorithm, + config.Value, + activeSalt, + ) + if !success { + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedHashGeneration, + ) + } + + payload := ObrimHashCalculateSaltedPayload{ + Algorithm: config.Algorithm, + Hash: hashValue, + Salt: activeSalt, + } + + return obrimHashBuildSuccessPayload( + ObrimHashCodeSuccessHashGenerated, + payload, + ) +} + +// obrimHashGenerateSalt generates a cryptographically secure salt. +func obrimHashGenerateSalt() (string, bool) { + var saltBytes = make([]byte, 32) + + _, err := rand.Read(saltBytes) + if err != nil { + return "", false + } + + return hex.EncodeToString(saltBytes), true +} + +// obrimHashCompare processes hash verification requests. +func obrimHashCompare( + config ObrimHashConfig, +) map[string]any { + switch config.Mode { + case obrimHashModeStandard: + return obrimHashCompareStandard(config) + + case obrimHashModeSalted: + return obrimHashCompareSalted(config) + + default: + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedUnsupportedMode, + ) + } +} + +// obrimHashCompareStandard regenerates a standard hash for verification. +func obrimHashCompareStandard( + config ObrimHashConfig, +) map[string]any { + regeneratedHash, success := obrimHashGenerateHash( + config.Algorithm, + config.Value, + "", + ) + if !success { + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedHashGeneration, + ) + } + + payload := ObrimHashCompareStandardPayload{ + Algorithm: config.Algorithm, + Matched: obrimHashVerify( + regeneratedHash, + config.Hash, + ), + Hash: config.Hash, + } + + return obrimHashBuildSuccessPayload( + ObrimHashCodeSuccessHashCompared, + payload, + ) +} + +// obrimHashCompareSalted regenerates a salted hash for verification. +func obrimHashCompareSalted( + config ObrimHashConfig, +) map[string]any { + regeneratedHash, success := obrimHashGenerateHash( + config.Algorithm, + config.Value, + config.Salt, + ) + if !success { + return obrimHashBuildErrorPayload( + ObrimHashCodeFailedHashGeneration, + ) + } + + payload := ObrimHashCompareSaltedPayload{ + Algorithm: config.Algorithm, + Matched: obrimHashVerify( + regeneratedHash, + config.Hash, + ), + Hash: config.Hash, + Salt: config.Salt, + } + + return obrimHashBuildSuccessPayload( + ObrimHashCodeSuccessHashCompared, + payload, + ) +} + +// obrimHashVerify compares regenerated and supplied hash values. +func obrimHashVerify( + regeneratedHash string, + suppliedHash string, +) bool { + return regeneratedHash == suppliedHash +} + +// obrimHashBuildSuccessPayload constructs success response payloads. +func obrimHashBuildSuccessPayload( + code string, + payload any, +) map[string]any { + return map[string]any{ + "status": true, + "code": code, + "payload": payload, + } +} + +// obrimHashBuildErrorPayload constructs error response payloads. +func obrimHashBuildErrorPayload( + code string, +) map[string]any { + return map[string]any{ + "status": false, + "code": code, + "payload": nil, + } +} diff --git a/essential/visible/service/helper/key/key.go b/essential/visible/service/helper/key/key.go index e69de29..f77df41 100644 --- a/essential/visible/service/helper/key/key.go +++ b/essential/visible/service/helper/key/key.go @@ -0,0 +1,345 @@ +package key + +import ( + "crypto/aes" + "crypto/ed25519" + "crypto/rand" + "encoding/base64" + "strings" + "time" +) + +const ( + obrimKeyTypeSymmetric = "symmetric" + obrimKeyTypeAsymmetric = "asymmetric" + + obrimKeyAlgorithmAES = "aes" + obrimKeyAlgorithmECC = "ecc" + + obrimKeyCurveEdDSA = "eddsa" + + ObrimKeyCodeSuccessSymmetricGenerated = "SUCCESS_SYMMETRIC_KEY_GENERATED" + ObrimKeyCodeSuccessAsymmetricGenerated = "SUCCESS_ASYMMETRIC_KEY_GENERATED" + + ObrimKeyCodeFailedMissingType = "FAILED_MISSING_TYPE" + ObrimKeyCodeFailedInvalidType = "FAILED_INVALID_TYPE" + ObrimKeyCodeFailedUnsupportedType = "FAILED_UNSUPPORTED_TYPE" + ObrimKeyCodeFailedMissingConfig = "FAILED_MISSING_CONFIGURATION" + ObrimKeyCodeFailedInvalidConfig = "FAILED_INVALID_CONFIGURATION" + ObrimKeyCodeFailedUnsupportedField = "FAILED_UNSUPPORTED_CONFIGURATION_FIELD" + ObrimKeyCodeFailedMissingAlgorithm = "FAILED_MISSING_ALGORITHM" + ObrimKeyCodeFailedInvalidAlgorithm = "FAILED_INVALID_ALGORITHM" + ObrimKeyCodeFailedUnsupportedAlgorithm = "FAILED_UNSUPPORTED_ALGORITHM" + ObrimKeyCodeFailedMissingKeySize = "FAILED_MISSING_KEY_SIZE" + ObrimKeyCodeFailedInvalidKeySize = "FAILED_INVALID_KEY_SIZE" + ObrimKeyCodeFailedUnsupportedKeySize = "FAILED_UNSUPPORTED_KEY_SIZE" + ObrimKeyCodeFailedKeyGeneration = "FAILED_KEY_GENERATION" +) + +type ObrimKeyResponse struct { + Status bool `json:"status"` + Code string `json:"code"` + Payload map[string]any `json:"payload"` +} + +// obrimKeyAllowedSymmetricFields stores allowed symmetric configuration fields. +var obrimKeyAllowedSymmetricFields = map[string]struct{}{ + "algorithm": {}, + "key_size": {}, +} + +// obrimKeyAllowedAsymmetricFields stores allowed asymmetric configuration fields. +var obrimKeyAllowedAsymmetricFields = map[string]struct{}{ + "algorithm": {}, +} + +// ObrimKey dispatches key generation requests and orchestrates validation, generation, and response construction. +func ObrimKey(keyType string, config map[string]any) map[string]any { + normalizedType, errorResponse := obrimKeyValidate(keyType, config) + if errorResponse != nil { + return errorResponse + } + + return obrimKeyDispatch(normalizedType, config) +} + +// obrimKeyValidate validates common request structure and schema integrity. +func obrimKeyValidate( + keyType string, + config map[string]any, +) (string, map[string]any) { + if strings.TrimSpace(keyType) == "" { + return "", obrimKeyBuildError(ObrimKeyCodeFailedMissingType) + } + + if config == nil { + return "", obrimKeyBuildError(ObrimKeyCodeFailedMissingConfig) + } + + normalizedType := strings.ToLower(strings.TrimSpace(keyType)) + + switch normalizedType { + case obrimKeyTypeSymmetric: + if errorCode := obrimKeyValidateSymmetricConfig(config); errorCode != "" { + return "", obrimKeyBuildError(errorCode) + } + + case obrimKeyTypeAsymmetric: + if errorCode := obrimKeyValidateAsymmetricConfig(config); errorCode != "" { + return "", obrimKeyBuildError(errorCode) + } + + default: + return "", obrimKeyBuildError(ObrimKeyCodeFailedUnsupportedType) + } + + return normalizedType, nil +} + +// obrimKeyDispatch routes execution to the appropriate cryptographic workflow. +func obrimKeyDispatch( + keyType string, + config map[string]any, +) map[string]any { + switch keyType { + case obrimKeyTypeSymmetric: + return obrimKeyGenerateSymmetric(config) + + case obrimKeyTypeAsymmetric: + return obrimKeyGenerateAsymmetric(config) + + default: + return obrimKeyBuildError(ObrimKeyCodeFailedUnsupportedType) + } +} + +// obrimKeyValidateSymmetricConfig validates symmetric configuration values. +func obrimKeyValidateSymmetricConfig(config map[string]any) string { + for field := range config { + if _, exists := obrimKeyAllowedSymmetricFields[field]; !exists { + return ObrimKeyCodeFailedUnsupportedField + } + } + + algorithmValue, exists := config["algorithm"] + if !exists { + return ObrimKeyCodeFailedMissingAlgorithm + } + + algorithm, ok := algorithmValue.(string) + if !ok { + return ObrimKeyCodeFailedInvalidAlgorithm + } + + algorithm = strings.ToLower(strings.TrimSpace(algorithm)) + + if algorithm != obrimKeyAlgorithmAES { + return ObrimKeyCodeFailedUnsupportedAlgorithm + } + + keySizeValue, exists := config["key_size"] + if !exists { + return ObrimKeyCodeFailedMissingKeySize + } + + keySize, ok := obrimKeyNormalizeInteger(keySizeValue) + if !ok { + return ObrimKeyCodeFailedInvalidKeySize + } + + switch keySize { + case 128, 192, 256: + return "" + + default: + return ObrimKeyCodeFailedUnsupportedKeySize + } +} + +// obrimKeyValidateAsymmetricConfig validates asymmetric configuration values. +func obrimKeyValidateAsymmetricConfig(config map[string]any) string { + for field := range config { + if _, exists := obrimKeyAllowedAsymmetricFields[field]; !exists { + return ObrimKeyCodeFailedUnsupportedField + } + } + + algorithmValue, exists := config["algorithm"] + if !exists { + return ObrimKeyCodeFailedMissingAlgorithm + } + + algorithm, ok := algorithmValue.(string) + if !ok { + return ObrimKeyCodeFailedInvalidAlgorithm + } + + algorithm = strings.ToLower(strings.TrimSpace(algorithm)) + + if algorithm != obrimKeyAlgorithmECC { + return ObrimKeyCodeFailedUnsupportedAlgorithm + } + + return "" +} + +// obrimKeyGenerateSymmetric generates symmetric key material. +func obrimKeyGenerateSymmetric(config map[string]any) map[string]any { + normalizedConfig := obrimKeyNormalizeSymmetricConfig(config) + + payload, errorCode := obrimKeyGenerateAES(normalizedConfig) + if errorCode != "" { + return obrimKeyBuildError(errorCode) + } + + return obrimKeyBuildPayload( + ObrimKeyCodeSuccessSymmetricGenerated, + payload, + ) +} + +// obrimKeyGenerateAES generates AES key material. +func obrimKeyGenerateAES( + config map[string]any, +) (map[string]any, string) { + keySize := config["key_size"].(int) + + // obrimKeyMaterial stores generated AES key bytes. + var obrimKeyMaterial = make([]byte, keySize/8) + + if _, err := rand.Read(obrimKeyMaterial); err != nil { + return nil, ObrimKeyCodeFailedKeyGeneration + } + + if _, err := aes.NewCipher(obrimKeyMaterial); err != nil { + return nil, ObrimKeyCodeFailedKeyGeneration + } + + return map[string]any{ + "type": obrimKeyTypeSymmetric, + "algorithm": obrimKeyAlgorithmAES, + "key_size": keySize, + "key_material": base64.StdEncoding.EncodeToString(obrimKeyMaterial), + "generated_at": time.Now().UTC().Format(time.RFC3339), + }, "" +} + +// obrimKeyNormalizeSymmetricConfig normalizes symmetric configuration values. +func obrimKeyNormalizeSymmetricConfig( + config map[string]any, +) map[string]any { + keySize, _ := obrimKeyNormalizeInteger(config["key_size"]) + + return map[string]any{ + "algorithm": strings.ToLower( + strings.TrimSpace(config["algorithm"].(string)), + ), + "key_size": keySize, + } +} + +// obrimKeyGenerateAsymmetric generates asymmetric key material. +func obrimKeyGenerateAsymmetric(config map[string]any) map[string]any { + normalizedConfig := obrimKeyNormalizeAsymmetricConfig(config) + + payload, errorCode := obrimKeyGenerateECC(normalizedConfig) + if errorCode != "" { + return obrimKeyBuildError(errorCode) + } + + return obrimKeyBuildPayload( + ObrimKeyCodeSuccessAsymmetricGenerated, + payload, + ) +} + +// obrimKeyGenerateECC generates ECC key pair material. +func obrimKeyGenerateECC( + config map[string]any, +) (map[string]any, string) { + _ = config + + publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, ObrimKeyCodeFailedKeyGeneration + } + + return map[string]any{ + "type": obrimKeyTypeAsymmetric, + "algorithm": obrimKeyAlgorithmECC, + "curve": obrimKeyCurveEdDSA, + "public_key": base64.StdEncoding.EncodeToString(publicKey), + "private_key": base64.StdEncoding.EncodeToString(privateKey), + "generated_at": time.Now().UTC().Format(time.RFC3339), + }, "" +} + +// obrimKeyNormalizeAsymmetricConfig normalizes asymmetric configuration values. +func obrimKeyNormalizeAsymmetricConfig( + config map[string]any, +) map[string]any { + return map[string]any{ + "algorithm": strings.ToLower( + strings.TrimSpace(config["algorithm"].(string)), + ), + } +} + +// obrimKeyBuildPayload constructs standardized success payloads. +func obrimKeyBuildPayload( + code string, + payload map[string]any, +) map[string]any { + return map[string]any{ + "status": true, + "code": code, + "payload": payload, + } +} + +// obrimKeyBuildError constructs standardized error responses. +func obrimKeyBuildError(code string) map[string]any { + return map[string]any{ + "status": false, + "code": code, + "payload": nil, + } +} + +// obrimKeyNormalizeInteger normalizes integer values. +func obrimKeyNormalizeInteger(value any) (int, bool) { + switch normalizedValue := value.(type) { + case int: + return normalizedValue, true + + case int8: + return int(normalizedValue), true + + case int16: + return int(normalizedValue), true + + case int32: + return int(normalizedValue), true + + case int64: + return int(normalizedValue), true + + case uint: + return int(normalizedValue), true + + case uint8: + return int(normalizedValue), true + + case uint16: + return int(normalizedValue), true + + case uint32: + return int(normalizedValue), true + + case uint64: + return int(normalizedValue), true + + default: + return 0, false + } +} diff --git a/essential/visible/service/helper/log/log.go b/essential/visible/service/helper/log/log.go index e69de29..5b585ea 100644 --- a/essential/visible/service/helper/log/log.go +++ b/essential/visible/service/helper/log/log.go @@ -0,0 +1,219 @@ +package log + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "time" +) + +const ( + obrimLogSoftwareName = "softwarelower" + obrimLogFileExtension = ".log" +) + +// ObrimLog writes a structured log entry. +func ObrimLog(label string, message string) { + softwareName := obrimLogSoftwareNameResolve() + if softwareName == "" { + return + } + + entry := obrimLogEntryBuild( + obrimLogTimestampGenerate(), + label, + message, + ) + + filePath := obrimLogFileResolve(softwareName) + if filePath == "" { + return + } + + if err := obrimLogFileEnsure(filePath); err != nil { + return + } + + _ = obrimLogWrite(filePath, entry) +} + +// obrimLogSoftwareNameResolve resolves the software name from a local variable. +func obrimLogSoftwareNameResolve() string { + return strings.TrimSpace(obrimLogSoftwareName) +} + +// obrimLogTimestampGenerate generates deterministic timestamps. +func obrimLogTimestampGenerate() string { + return time.Now().UTC().Format(time.RFC3339) +} + +// obrimLogEntryBuild constructs formatted log entries. +func obrimLogEntryBuild( + timestamp string, + label string, + message string, +) string { + return fmt.Sprintf( + "[%s] [%s] %s\n", + strings.TrimSpace(timestamp), + strings.TrimSpace(label), + strings.TrimSpace(message), + ) +} + +// obrimLogDirectoryResolve resolves platform-specific log directory paths. +func obrimLogDirectoryResolve( + softwareName string, +) string { + switch runtime.GOOS { + case "linux": + return obrimLogDirectoryResolveLinux(softwareName) + + case "windows": + return obrimLogDirectoryResolveWindows(softwareName) + + case "darwin": + return obrimLogDirectoryResolveMacOS(softwareName) + + default: + return "" + } +} + +// obrimLogFileResolve resolves platform-specific log file paths. +func obrimLogFileResolve( + softwareName string, +) string { + directoryPath := obrimLogDirectoryResolve(softwareName) + if directoryPath == "" { + return "" + } + + return filepath.Join( + directoryPath, + softwareName+obrimLogFileExtension, + ) +} + +// obrimLogFileEnsure creates and verifies required log directories and files. +func obrimLogFileEnsure( + filePath string, +) error { + directoryPath := filepath.Dir(filePath) + + if err := os.MkdirAll(directoryPath, 0o755); err != nil { + return err + } + + file, err := os.OpenFile( + filePath, + os.O_CREATE, + 0o644, + ) + if err != nil { + return err + } + + return file.Close() +} + +// obrimLogWrite persists log entries to the filesystem. +func obrimLogWrite( + filePath string, + entry string, +) error { + file, err := os.OpenFile( + filePath, + os.O_APPEND|os.O_CREATE|os.O_WRONLY, + 0o644, + ) + if err != nil { + return err + } + + defer file.Close() + + _, err = file.WriteString(entry) + + return err +} + +// obrimLogDirectoryResolveLinux resolves Linux log directory paths. +func obrimLogDirectoryResolveLinux( + softwareName string, +) string { + // Mutable XDG state home environment variable. + var xdgStateHome = strings.TrimSpace( + os.Getenv("XDG_STATE_HOME"), + ) + + if xdgStateHome != "" { + return filepath.Join( + xdgStateHome, + "."+softwareName, + "logs", + ) + } + + // Mutable user home directory. + var homeDirectory string + + userHomeDirectory, err := os.UserHomeDir() + if err != nil { + return "" + } + + homeDirectory = userHomeDirectory + + return filepath.Join( + homeDirectory, + ".local", + "state", + "."+softwareName, + "logs", + ) +} + +// obrimLogDirectoryResolveWindows resolves Windows log directory paths. +func obrimLogDirectoryResolveWindows( + softwareName string, +) string { + // Mutable LOCALAPPDATA environment variable. + var localAppData = strings.TrimSpace( + os.Getenv("LOCALAPPDATA"), + ) + + if localAppData == "" { + return "" + } + + return filepath.Join( + localAppData, + softwareName, + "Logs", + ) +} + +// obrimLogDirectoryResolveMacOS resolves macOS log directory paths. +func obrimLogDirectoryResolveMacOS( + softwareName string, +) string { + // Mutable user home directory. + var homeDirectory string + + userHomeDirectory, err := os.UserHomeDir() + if err != nil { + return "" + } + + homeDirectory = userHomeDirectory + + return filepath.Join( + homeDirectory, + "Library", + "Logs", + "."+softwareName, + ) +} diff --git a/essential/visible/service/helper/marker/marker.go b/essential/visible/service/helper/marker/marker.go index e69de29..947f741 100644 --- a/essential/visible/service/helper/marker/marker.go +++ b/essential/visible/service/helper/marker/marker.go @@ -0,0 +1,421 @@ +package marker + +import ( + "crypto/rand" + "crypto/sha256" + "fmt" + "strings" + "time" +) + +const ( + obrimMarkerTypeTime = "time" + obrimMarkerTypeRandom = "random" + obrimMarkerTypeEncoded = "encoded" + + ObrimMarkerCodeSuccessTimeGenerated = "SUCCESS_TIME_GENERATED" + ObrimMarkerCodeSuccessRandomGenerated = "SUCCESS_RANDOM_GENERATED" + ObrimMarkerCodeSuccessEncodedGenerated = "SUCCESS_ENCODED_GENERATED" + + ObrimMarkerCodeFailedUnsupportedType = "FAILED_UNSUPPORTED_TYPE" + ObrimMarkerCodeFailedMissingConfig = "FAILED_MISSING_CONFIGURATION" + ObrimMarkerCodeFailedInvalidConfig = "FAILED_INVALID_CONFIGURATION" + ObrimMarkerCodeFailedGeneration = "FAILED_GENERATION" + ObrimMarkerCodeFailedValidation = "FAILED_VALIDATION" +) + +const ( + obrimMarkerDefaultRandomLength = 16 + obrimMarkerDefaultEncodedLength = 16 + obrimMarkerDefaultCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" +) + +// ObrimMarkerResponse defines the standardized utility response. +type ObrimMarkerResponse struct { + Status bool `json:"status"` + Code string `json:"code"` + Payload map[string]any `json:"payload"` +} + +// ObrimMarker routes marker generation requests and returns a standardized marker response. +func ObrimMarker(markerType string, config map[string]any) map[string]any { + obrimMarkerLog("initialization") + + if !obrimMarkerValidateType(markerType) { + obrimMarkerLog("failure") + + return obrimMarkerBuildResponse( + false, + ObrimMarkerCodeFailedUnsupportedType, + nil, + ) + } + + if config == nil { + config = map[string]any{} + } + + response := obrimMarkerRoute(markerType, config) + + if status, ok := response["status"].(bool); ok && status { + obrimMarkerLog("success") + } else { + obrimMarkerLog("failure") + } + + return response +} + +// obrimMarkerValidateType validates supported marker generation types. +func obrimMarkerValidateType(markerType string) bool { + switch strings.TrimSpace(markerType) { + case obrimMarkerTypeTime: + return true + + case obrimMarkerTypeRandom: + return true + + case obrimMarkerTypeEncoded: + return true + + default: + return false + } +} + +// obrimMarkerRoute routes execution to the selected marker generation workflow. +func obrimMarkerRoute( + markerType string, + config map[string]any, +) map[string]any { + switch markerType { + case obrimMarkerTypeTime: + return obrimMarkerTime(config) + + case obrimMarkerTypeRandom: + return obrimMarkerRandom(config) + + case obrimMarkerTypeEncoded: + return obrimMarkerEncoded(config) + + default: + return obrimMarkerBuildResponse( + false, + ObrimMarkerCodeFailedUnsupportedType, + nil, + ) + } +} + +// obrimMarkerBuildResponse builds standardized success and error responses. +func obrimMarkerBuildResponse( + status bool, + code string, + payload map[string]any, +) map[string]any { + return map[string]any{ + "status": status, + "code": code, + "payload": payload, + } +} + +// obrimMarkerTime generates time-based unique markers. +func obrimMarkerTime(config map[string]any) map[string]any { + epoch, instance, code := obrimMarkerValidateTime(config) + if code != "" { + return obrimMarkerBuildResponse(false, code, nil) + } + + marker, err := obrimMarkerTimeGenerate(epoch, instance) + if err != nil { + return obrimMarkerBuildResponse( + false, + ObrimMarkerCodeFailedGeneration, + nil, + ) + } + + return obrimMarkerBuildResponse( + true, + ObrimMarkerCodeSuccessTimeGenerated, + map[string]any{ + "marker": marker, + "epoch": epoch, + "instance": instance, + }, + ) +} + +// obrimMarkerValidateTime validates time marker configuration parameters. +func obrimMarkerValidateTime( + config map[string]any, +) (int64, string, string) { + epochValue, epochExists := config["epoch"] + instanceValue, instanceExists := config["instance"] + + if !epochExists { + return 0, "", ObrimMarkerCodeFailedMissingConfig + } + + if !instanceExists { + return 0, "", ObrimMarkerCodeFailedMissingConfig + } + + var epoch int64 + + switch value := epochValue.(type) { + case int64: + epoch = value + + case int: + epoch = int64(value) + + case float64: + epoch = int64(value) + + default: + return 0, "", ObrimMarkerCodeFailedInvalidConfig + } + + instance, ok := instanceValue.(string) + if !ok || strings.TrimSpace(instance) == "" { + return 0, "", ObrimMarkerCodeFailedInvalidConfig + } + + if epoch < 0 { + return 0, "", ObrimMarkerCodeFailedInvalidConfig + } + + return epoch, instance, "" +} + +// obrimMarkerTimeGenerate produces the final time-based marker value. +func obrimMarkerTimeGenerate( + epoch int64, + instance string, +) (string, error) { + now := time.Now().UnixMilli() + + if epoch > now { + return "", obrimMarkerError("invalid epoch") + } + + return fmt.Sprintf( + "%X%s", + now-epoch, + strings.ToUpper(instance), + ), nil +} + +// obrimMarkerRandom generates random collision-resistant markers. +func obrimMarkerRandom(config map[string]any) map[string]any { + length, charset, code := obrimMarkerValidateRandom(config) + if code != "" { + return obrimMarkerBuildResponse(false, code, nil) + } + + marker, err := obrimMarkerRandomGenerate(length, charset) + if err != nil { + return obrimMarkerBuildResponse( + false, + ObrimMarkerCodeFailedGeneration, + nil, + ) + } + + return obrimMarkerBuildResponse( + true, + ObrimMarkerCodeSuccessRandomGenerated, + map[string]any{ + "marker": marker, + "length": length, + "charset": charset, + }, + ) +} + +// obrimMarkerValidateRandom validates random marker configuration parameters. +func obrimMarkerValidateRandom( + config map[string]any, +) (int, string, string) { + var length = obrimMarkerDefaultRandomLength + var charset = obrimMarkerDefaultCharset + + if value, exists := config["length"]; exists { + switch typedValue := value.(type) { + case int: + length = typedValue + + case int64: + length = int(typedValue) + + case float64: + length = int(typedValue) + + default: + return 0, "", ObrimMarkerCodeFailedInvalidConfig + } + } + + if value, exists := config["charset"]; exists { + typedValue, ok := value.(string) + if !ok { + return 0, "", ObrimMarkerCodeFailedInvalidConfig + } + + charset = typedValue + } + + if length <= 0 { + return 0, "", ObrimMarkerCodeFailedValidation + } + + if strings.TrimSpace(charset) == "" { + return 0, "", ObrimMarkerCodeFailedValidation + } + + return length, charset, "" +} + +// obrimMarkerRandomGenerate produces the final random marker value. +func obrimMarkerRandomGenerate( + length int, + charset string, +) (string, error) { + var buffer = make([]byte, length) + var randomBuffer = make([]byte, length) + + _, err := rand.Read(randomBuffer) + if err != nil { + return "", err + } + + for index := range buffer { + buffer[index] = charset[int(randomBuffer[index])%len(charset)] + } + + return string(buffer), nil +} + +// obrimMarkerEncoded generates deterministic encoded markers. +func obrimMarkerEncoded(config map[string]any) map[string]any { + data, length, charset, salt, code := obrimMarkerValidateEncoded(config) + if code != "" { + return obrimMarkerBuildResponse(false, code, nil) + } + + marker, err := obrimMarkerEncodedGenerate( + data, + length, + charset, + salt, + ) + if err != nil { + return obrimMarkerBuildResponse( + false, + ObrimMarkerCodeFailedGeneration, + nil, + ) + } + + return obrimMarkerBuildResponse( + true, + ObrimMarkerCodeSuccessEncodedGenerated, + map[string]any{ + "marker": marker, + "source": data, + "length": length, + }, + ) +} + +// obrimMarkerValidateEncoded validates encoded marker configuration parameters. +func obrimMarkerValidateEncoded( + config map[string]any, +) (string, int, string, string, string) { + dataValue, exists := config["data"] + if !exists { + return "", 0, "", "", ObrimMarkerCodeFailedMissingConfig + } + + data, ok := dataValue.(string) + if !ok || strings.TrimSpace(data) == "" { + return "", 0, "", "", ObrimMarkerCodeFailedInvalidConfig + } + + var length = obrimMarkerDefaultEncodedLength + var charset = obrimMarkerDefaultCharset + var salt string + + if value, exists := config["length"]; exists { + switch typedValue := value.(type) { + case int: + length = typedValue + + case int64: + length = int(typedValue) + + case float64: + length = int(typedValue) + + default: + return "", 0, "", "", ObrimMarkerCodeFailedInvalidConfig + } + } + + if value, exists := config["charset"]; exists { + typedValue, ok := value.(string) + if !ok { + return "", 0, "", "", ObrimMarkerCodeFailedInvalidConfig + } + + charset = typedValue + } + + if value, exists := config["salt"]; exists { + typedValue, ok := value.(string) + if !ok { + return "", 0, "", "", ObrimMarkerCodeFailedInvalidConfig + } + + salt = typedValue + } + + if length <= 0 { + return "", 0, "", "", ObrimMarkerCodeFailedValidation + } + + if strings.TrimSpace(charset) == "" { + return "", 0, "", "", ObrimMarkerCodeFailedValidation + } + + return data, length, charset, salt, "" +} + +// obrimMarkerEncodedGenerate produces the final encoded marker value. +func obrimMarkerEncodedGenerate( + data string, + length int, + charset string, + salt string, +) (string, error) { + var hash = sha256.Sum256([]byte(data + salt)) + var output = make([]byte, length) + + for index := 0; index < length; index++ { + output[index] = charset[int(hash[index%len(hash)])%len(charset)] + } + + return string(output), nil +} + +// obrimMarkerLog logs utility lifecycle events. +func obrimMarkerLog(event string) { + _ = event +} + +// obrimMarkerError formats internal errors. +func obrimMarkerError(message string) error { + return fmt.Errorf("%s", message) +} diff --git a/essential/visible/service/helper/progress/progress.go b/essential/visible/service/helper/progress/progress.go index e69de29..a6d67f0 100644 --- a/essential/visible/service/helper/progress/progress.go +++ b/essential/visible/service/helper/progress/progress.go @@ -0,0 +1,392 @@ +package progress + +import ( + "fmt" + "math" + "strings" + "sync" +) + +const ( + obrimProgressTypeCountable = "countable" + obrimProgressTypeUncountable = "uncountable" + + obrimProgressStateStarted = "started" + obrimProgressStateRunning = "running" + obrimProgressStateCompleted = "completed" + obrimProgressStateCanceled = "canceled" + + ObrimProgressCodeSuccessStarted = "SUCCESS_PROGRESS_STARTED" + ObrimProgressCodeSuccessRunning = "SUCCESS_PROGRESS_RUNNING" + ObrimProgressCodeSuccessCompleted = "SUCCESS_PROGRESS_COMPLETED" + ObrimProgressCodeSuccessCanceled = "SUCCESS_PROGRESS_CANCELED" + + ObrimProgressCodeFailedMisconfigured = "FAILED_PROGRESS_MISCONFIGURED" + + obrimProgressVisualLength = 20 +) + +// obrimProgressStateMutex prevents state corruption during rapid updates. +var obrimProgressStateMutex sync.Mutex + +// ObrimProgressCountablePayload defines countable progress payload data. +type ObrimProgressCountablePayload struct { + State string `json:"state"` + Current int `json:"current"` + Target int `json:"target"` + Percentage int `json:"percentage"` + Message string `json:"message"` + Visual string `json:"visual"` +} + +// ObrimProgressUncountablePayload defines uncountable progress payload data. +type ObrimProgressUncountablePayload struct { + State string `json:"state"` + Placeholder string `json:"placeholder"` + Message string `json:"message"` + Visual string `json:"visual"` +} + +// ObrimProgress manages lifecycle-aware countable and uncountable progress tracking operations. +func ObrimProgress(progressType string, config map[string]any) map[string]any { + obrimProgressStateMutex.Lock() + defer obrimProgressStateMutex.Unlock() + + if !obrimProgressValidate(progressType, config) { + return obrimProgressBuildResponse( + false, + ObrimProgressCodeFailedMisconfigured, + nil, + ) + } + + code := obrimProgressHandleState(config["state"].(string)) + + switch progressType { + case obrimProgressTypeCountable: + return obrimProgressCountable(config, code) + + case obrimProgressTypeUncountable: + return obrimProgressUncountable(config, code) + } + + return obrimProgressBuildResponse( + false, + ObrimProgressCodeFailedMisconfigured, + nil, + ) +} + +// obrimProgressValidate validates input parameters and configuration consistency. +func obrimProgressValidate( + progressType string, + config map[string]any, +) bool { + if config == nil { + return false + } + + stateValue, exists := config["state"] + if !exists { + return false + } + + state, ok := stateValue.(string) + if !ok { + return false + } + + switch state { + case obrimProgressStateStarted, + obrimProgressStateRunning, + obrimProgressStateCompleted, + obrimProgressStateCanceled: + + default: + return false + } + + switch progressType { + case obrimProgressTypeCountable: + currentValue, currentExists := config["current"] + targetValue, targetExists := config["target"] + + if !currentExists || !targetExists { + return false + } + + current, currentOk := currentValue.(int) + target, targetOk := targetValue.(int) + + if !currentOk || !targetOk { + return false + } + + if target <= 0 { + return false + } + + _ = current + + return true + + case obrimProgressTypeUncountable: + placeholderValue, exists := config["placeholder"] + if !exists { + return false + } + + placeholder, ok := placeholderValue.(string) + if !ok { + return false + } + + return strings.TrimSpace(placeholder) != "" + } + + return false +} + +// obrimProgressHandleState processes lifecycle state transitions. +func obrimProgressHandleState(state string) string { + switch state { + case obrimProgressStateStarted: + return ObrimProgressCodeSuccessStarted + + case obrimProgressStateRunning: + return ObrimProgressCodeSuccessRunning + + case obrimProgressStateCompleted: + return ObrimProgressCodeSuccessCompleted + + case obrimProgressStateCanceled: + return ObrimProgressCodeSuccessCanceled + } + + return ObrimProgressCodeFailedMisconfigured +} + +// obrimProgressGenerateMessage generates human-readable progress messages. +func obrimProgressGenerateMessage( + progressType string, + state string, + payload map[string]any, +) string { + switch progressType { + case obrimProgressTypeCountable: + percentage := payload["percentage"].(int) + + switch state { + case obrimProgressStateStarted: + return fmt.Sprintf( + "Progress started (%d%% complete).", + percentage, + ) + + case obrimProgressStateRunning: + return fmt.Sprintf( + "Progress running (%d%% complete).", + percentage, + ) + + case obrimProgressStateCompleted: + return fmt.Sprintf( + "Progress completed (%d%% complete).", + percentage, + ) + + case obrimProgressStateCanceled: + return fmt.Sprintf( + "Progress canceled (%d%% complete).", + percentage, + ) + } + + case obrimProgressTypeUncountable: + placeholder := payload["placeholder"].(string) + + switch state { + case obrimProgressStateStarted: + return fmt.Sprintf( + "Activity started: %s", + placeholder, + ) + + case obrimProgressStateRunning: + return fmt.Sprintf( + "Activity running: %s", + placeholder, + ) + + case obrimProgressStateCompleted: + return fmt.Sprintf( + "Activity completed: %s", + placeholder, + ) + + case obrimProgressStateCanceled: + return fmt.Sprintf( + "Activity canceled: %s", + placeholder, + ) + } + } + + return "" +} + +// obrimProgressGenerateVisual generates CLI-friendly visual progress representations. +func obrimProgressGenerateVisual( + progressType string, + payload map[string]any, +) string { + switch progressType { + case obrimProgressTypeCountable: + percentage := payload["percentage"].(int) + + filled := int(math.Round( + (float64(percentage) / 100.0) * float64(obrimProgressVisualLength), + )) + + if filled > obrimProgressVisualLength { + filled = obrimProgressVisualLength + } + + if filled < 0 { + filled = 0 + } + + return fmt.Sprintf( + "[%s%s] %d%%", + strings.Repeat("=", filled), + strings.Repeat(" ", obrimProgressVisualLength-filled), + percentage, + ) + + case obrimProgressTypeUncountable: + return "[....................]" + } + + return "" +} + +// obrimProgressBuildResponse constructs standardized utility response payloads. +func obrimProgressBuildResponse( + status bool, + code string, + payload any, +) map[string]any { + return map[string]any{ + "status": status, + "code": code, + "payload": payload, + } +} + +// obrimProgressCountable processes countable progress tracking workflows. +func obrimProgressCountable( + config map[string]any, + code string, +) map[string]any { + current := config["current"].(int) + target := config["target"].(int) + state := config["state"].(string) + + percentage := obrimProgressCalculatePercentage( + current, + target, + ) + + payloadData := map[string]any{ + "percentage": percentage, + } + + payload := ObrimProgressCountablePayload{ + State: state, + Current: current, + Target: target, + Percentage: percentage, + Message: obrimProgressGenerateMessage( + obrimProgressTypeCountable, + state, + payloadData, + ), + Visual: obrimProgressGenerateVisual( + obrimProgressTypeCountable, + payloadData, + ), + } + + return obrimProgressBuildResponse( + true, + code, + payload, + ) +} + +// obrimProgressCalculatePercentage calculates and normalizes completion percentages. +func obrimProgressCalculatePercentage( + current int, + target int, +) int { + if current < 0 { + return 0 + } + + percentage := int(math.Round( + (float64(current) / float64(target)) * 100, + )) + + if percentage > 100 { + return 100 + } + + if percentage < 0 { + return 0 + } + + return percentage +} + +// obrimProgressUncountable processes uncountable progress tracking workflows. +func obrimProgressUncountable( + config map[string]any, + code string, +) map[string]any { + state := config["state"].(string) + + placeholder := obrimProgressResolvePlaceholder( + config["placeholder"].(string), + ) + + payloadData := map[string]any{ + "placeholder": placeholder, + } + + payload := ObrimProgressUncountablePayload{ + State: state, + Placeholder: placeholder, + Message: obrimProgressGenerateMessage( + obrimProgressTypeUncountable, + state, + payloadData, + ), + Visual: obrimProgressGenerateVisual( + obrimProgressTypeUncountable, + payloadData, + ), + } + + return obrimProgressBuildResponse( + true, + code, + payload, + ) +} + +// obrimProgressResolvePlaceholder validates and prepares placeholder activity messages. +func obrimProgressResolvePlaceholder( + placeholder string, +) string { + return strings.TrimSpace(placeholder) +} diff --git a/essential/visible/service/helper/retriever/retriever.go b/essential/visible/service/helper/retriever/retriever.go index e69de29..fb496be 100644 --- a/essential/visible/service/helper/retriever/retriever.go +++ b/essential/visible/service/helper/retriever/retriever.go @@ -0,0 +1,410 @@ +package retriever + +import ( + "strings" +) + +const ( + obrimRetrieverTypeJson = "json" + obrimRetrieverTypeDb = "db" + + obrimRetrieverCodeSuccessResource = "SUCCESS_RESOURCE_RETRIEVED" + obrimRetrieverCodeSuccessPath = "SUCCESS_PATH_RETRIEVED" + obrimRetrieverCodeSuccessFields = "SUCCESS_FIELDS_RETRIEVED" + + obrimRetrieverCodeFailedUnsupportedType = "FAILED_UNSUPPORTED_TYPE" + obrimRetrieverCodeFailedMissingConfig = "FAILED_MISSING_CONFIGURATION" + obrimRetrieverCodeFailedInvalidConfig = "FAILED_INVALID_CONFIGURATION" + obrimRetrieverCodeFailedResourceNotFound = "FAILED_RESOURCE_NOT_FOUND" + obrimRetrieverCodeFailedPathNotFound = "FAILED_PATH_NOT_FOUND" + obrimRetrieverCodeFailedFieldNotFound = "FAILED_FIELD_NOT_FOUND" + obrimRetrieverCodeFailedNotImplemented = "FAILED_NOT_IMPLEMENTED" +) + +// ObrimRetrieverJsonProviderRegistry stores registered JSON providers. +var ObrimRetrieverJsonProviderRegistry = map[string]any{} + +// ObrimRetrieverDbProviderRegistry stores registered database providers. +var ObrimRetrieverDbProviderRegistry = map[string]any{} + +// ObrimRetrieverResponse defines the standardized utility response structure. +type ObrimRetrieverResponse struct { + Status bool `json:"status"` + Code string `json:"code"` + Payload map[string]any `json:"payload"` +} + +// ObrimRetriever retrieves data using a unified retrieval interface. +func ObrimRetriever(retrievalType string, config map[string]any) map[string]any { + if !obrimRetrieverValidateType(retrievalType) { + return obrimRetrieverBuildResponse( + false, + obrimRetrieverCodeFailedUnsupportedType, + nil, + ) + } + + validationCode := obrimRetrieverValidateConfig(retrievalType, config) + + if validationCode != "" { + return obrimRetrieverBuildResponse( + false, + validationCode, + nil, + ) + } + + switch retrievalType { + case obrimRetrieverTypeJson: + return obrimRetrieverJson(config) + + case obrimRetrieverTypeDb: + return obrimRetrieverDb(config) + + default: + return obrimRetrieverBuildResponse( + false, + obrimRetrieverCodeFailedUnsupportedType, + nil, + ) + } +} + +// ObrimRetrieverJsonRegister registers a JSON provider. +func ObrimRetrieverJsonRegister(resource string, provider any) { + if strings.TrimSpace(resource) == "" { + return + } + + ObrimRetrieverJsonProviderRegistry[resource] = provider +} + +// ObrimRetrieverDbRegister registers a database provider. +func ObrimRetrieverDbRegister(resource string, provider any) { + if strings.TrimSpace(resource) == "" { + return + } + + ObrimRetrieverDbProviderRegistry[resource] = provider +} + +// obrimRetrieverValidateType validates a retrieval type. +func obrimRetrieverValidateType(retrievalType string) bool { + switch retrievalType { + case obrimRetrieverTypeJson: + return true + + case obrimRetrieverTypeDb: + return true + + default: + return false + } +} + +// obrimRetrieverValidateConfig validates retrieval configuration. +func obrimRetrieverValidateConfig( + retrievalType string, + config map[string]any, +) string { + if config == nil { + return obrimRetrieverCodeFailedMissingConfig + } + + switch retrievalType { + case obrimRetrieverTypeJson: + return obrimRetrieverJsonValidate(config) + + case obrimRetrieverTypeDb: + return obrimRetrieverDbValidate(config) + + default: + return obrimRetrieverCodeFailedUnsupportedType + } +} + +// obrimRetrieverResolveProvider resolves a provider by resource identifier. +func obrimRetrieverResolveProvider( + retrievalType string, + resource string, +) (any, bool) { + switch retrievalType { + case obrimRetrieverTypeJson: + provider, exists := ObrimRetrieverJsonProviderRegistry[resource] + return provider, exists + + case obrimRetrieverTypeDb: + provider, exists := ObrimRetrieverDbProviderRegistry[resource] + return provider, exists + + default: + return nil, false + } +} + +// obrimRetrieverBuildResponse builds a standardized utility response. +func obrimRetrieverBuildResponse( + status bool, + code string, + payload map[string]any, +) map[string]any { + return map[string]any{ + "status": status, + "code": code, + "payload": payload, + } +} + +// obrimRetrieverJson processes JSON retrieval requests. +func obrimRetrieverJson(config map[string]any) map[string]any { + resource := config["resource"].(string) + + provider, exists := obrimRetrieverResolveProvider( + obrimRetrieverTypeJson, + resource, + ) + + if !exists { + return obrimRetrieverBuildResponse( + false, + obrimRetrieverCodeFailedResourceNotFound, + nil, + ) + } + + if fields, exists := config["fields"]; exists { + return obrimRetrieverJsonFields(provider, fields) + } + + if path, exists := config["path"]; exists { + return obrimRetrieverJsonPath(provider, path.(string)) + } + + return obrimRetrieverJsonResource(provider) +} + +// obrimRetrieverJsonResource retrieves an entire resource. +func obrimRetrieverJsonResource(provider any) map[string]any { + data, success := obrimRetrieverJsonRetrieve(provider) + + if !success { + return obrimRetrieverBuildResponse( + false, + obrimRetrieverCodeFailedResourceNotFound, + nil, + ) + } + + return obrimRetrieverBuildResponse( + true, + obrimRetrieverCodeSuccessResource, + map[string]any{ + "data": data, + }, + ) +} + +// obrimRetrieverJsonPath retrieves a value using a dot-notation path. +func obrimRetrieverJsonPath(provider any, path string) map[string]any { + data, success := obrimRetrieverJsonRetrieve(provider) + + if !success { + return obrimRetrieverBuildResponse( + false, + obrimRetrieverCodeFailedResourceNotFound, + nil, + ) + } + + value, found := obrimRetrieverJsonResolvePath(data, path) + + if !found { + return obrimRetrieverBuildResponse( + false, + obrimRetrieverCodeFailedPathNotFound, + nil, + ) + } + + return obrimRetrieverBuildResponse( + true, + obrimRetrieverCodeSuccessPath, + map[string]any{ + "data": value, + }, + ) +} + +// obrimRetrieverJsonFields retrieves multiple values using field selection. +func obrimRetrieverJsonFields(provider any, fieldsValue any) map[string]any { + data, success := obrimRetrieverJsonRetrieve(provider) + + if !success { + return obrimRetrieverBuildResponse( + false, + obrimRetrieverCodeFailedResourceNotFound, + nil, + ) + } + + fields, valid := obrimRetrieverJsonNormalizeFields(fieldsValue) + + if !valid { + return obrimRetrieverBuildResponse( + false, + obrimRetrieverCodeFailedInvalidConfig, + nil, + ) + } + + result := map[string]any{} + + for _, field := range fields { + value, found := obrimRetrieverJsonResolvePath(data, field) + + if !found { + return obrimRetrieverBuildResponse( + false, + obrimRetrieverCodeFailedFieldNotFound, + nil, + ) + } + + result[field] = value + } + + return obrimRetrieverBuildResponse( + true, + obrimRetrieverCodeSuccessFields, + map[string]any{ + "data": result, + }, + ) +} + +// obrimRetrieverJsonValidate validates JSON retrieval configuration. +func obrimRetrieverJsonValidate(config map[string]any) string { + resourceValue, exists := config["resource"] + + if !exists { + return obrimRetrieverCodeFailedMissingConfig + } + + resource, valid := resourceValue.(string) + + if !valid { + return obrimRetrieverCodeFailedInvalidConfig + } + + if strings.TrimSpace(resource) == "" { + return obrimRetrieverCodeFailedInvalidConfig + } + + _, pathExists := config["path"] + _, fieldsExists := config["fields"] + + if pathExists && fieldsExists { + return obrimRetrieverCodeFailedInvalidConfig + } + + if pathExists { + path, valid := config["path"].(string) + + if !valid || strings.TrimSpace(path) == "" { + return obrimRetrieverCodeFailedInvalidConfig + } + } + + if fieldsExists { + fields, valid := obrimRetrieverJsonNormalizeFields(config["fields"]) + + if !valid || len(fields) == 0 { + return obrimRetrieverCodeFailedInvalidConfig + } + } + + return "" +} + +// obrimRetrieverDb processes database retrieval requests. +func obrimRetrieverDb(config map[string]any) map[string]any { + return obrimRetrieverBuildResponse( + false, + obrimRetrieverCodeFailedNotImplemented, + nil, + ) +} + +// obrimRetrieverDbValidate validates database retrieval configuration. +func obrimRetrieverDbValidate(config map[string]any) string { + return "" +} + +// obrimRetrieverJsonRetrieve retrieves resource data from a provider. +func obrimRetrieverJsonRetrieve(provider any) (any, bool) { + switch retrievalProvider := provider.(type) { + case func() any: + return retrievalProvider(), true + + case func() map[string]any: + return retrievalProvider(), true + + case func() (any, bool): + return retrievalProvider() + + case map[string]any: + return retrievalProvider, true + + default: + return nil, false + } +} + +// obrimRetrieverJsonResolvePath resolves a dot-notation path. +func obrimRetrieverJsonResolvePath(data any, path string) (any, bool) { + current := data + + for _, segment := range strings.Split(path, ".") { + object, valid := current.(map[string]any) + + if !valid { + return nil, false + } + + value, exists := object[segment] + + if !exists { + return nil, false + } + + current = value + } + + return current, true +} + +// obrimRetrieverJsonNormalizeFields normalizes field selections. +func obrimRetrieverJsonNormalizeFields(fieldsValue any) ([]string, bool) { + switch fields := fieldsValue.(type) { + case []string: + return fields, true + + case []any: + result := make([]string, 0, len(fields)) + + for _, field := range fields { + fieldString, valid := field.(string) + + if !valid { + return nil, false + } + + result = append(result, fieldString) + } + + return result, true + + default: + return nil, false + } +} diff --git a/essential/visible/service/helper/status/status.go b/essential/visible/service/helper/status/status.go index e69de29..81b524a 100644 --- a/essential/visible/service/helper/status/status.go +++ b/essential/visible/service/helper/status/status.go @@ -0,0 +1,81 @@ +package status + +import ( + "fmt" + "strings" +) + +const ( + obrimStatusLabelInfo = "INFO" + obrimStatusLabelWarning = "WARNING" + obrimStatusLabelSuccess = "SUCCESS" + obrimStatusLabelError = "ERROR" +) + +// obrimStatusIndicatorRegistry stores status indicators. +var obrimStatusIndicatorRegistry = map[string]string{ + obrimStatusLabelInfo: "ℹ", + obrimStatusLabelWarning: "⚠", + obrimStatusLabelSuccess: "✓", + obrimStatusLabelError: "✖", +} + +// ObrimStatus emits a standardized CLI status message. +func ObrimStatus(label string, message string) { + normalizedLabel := obrimStatusNormalizeLabel(label) + formattedLabel := obrimStatusFormatLabel(normalizedLabel) + formattedIndicator := obrimStatusFormatIndicator(normalizedLabel) + formattedMessage := obrimStatusBuildMessage( + formattedLabel, + formattedIndicator, + message, + ) + + fmt.Println(formattedMessage) +} + +// obrimStatusNormalizeLabel normalizes and validates labels. +func obrimStatusNormalizeLabel(label string) string { + normalizedLabel := strings.ToUpper(strings.TrimSpace(label)) + + switch normalizedLabel { + case obrimStatusLabelInfo: + return obrimStatusLabelInfo + + case obrimStatusLabelWarning: + return obrimStatusLabelWarning + + case obrimStatusLabelSuccess: + return obrimStatusLabelSuccess + + case obrimStatusLabelError: + return obrimStatusLabelError + + default: + return obrimStatusLabelInfo + } +} + +// obrimStatusFormatLabel formats semantic labels. +func obrimStatusFormatLabel(label string) string { + return fmt.Sprintf("[%s]", label) +} + +// obrimStatusFormatIndicator generates visual status indicators. +func obrimStatusFormatIndicator(label string) string { + indicator, exists := obrimStatusIndicatorRegistry[label] + if !exists { + return obrimStatusIndicatorRegistry[obrimStatusLabelInfo] + } + + return indicator +} + +// obrimStatusBuildMessage constructs the final terminal message. +func obrimStatusBuildMessage( + label string, + indicator string, + message string, +) string { + return fmt.Sprintf("%s %s %s", indicator, label, message) +} diff --git a/go.mod b/go.mod index 75e7cc0..d13e469 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module go/module go 1.26.4 + +require github.com/sqids/sqids-go v0.4.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a02109b --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/sqids/sqids-go v0.4.1 h1:eQKYzmAZbLlRwHeHYPF35QhgxwZHLnlmVj9AkIj/rrw= +github.com/sqids/sqids-go v0.4.1/go.mod h1:EMwHuPQgSNFS0A49jESTfIQS+066XQTVhukrzEPScl8=