upd: helper services updated
This commit is contained in:
parent
ed6156d6e2
commit
27144056b1
@ -0,0 +1,447 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Cipher
|
||||
|
|
||||
| Purpose:
|
||||
| - Provide reusable AES-256 encryption and decryption utilities for
|
||||
| standard and salted file-based cryptographic workflows.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use only AES-256 compatible keys.
|
||||
| - Use encrypt-standard for non-salted encryption workflows.
|
||||
| - Use encrypt-salted for self-contained encrypted file workflows.
|
||||
| - Use decrypt-standard for non-salted encrypted files.
|
||||
| - Use decrypt-salted for self-contained encrypted files.
|
||||
| - Always provide valid input and output file paths.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimCipher("encrypt-standard", config)
|
||||
| - ObrimCipher("encrypt-salted", config)
|
||||
| - ObrimCipher("decrypt-standard", config)
|
||||
| - ObrimCipher("decrypt-salted", config)
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package cipher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"go/module/essential/visible/service/helper/log"
|
||||
"go/module/essential/visible/service/helper/retriever"
|
||||
"go/module/essential/visible/service/helper/status"
|
||||
)
|
||||
|
||||
const (
|
||||
obrimCipherAlgorithm = "AES-256"
|
||||
obrimCipherSignature = "OBRIMCIPHER"
|
||||
obrimCipherVersion = "1"
|
||||
obrimCipherSaltSize = 32
|
||||
obrimCipherNonceSize = 12
|
||||
)
|
||||
|
||||
type obrimCipherResponse struct {
|
||||
Status bool `json:"status"`
|
||||
Code string `json:"code"`
|
||||
Payload any `json:"payload"`
|
||||
}
|
||||
|
||||
// ObrimCipher executes encryption and decryption workflows.
|
||||
func ObrimCipher(operationType string, config map[string]any) map[string]any {
|
||||
_, _ = retriever.ObrimRetriever, status.ObrimStatus
|
||||
|
||||
log.ObrimLog("INIT", "Cipher operation initialized.")
|
||||
|
||||
if err := obrimCipherValidateType(operationType); err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_INVALID_TYPE", nil)
|
||||
}
|
||||
|
||||
if err := obrimCipherValidateConfig(config); err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_INVALID_CONFIG", nil)
|
||||
}
|
||||
|
||||
keyValue := config["key"].(string)
|
||||
|
||||
if err := obrimCipherValidateKey(keyValue); err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_INVALID_KEY", nil)
|
||||
}
|
||||
|
||||
inputPath, err := obrimCipherResolvePath(config["input"].(string))
|
||||
if err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_INPUT_PATH_VALIDATION", nil)
|
||||
}
|
||||
|
||||
outputPath, err := obrimCipherResolvePath(config["output"].(string))
|
||||
if err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_OUTPUT_PATH_VALIDATION", nil)
|
||||
}
|
||||
|
||||
inputData, err := obrimCipherReadInput(inputPath)
|
||||
if err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_SOURCE_ACCESS", nil)
|
||||
}
|
||||
|
||||
switch operationType {
|
||||
case "encrypt-standard":
|
||||
encryptedData, err := obrimCipherEncryptStandard([]byte(keyValue), inputData)
|
||||
if err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_ENCRYPTION", nil)
|
||||
}
|
||||
|
||||
if err := obrimCipherWriteOutput(outputPath, encryptedData); err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_OUTPUT_WRITE", nil)
|
||||
}
|
||||
|
||||
return obrimCipherBuildResponse(true, "SUCCESS_ENCRYPT_STANDARD", map[string]any{
|
||||
"operation": operationType,
|
||||
"algorithm": obrimCipherAlgorithm,
|
||||
"inputPath": inputPath,
|
||||
"outputPath": outputPath,
|
||||
})
|
||||
|
||||
case "encrypt-salted":
|
||||
salt, err := obrimCipherGenerateSalt()
|
||||
if err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_SALT_GENERATION", nil)
|
||||
}
|
||||
|
||||
encryptedData, err := obrimCipherEncryptSalted([]byte(keyValue), salt, inputData)
|
||||
if err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_ENCRYPTION", nil)
|
||||
}
|
||||
|
||||
if err := obrimCipherWriteOutput(outputPath, encryptedData); err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_OUTPUT_WRITE", nil)
|
||||
}
|
||||
|
||||
return obrimCipherBuildResponse(true, "SUCCESS_ENCRYPT_SALTED", map[string]any{
|
||||
"operation": operationType,
|
||||
"algorithm": obrimCipherAlgorithm,
|
||||
"format": obrimCipherSignature,
|
||||
"version": obrimCipherVersion,
|
||||
"inputPath": inputPath,
|
||||
"outputPath": outputPath,
|
||||
})
|
||||
|
||||
case "decrypt-standard":
|
||||
decryptedData, err := obrimCipherDecryptStandard([]byte(keyValue), inputData)
|
||||
if err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_DECRYPTION", nil)
|
||||
}
|
||||
|
||||
if err := obrimCipherWriteOutput(outputPath, decryptedData); err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_OUTPUT_WRITE", nil)
|
||||
}
|
||||
|
||||
return obrimCipherBuildResponse(true, "SUCCESS_DECRYPT_STANDARD", map[string]any{
|
||||
"operation": operationType,
|
||||
"algorithm": obrimCipherAlgorithm,
|
||||
"inputPath": inputPath,
|
||||
"outputPath": outputPath,
|
||||
})
|
||||
|
||||
case "decrypt-salted":
|
||||
signature, version, err := obrimCipherParseHeader(inputData)
|
||||
if err != nil {
|
||||
if err.Error() == "version" {
|
||||
return obrimCipherBuildResponse(false, "FAILED_VERSION_VALIDATION", nil)
|
||||
}
|
||||
|
||||
return obrimCipherBuildResponse(false, "FAILED_SIGNATURE_VALIDATION", nil)
|
||||
}
|
||||
|
||||
salt, err := obrimCipherExtractSalt(inputData)
|
||||
if err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_SALT_EXTRACTION", nil)
|
||||
}
|
||||
|
||||
payload, err := obrimCipherExtractPayload(inputData)
|
||||
if err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_PAYLOAD_EXTRACTION", nil)
|
||||
}
|
||||
|
||||
decryptedData, err := obrimCipherDecryptSalted([]byte(keyValue), salt, payload)
|
||||
if err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_DECRYPTION", nil)
|
||||
}
|
||||
|
||||
if err := obrimCipherWriteOutput(outputPath, decryptedData); err != nil {
|
||||
return obrimCipherBuildResponse(false, "FAILED_OUTPUT_WRITE", nil)
|
||||
}
|
||||
|
||||
return obrimCipherBuildResponse(true, "SUCCESS_DECRYPT_SALTED", map[string]any{
|
||||
"operation": operationType,
|
||||
"algorithm": obrimCipherAlgorithm,
|
||||
"format": signature,
|
||||
"version": version,
|
||||
"inputPath": inputPath,
|
||||
"outputPath": outputPath,
|
||||
})
|
||||
}
|
||||
|
||||
return obrimCipherBuildResponse(false, "FAILED_UNKNOWN_OPERATION", nil)
|
||||
}
|
||||
|
||||
// obrimCipherValidateType validates operation type.
|
||||
func obrimCipherValidateType(operationType string) error {
|
||||
switch operationType {
|
||||
case "encrypt-standard", "encrypt-salted", "decrypt-standard", "decrypt-salted":
|
||||
return nil
|
||||
default:
|
||||
return errors.New("invalid")
|
||||
}
|
||||
}
|
||||
|
||||
// obrimCipherValidateConfig validates configuration.
|
||||
func obrimCipherValidateConfig(config map[string]any) error {
|
||||
if config == nil {
|
||||
return errors.New("invalid")
|
||||
}
|
||||
|
||||
keyValue, keyExists := config["key"].(string)
|
||||
inputValue, inputExists := config["input"].(string)
|
||||
outputValue, outputExists := config["output"].(string)
|
||||
|
||||
if !keyExists || !inputExists || !outputExists {
|
||||
return errors.New("invalid")
|
||||
}
|
||||
|
||||
if keyValue == "" || inputValue == "" || outputValue == "" {
|
||||
return errors.New("invalid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// obrimCipherValidateKey validates AES-256 key requirements.
|
||||
func obrimCipherValidateKey(key []byte) error {
|
||||
if len(key) != 32 {
|
||||
return errors.New("invalid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// obrimCipherResolvePath resolves path to absolute path.
|
||||
func obrimCipherResolvePath(path string) (string, error) {
|
||||
return filepath.Abs(path)
|
||||
}
|
||||
|
||||
// obrimCipherReadInput reads source file content.
|
||||
func obrimCipherReadInput(path string) ([]byte, error) {
|
||||
fileInfo, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if fileInfo.IsDir() {
|
||||
return nil, errors.New("directory")
|
||||
}
|
||||
|
||||
return os.ReadFile(path)
|
||||
}
|
||||
|
||||
// obrimCipherWriteOutput writes processed content.
|
||||
func obrimCipherWriteOutput(path string, data []byte) error {
|
||||
directory := filepath.Dir(path)
|
||||
|
||||
if err := os.MkdirAll(directory, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tempFile, err := os.CreateTemp(directory, "obrim-cipher-*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tempPath := tempFile.Name()
|
||||
|
||||
if _, err := tempFile.Write(data); err != nil {
|
||||
_ = tempFile.Close()
|
||||
_ = os.Remove(tempPath)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tempFile.Close(); err != nil {
|
||||
_ = os.Remove(tempPath)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Rename(tempPath, path); err != nil {
|
||||
_ = os.Remove(tempPath)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// obrimCipherBuildResponse builds standardized response.
|
||||
func obrimCipherBuildResponse(statusValue bool, code string, payload any) map[string]any {
|
||||
response := obrimCipherResponse{
|
||||
Status: statusValue,
|
||||
Code: code,
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
encoded, _ := json.Marshal(response)
|
||||
|
||||
var result map[string]any
|
||||
|
||||
_ = json.Unmarshal(encoded, &result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// obrimCipherEncryptStandard encrypts AES-256 data.
|
||||
func obrimCipherEncryptStandard(key []byte, data []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Mutable variable: nonce buffer.
|
||||
nonce := make([]byte, obrimCipherNonceSize)
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ciphertext := gcm.Seal(nil, nonce, data, nil)
|
||||
|
||||
return append(nonce, ciphertext...), nil
|
||||
}
|
||||
|
||||
// obrimCipherGenerateSalt generates cryptographic salt.
|
||||
func obrimCipherGenerateSalt() ([]byte, error) {
|
||||
// Mutable variable: salt buffer.
|
||||
salt := make([]byte, obrimCipherSaltSize)
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return salt, nil
|
||||
}
|
||||
|
||||
// obrimCipherBuildHeader builds file header.
|
||||
func obrimCipherBuildHeader() []byte {
|
||||
return []byte(obrimCipherSignature + ":" + obrimCipherVersion + ":")
|
||||
}
|
||||
|
||||
// obrimCipherEncryptSalted encrypts AES-256 data with embedded salt.
|
||||
func obrimCipherEncryptSalted(key []byte, salt []byte, data []byte) ([]byte, error) {
|
||||
derivedKey := sha256.Sum256(append(key, salt...))
|
||||
|
||||
encryptedData, err := obrimCipherEncryptStandard(derivedKey[:], data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
header := obrimCipherBuildHeader()
|
||||
|
||||
var buffer bytes.Buffer
|
||||
|
||||
buffer.Write(header)
|
||||
buffer.Write(salt)
|
||||
buffer.Write(encryptedData)
|
||||
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// obrimCipherDecryptStandard decrypts AES-256 encrypted data.
|
||||
func obrimCipherDecryptStandard(key []byte, data []byte) ([]byte, error) {
|
||||
if len(data) <= obrimCipherNonceSize {
|
||||
return nil, errors.New("invalid")
|
||||
}
|
||||
|
||||
nonce := data[:obrimCipherNonceSize]
|
||||
payload := data[obrimCipherNonceSize:]
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gcm.Open(nil, nonce, payload, nil)
|
||||
}
|
||||
|
||||
// obrimCipherParseHeader parses header metadata.
|
||||
func obrimCipherParseHeader(data []byte) (string, string, error) {
|
||||
header := obrimCipherBuildHeader()
|
||||
|
||||
if len(data) < len(header)+obrimCipherSaltSize {
|
||||
return "", "", errors.New("signature")
|
||||
}
|
||||
|
||||
if !bytes.HasPrefix(data, header) {
|
||||
return "", "", errors.New("signature")
|
||||
}
|
||||
|
||||
return obrimCipherSignature, obrimCipherVersion, nil
|
||||
}
|
||||
|
||||
// obrimCipherExtractSalt extracts salt.
|
||||
func obrimCipherExtractSalt(data []byte) ([]byte, error) {
|
||||
headerLength := len(obrimCipherBuildHeader())
|
||||
|
||||
if len(data) < headerLength+obrimCipherSaltSize {
|
||||
return nil, errors.New("invalid")
|
||||
}
|
||||
|
||||
return data[headerLength : headerLength+obrimCipherSaltSize], nil
|
||||
}
|
||||
|
||||
// obrimCipherExtractPayload extracts encrypted payload.
|
||||
func obrimCipherExtractPayload(data []byte) ([]byte, error) {
|
||||
headerLength := len(obrimCipherBuildHeader())
|
||||
offset := headerLength + obrimCipherSaltSize
|
||||
|
||||
if len(data) <= offset {
|
||||
return nil, errors.New("invalid")
|
||||
}
|
||||
|
||||
return data[offset:], nil
|
||||
}
|
||||
|
||||
// obrimCipherDecryptSalted decrypts AES-256 encrypted data using salt.
|
||||
func obrimCipherDecryptSalted(key []byte, salt []byte, payload []byte) ([]byte, error) {
|
||||
derivedKey := sha256.Sum256(append(key, salt...))
|
||||
|
||||
return obrimCipherDecryptStandard(derivedKey[:], payload)
|
||||
}
|
||||
@ -0,0 +1,527 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Codec
|
||||
|
|
||||
| Purpose:
|
||||
| - Provide unified encoding and decoding capabilities using Base8,
|
||||
| Base10, Base16, Base32, Base64, and Sqids with centralized
|
||||
| validation, dispatching, transformation management, and
|
||||
| structured result handling.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use ObrimCodec() as the public entry point.
|
||||
| - Validate all parameters before dispatching operations.
|
||||
| - Use supported formats only.
|
||||
| - Handle all failures through structured responses.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimCodec("encode", config)
|
||||
| - ObrimCodec("decode", config)
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package codec
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go/module/essential/visible/service/helper/log"
|
||||
"go/module/essential/visible/service/helper/retriever"
|
||||
"go/module/essential/visible/service/helper/status"
|
||||
|
||||
"github.com/sqids/sqids-go"
|
||||
)
|
||||
|
||||
// ObrimCodecResult represents the standardized utility response.
|
||||
type ObrimCodecResult struct {
|
||||
Status bool `json:"status"`
|
||||
Code string `json:"code"`
|
||||
Payload map[string]any `json:"payload"`
|
||||
}
|
||||
|
||||
// ObrimCodecConfig represents validated codec configuration.
|
||||
type ObrimCodecConfig 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(operation string, config map[string]any) map[string]any {
|
||||
_ = retriever.ObrimRetriever
|
||||
status.ObrimStatus("INFO", "Codec operation initialized.")
|
||||
log.ObrimLog("INIT", "Codec operation initialized.")
|
||||
|
||||
validatedConfig, validationCode, validationError := obrimCodecValidation(operation, config)
|
||||
if validationError != nil {
|
||||
status.ObrimStatus("ERROR", validationError.Error())
|
||||
log.ObrimLog("ERROR", validationError.Error())
|
||||
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": validationCode,
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
|
||||
payload, dispatchCode, dispatchError := obrimCodecDispatch(operation, validatedConfig)
|
||||
if dispatchError != nil {
|
||||
status.ObrimStatus("ERROR", dispatchError.Error())
|
||||
log.ObrimLog("ERROR", dispatchError.Error())
|
||||
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": dispatchCode,
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
|
||||
status.ObrimStatus("SUCCESS", "Codec operation completed.")
|
||||
log.ObrimLog("SUCCESS", "Codec operation completed.")
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": dispatchCode,
|
||||
"payload": payload,
|
||||
}
|
||||
}
|
||||
|
||||
// obrimCodecValidation validates required parameters, supported operations, formats, and parameter types.
|
||||
func obrimCodecValidation(operation string, config map[string]any) (ObrimCodecConfig, string, error) {
|
||||
// Mutable validated configuration.
|
||||
var validated ObrimCodecConfig
|
||||
|
||||
switch operation {
|
||||
case "encode", "decode":
|
||||
default:
|
||||
return validated, "FAILED_UNSUPPORTED_OPERATION", errors.New("unsupported operation")
|
||||
}
|
||||
|
||||
// Mutable format value.
|
||||
formatValue, exists := config["format"]
|
||||
if !exists {
|
||||
return validated, "FAILED_MISSING_FORMAT", errors.New("missing format")
|
||||
}
|
||||
|
||||
format, ok := formatValue.(string)
|
||||
if !ok {
|
||||
return validated, "FAILED_INVALID_FORMAT_TYPE", errors.New("invalid format type")
|
||||
}
|
||||
|
||||
switch format {
|
||||
case "base8", "base10", "base16", "base32", "base64", "sqids":
|
||||
default:
|
||||
return validated, "FAILED_UNSUPPORTED_FORMAT", errors.New("unsupported format")
|
||||
}
|
||||
|
||||
// Mutable data value.
|
||||
dataValue, exists := config["data"]
|
||||
if !exists {
|
||||
return validated, "FAILED_MISSING_DATA", errors.New("missing data")
|
||||
}
|
||||
|
||||
switch dataValue.(type) {
|
||||
case string, []byte:
|
||||
default:
|
||||
return validated, "FAILED_INVALID_DATA_TYPE", errors.New("invalid data type")
|
||||
}
|
||||
|
||||
// Mutable charset value.
|
||||
charsetValue, exists := config["charset"]
|
||||
if !exists {
|
||||
return validated, "FAILED_MISSING_CHARSET", errors.New("missing charset")
|
||||
}
|
||||
|
||||
charset, ok := charsetValue.(string)
|
||||
if !ok {
|
||||
return validated, "FAILED_INVALID_CHARSET_TYPE", errors.New("invalid charset type")
|
||||
}
|
||||
|
||||
// Mutable salt value.
|
||||
saltValue, exists := config["salt"]
|
||||
if !exists {
|
||||
return validated, "FAILED_MISSING_SALT", errors.New("missing salt")
|
||||
}
|
||||
|
||||
salt, ok := saltValue.(string)
|
||||
if !ok {
|
||||
return validated, "FAILED_INVALID_SALT_TYPE", errors.New("invalid salt type")
|
||||
}
|
||||
|
||||
validated.Format = format
|
||||
validated.Data = dataValue
|
||||
validated.Charset = charset
|
||||
validated.Salt = salt
|
||||
|
||||
if format == "sqids" {
|
||||
// Mutable length value.
|
||||
lengthValue, exists := config["length"]
|
||||
if !exists {
|
||||
return validated, "FAILED_MISSING_LENGTH", errors.New("missing length")
|
||||
}
|
||||
|
||||
switch value := lengthValue.(type) {
|
||||
case int:
|
||||
validated.Length = value
|
||||
case int64:
|
||||
validated.Length = int(value)
|
||||
case float64:
|
||||
validated.Length = int(value)
|
||||
default:
|
||||
return validated, "FAILED_INVALID_LENGTH_TYPE", errors.New("invalid length type")
|
||||
}
|
||||
} else {
|
||||
// Mutable case value.
|
||||
caseValue, exists := config["case"]
|
||||
if !exists {
|
||||
return validated, "FAILED_MISSING_CASE", errors.New("missing case")
|
||||
}
|
||||
|
||||
caseRule, ok := caseValue.(string)
|
||||
if !ok {
|
||||
return validated, "FAILED_INVALID_CASE_TYPE", errors.New("invalid case type")
|
||||
}
|
||||
|
||||
switch caseRule {
|
||||
case "lower", "upper":
|
||||
default:
|
||||
return validated, "FAILED_INVALID_CASE_VALUE", errors.New("invalid case value")
|
||||
}
|
||||
|
||||
validated.Case = caseRule
|
||||
}
|
||||
|
||||
return validated, "SUCCESS_VALIDATION", nil
|
||||
}
|
||||
|
||||
// obrimCodecDispatch routes validated requests to the appropriate codec implementation.
|
||||
func obrimCodecDispatch(operation string, config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
switch operation {
|
||||
case "encode":
|
||||
switch config.Format {
|
||||
case "base8":
|
||||
return obrimCodecEncodeBase8(config)
|
||||
case "base10":
|
||||
return obrimCodecEncodeBase10(config)
|
||||
case "base16":
|
||||
return obrimCodecEncodeBase16(config)
|
||||
case "base32":
|
||||
return obrimCodecEncodeBase32(config)
|
||||
case "base64":
|
||||
return obrimCodecEncodeBase64(config)
|
||||
case "sqids":
|
||||
return obrimCodecEncodeSqids(config)
|
||||
}
|
||||
case "decode":
|
||||
switch config.Format {
|
||||
case "base8":
|
||||
return obrimCodecDecodeBase8(config)
|
||||
case "base10":
|
||||
return obrimCodecDecodeBase10(config)
|
||||
case "base16":
|
||||
return obrimCodecDecodeBase16(config)
|
||||
case "base32":
|
||||
return obrimCodecDecodeBase32(config)
|
||||
case "base64":
|
||||
return obrimCodecDecodeBase64(config)
|
||||
case "sqids":
|
||||
return obrimCodecDecodeSqids(config)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, "FAILED_DISPATCH", errors.New("dispatch failed")
|
||||
}
|
||||
|
||||
// obrimCodecEncodeBase8 encodes data using Base8 encoding.
|
||||
func obrimCodecEncodeBase8(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
value := obrimCodecBytesToBase(config, 8)
|
||||
|
||||
return map[string]any{
|
||||
"operation": "encode",
|
||||
"format": "base8",
|
||||
"value": obrimCodecApplyCase(obrimCodecTransformEncode(value, config), config.Case),
|
||||
}, "SUCCESS_BASE8_ENCODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecEncodeBase10 encodes data using Base10 encoding.
|
||||
func obrimCodecEncodeBase10(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
value := obrimCodecBytesToBase(config, 10)
|
||||
|
||||
return map[string]any{
|
||||
"operation": "encode",
|
||||
"format": "base10",
|
||||
"value": obrimCodecApplyCase(obrimCodecTransformEncode(value, config), config.Case),
|
||||
}, "SUCCESS_BASE10_ENCODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecEncodeBase16 encodes data using Base16 encoding.
|
||||
func obrimCodecEncodeBase16(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
value := hex.EncodeToString(obrimCodecBytes(config.Data))
|
||||
value = obrimCodecApplyCase(value, config.Case)
|
||||
value = obrimCodecTransformEncode(value, config)
|
||||
|
||||
return map[string]any{
|
||||
"operation": "encode",
|
||||
"format": "base16",
|
||||
"value": value,
|
||||
}, "SUCCESS_BASE16_ENCODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecEncodeBase32 encodes data using Base32 encoding.
|
||||
func obrimCodecEncodeBase32(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
value := base32.StdEncoding.EncodeToString(obrimCodecBytes(config.Data))
|
||||
value = obrimCodecApplyCase(value, config.Case)
|
||||
value = obrimCodecTransformEncode(value, config)
|
||||
|
||||
return map[string]any{
|
||||
"operation": "encode",
|
||||
"format": "base32",
|
||||
"value": value,
|
||||
}, "SUCCESS_BASE32_ENCODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecEncodeBase64 encodes data using Base64 encoding.
|
||||
func obrimCodecEncodeBase64(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
value := base64.StdEncoding.EncodeToString(obrimCodecBytes(config.Data))
|
||||
value = obrimCodecApplyCase(value, config.Case)
|
||||
value = obrimCodecTransformEncode(value, config)
|
||||
|
||||
return map[string]any{
|
||||
"operation": "encode",
|
||||
"format": "base64",
|
||||
"value": value,
|
||||
}, "SUCCESS_BASE64_ENCODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecEncodeSqids encodes data using Sqids encoding with minimum length enforcement.
|
||||
func obrimCodecEncodeSqids(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
options := sqids.Options{
|
||||
MinLength: uint8(config.Length),
|
||||
Alphabet: obrimCodecAlphabet(config.Charset),
|
||||
Blocklist: []string{},
|
||||
}
|
||||
|
||||
instance, err := sqids.New(options)
|
||||
if err != nil {
|
||||
return nil, "FAILED_SQIDS_INITIALIZATION", err
|
||||
}
|
||||
|
||||
number, err := strconv.ParseUint(obrimCodecTransformNumberInput(config), 10, 64)
|
||||
if err != nil {
|
||||
return nil, "FAILED_SQIDS_INPUT", err
|
||||
}
|
||||
|
||||
value, err := instance.Encode([]uint64{number})
|
||||
if err != nil {
|
||||
return nil, "FAILED_SQIDS_ENCODE", err
|
||||
}
|
||||
|
||||
value = config.Salt + value
|
||||
|
||||
return map[string]any{
|
||||
"operation": "encode",
|
||||
"format": "sqids",
|
||||
"value": value,
|
||||
}, "SUCCESS_SQIDS_ENCODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecDecodeBase8 decodes Base8 encoded data.
|
||||
func obrimCodecDecodeBase8(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
value := obrimCodecTransformDecode(obrimCodecString(config.Data), config)
|
||||
|
||||
return map[string]any{
|
||||
"operation": "decode",
|
||||
"format": "base8",
|
||||
"value": value,
|
||||
}, "SUCCESS_BASE8_DECODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecDecodeBase10 decodes Base10 encoded data.
|
||||
func obrimCodecDecodeBase10(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
value := obrimCodecTransformDecode(obrimCodecString(config.Data), config)
|
||||
|
||||
return map[string]any{
|
||||
"operation": "decode",
|
||||
"format": "base10",
|
||||
"value": value,
|
||||
}, "SUCCESS_BASE10_DECODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecDecodeBase16 decodes Base16 encoded data.
|
||||
func obrimCodecDecodeBase16(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
value := obrimCodecTransformDecode(obrimCodecString(config.Data), config)
|
||||
|
||||
decoded, err := hex.DecodeString(value)
|
||||
if err != nil {
|
||||
return nil, "FAILED_BASE16_DECODE", err
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"operation": "decode",
|
||||
"format": "base16",
|
||||
"value": string(decoded),
|
||||
}, "SUCCESS_BASE16_DECODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecDecodeBase32 decodes Base32 encoded data.
|
||||
func obrimCodecDecodeBase32(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
value := strings.ToUpper(obrimCodecTransformDecode(obrimCodecString(config.Data), config))
|
||||
|
||||
decoded, err := base32.StdEncoding.DecodeString(value)
|
||||
if err != nil {
|
||||
return nil, "FAILED_BASE32_DECODE", err
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"operation": "decode",
|
||||
"format": "base32",
|
||||
"value": string(decoded),
|
||||
}, "SUCCESS_BASE32_DECODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecDecodeBase64 decodes Base64 encoded data.
|
||||
func obrimCodecDecodeBase64(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
value := obrimCodecTransformDecode(obrimCodecString(config.Data), config)
|
||||
|
||||
decoded, err := base64.StdEncoding.DecodeString(value)
|
||||
if err != nil {
|
||||
return nil, "FAILED_BASE64_DECODE", err
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"operation": "decode",
|
||||
"format": "base64",
|
||||
"value": string(decoded),
|
||||
}, "SUCCESS_BASE64_DECODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecDecodeSqids decodes Sqids encoded data using deterministic length validation.
|
||||
func obrimCodecDecodeSqids(config ObrimCodecConfig) (map[string]any, string, error) {
|
||||
options := sqids.Options{
|
||||
MinLength: uint8(config.Length),
|
||||
Alphabet: obrimCodecAlphabet(config.Charset),
|
||||
Blocklist: []string{},
|
||||
}
|
||||
|
||||
instance, err := sqids.New(options)
|
||||
if err != nil {
|
||||
return nil, "FAILED_SQIDS_INITIALIZATION", err
|
||||
}
|
||||
|
||||
value := strings.TrimPrefix(obrimCodecString(config.Data), config.Salt)
|
||||
|
||||
decoded := instance.Decode(value)
|
||||
if len(decoded) == 0 {
|
||||
return nil, "FAILED_SQIDS_DECODE", errors.New("invalid sqids value")
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"operation": "decode",
|
||||
"format": "sqids",
|
||||
"value": fmt.Sprintf("%d", decoded[0]),
|
||||
}, "SUCCESS_SQIDS_DECODE", nil
|
||||
}
|
||||
|
||||
// obrimCodecBytes converts supported data types to bytes.
|
||||
func obrimCodecBytes(data any) []byte {
|
||||
switch value := data.(type) {
|
||||
case string:
|
||||
return []byte(value)
|
||||
case []byte:
|
||||
return value
|
||||
default:
|
||||
return []byte{}
|
||||
}
|
||||
}
|
||||
|
||||
// obrimCodecString converts supported data types to string.
|
||||
func obrimCodecString(data any) string {
|
||||
switch value := data.(type) {
|
||||
case string:
|
||||
return value
|
||||
case []byte:
|
||||
return string(value)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// obrimCodecApplyCase applies output casing rules.
|
||||
func obrimCodecApplyCase(value string, caseRule string) string {
|
||||
if caseRule == "upper" {
|
||||
return strings.ToUpper(value)
|
||||
}
|
||||
|
||||
return strings.ToLower(value)
|
||||
}
|
||||
|
||||
// obrimCodecTransformEncode applies charset and salt transformations.
|
||||
func obrimCodecTransformEncode(value string, config ObrimCodecConfig) string {
|
||||
return config.Salt + config.Charset + ":" + value
|
||||
}
|
||||
|
||||
// obrimCodecTransformDecode reverses charset and salt transformations.
|
||||
func obrimCodecTransformDecode(value string, config ObrimCodecConfig) string {
|
||||
value = strings.TrimPrefix(value, config.Salt)
|
||||
value = strings.TrimPrefix(value, config.Charset+":")
|
||||
return value
|
||||
}
|
||||
|
||||
// obrimCodecAlphabet resolves Sqids alphabet.
|
||||
func obrimCodecAlphabet(charset string) string {
|
||||
if charset == "" {
|
||||
return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
|
||||
return charset
|
||||
}
|
||||
|
||||
// obrimCodecTransformNumberInput converts input into deterministic numeric content.
|
||||
func obrimCodecTransformNumberInput(config ObrimCodecConfig) string {
|
||||
value := obrimCodecString(config.Data)
|
||||
|
||||
if _, err := strconv.ParseUint(value, 10, 64); err == nil {
|
||||
return value
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%d", len(value)+len(config.Salt)+len(config.Charset))
|
||||
}
|
||||
|
||||
// obrimCodecBytesToBase converts bytes into arbitrary base string representation.
|
||||
func obrimCodecBytesToBase(config ObrimCodecConfig, base int) string {
|
||||
data := obrimCodecBytes(config.Data)
|
||||
|
||||
var builder strings.Builder
|
||||
|
||||
for _, item := range data {
|
||||
builder.WriteString(strconv.FormatInt(int64(item), base))
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
@ -0,0 +1,276 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - datetime
|
||||
|
|
||||
| Purpose:
|
||||
| - Retrieve and format the current date and time from either the host
|
||||
| system clock or a trusted framework-managed NTP source.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use local for host system clock retrieval.
|
||||
| - Use trusted for framework-managed NTP retrieval.
|
||||
| - Only use supported framework date/time format patterns.
|
||||
| - All responses must be returned as standardized JSON objects.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimDatetime("local", map[string]any{"format":"yyyy-MM-dd"})
|
||||
| - ObrimDatetime("trusted", map[string]any{"format":"timestampsec"})
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package datetime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"go/module/essential/visible/service/helper/log"
|
||||
"go/module/essential/visible/service/helper/status"
|
||||
)
|
||||
|
||||
// ObrimDatetimePayload represents datetime payload data.
|
||||
type ObrimDatetimePayload struct {
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// ObrimDatetimeOutput represents utility output structure.
|
||||
type ObrimDatetimeOutput 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": "2006-01-02T15:04:05Z07:00",
|
||||
}
|
||||
|
||||
// ObrimDatetime retrieves and formats current date and time.
|
||||
func ObrimDatetime(datetimeType string, config map[string]any) string {
|
||||
status.ObrimStatus("INFO", "Initializing datetime utility.")
|
||||
log.ObrimLog("INIT", "Datetime utility initialized.")
|
||||
|
||||
if err := obrimDatetimeValidate(datetimeType, config); err != nil {
|
||||
status.ObrimStatus("ERROR", err.Error())
|
||||
log.ObrimLog("ERROR", err.Error())
|
||||
|
||||
response := obrimDatetimeResponse(false, "FAILED_"+err.Error(), nil)
|
||||
return response
|
||||
}
|
||||
|
||||
format := config["format"].(string)
|
||||
|
||||
var currentTime time.Time
|
||||
var err error
|
||||
|
||||
switch datetimeType {
|
||||
case "local":
|
||||
currentTime, err = obrimDatetimeLocal()
|
||||
|
||||
case "trusted":
|
||||
currentTime, err = obrimDatetimeTrusted()
|
||||
|
||||
default:
|
||||
err = errors.New("INVALID_TYPE")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
status.ObrimStatus("ERROR", err.Error())
|
||||
log.ObrimLog("ERROR", err.Error())
|
||||
|
||||
response := obrimDatetimeResponse(false, "FAILED_"+err.Error(), nil)
|
||||
return response
|
||||
}
|
||||
|
||||
value, err := obrimDatetimeFormatApply(currentTime, format)
|
||||
if err != nil {
|
||||
status.ObrimStatus("ERROR", err.Error())
|
||||
log.ObrimLog("ERROR", err.Error())
|
||||
|
||||
response := obrimDatetimeResponse(false, "FAILED_"+err.Error(), nil)
|
||||
return response
|
||||
}
|
||||
|
||||
payload := &ObrimDatetimePayload{
|
||||
Value: value,
|
||||
}
|
||||
|
||||
status.ObrimStatus("SUCCESS", "Datetime retrieved successfully.")
|
||||
log.ObrimLog("SUCCESS", "Datetime retrieved successfully.")
|
||||
|
||||
return obrimDatetimeResponse(
|
||||
true,
|
||||
"SUCCESS_DATETIME_RETRIEVED",
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimDatetimeValidate validates utility inputs.
|
||||
func obrimDatetimeValidate(datetimeType string, config map[string]any) error {
|
||||
if datetimeType != "local" && datetimeType != "trusted" {
|
||||
return errors.New("INVALID_TYPE")
|
||||
}
|
||||
|
||||
formatValue, exists := config["format"]
|
||||
if !exists {
|
||||
return errors.New("INVALID_FORMAT")
|
||||
}
|
||||
|
||||
format, ok := formatValue.(string)
|
||||
if !ok {
|
||||
return errors.New("INVALID_FORMAT")
|
||||
}
|
||||
|
||||
if !obrimDatetimePatternValidate(format) {
|
||||
return errors.New("INVALID_FORMAT")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// obrimDatetimePatternValidate validates supported patterns.
|
||||
func obrimDatetimePatternValidate(pattern string) bool {
|
||||
_, exists := obrimDatetimePatternMap[pattern]
|
||||
return exists || pattern == "timestampsec" || pattern == "timestampmil"
|
||||
}
|
||||
|
||||
// obrimDatetimePatternResolve resolves framework patterns.
|
||||
func obrimDatetimePatternResolve(pattern string) (string, error) {
|
||||
if pattern == "timestampsec" || pattern == "timestampmil" {
|
||||
return pattern, nil
|
||||
}
|
||||
|
||||
layout, exists := obrimDatetimePatternMap[pattern]
|
||||
if !exists {
|
||||
return "", errors.New("INVALID_FORMAT")
|
||||
}
|
||||
|
||||
return layout, nil
|
||||
}
|
||||
|
||||
// obrimDatetimeFormatApply applies formatting.
|
||||
func obrimDatetimeFormatApply(value time.Time, pattern string) (string, error) {
|
||||
layout, err := obrimDatetimePatternResolve(pattern)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
switch pattern {
|
||||
case "timestampsec":
|
||||
return time.Unix(value.Unix(), 0).Format("1136239445"), nil
|
||||
|
||||
case "timestampmil":
|
||||
return time.UnixMilli(value.UnixMilli()).Format("1136239445000"), nil
|
||||
|
||||
default:
|
||||
return value.Format(layout), nil
|
||||
}
|
||||
}
|
||||
|
||||
// obrimDatetimeLocal retrieves local system time.
|
||||
func obrimDatetimeLocal() (time.Time, error) {
|
||||
return time.Now(), nil
|
||||
}
|
||||
|
||||
// obrimDatetimeTrusted retrieves trusted time.
|
||||
func obrimDatetimeTrusted() (time.Time, error) {
|
||||
return obrimDatetimeTrustedSync()
|
||||
}
|
||||
|
||||
// obrimDatetimeTrustedSync synchronizes trusted NTP time.
|
||||
func obrimDatetimeTrustedSync() (time.Time, error) {
|
||||
connection, err := net.DialTimeout(
|
||||
"udp",
|
||||
"time.google.com:123",
|
||||
5*time.Second,
|
||||
)
|
||||
if err != nil {
|
||||
return time.Time{}, errors.New("TRUSTED_TIME_RETRIEVAL")
|
||||
}
|
||||
|
||||
defer connection.Close()
|
||||
|
||||
request := make([]byte, 48)
|
||||
request[0] = 0x1B
|
||||
|
||||
if _, err = connection.Write(request); err != nil {
|
||||
return time.Time{}, errors.New("TRUSTED_TIME_RETRIEVAL")
|
||||
}
|
||||
|
||||
if err = connection.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
|
||||
return time.Time{}, errors.New("TRUSTED_TIME_RETRIEVAL")
|
||||
}
|
||||
|
||||
response := make([]byte, 48)
|
||||
|
||||
if _, err = connection.Read(response); err != nil {
|
||||
return time.Time{}, errors.New("TRUSTED_TIME_RETRIEVAL")
|
||||
}
|
||||
|
||||
seconds := uint64(response[40])<<24 |
|
||||
uint64(response[41])<<16 |
|
||||
uint64(response[42])<<8 |
|
||||
uint64(response[43])
|
||||
|
||||
const ntpEpochOffset = 2208988800
|
||||
|
||||
unixSeconds := int64(seconds) - ntpEpochOffset
|
||||
|
||||
return time.Unix(unixSeconds, 0).UTC(), nil
|
||||
}
|
||||
|
||||
// obrimDatetimeResponse builds standardized responses.
|
||||
func obrimDatetimeResponse(
|
||||
statusValue bool,
|
||||
code string,
|
||||
payload *ObrimDatetimePayload,
|
||||
) string {
|
||||
response := ObrimDatetimeOutput{
|
||||
Status: statusValue,
|
||||
Code: code,
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
data, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
fallback := ObrimDatetimeOutput{
|
||||
Status: false,
|
||||
Code: "FAILED_RESPONSE_BUILD",
|
||||
Payload: nil,
|
||||
}
|
||||
|
||||
data, _ = json.Marshal(fallback)
|
||||
}
|
||||
|
||||
return string(data)
|
||||
}
|
||||
@ -0,0 +1,677 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Filesystem
|
||||
|
|
||||
| Purpose:
|
||||
| - Provide reusable, OS-agnostic filesystem operations through a unified execution interface.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use for deterministic filesystem listing, validation, creation, deletion, and permission operations.
|
||||
| - Execute exactly one operation per invocation.
|
||||
| - Validate configuration before execution.
|
||||
| - Return structured output for all execution paths.
|
||||
| - Remain independent from runtime execution layers.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimFilesystem("list", map[string]any{"strategy":"user"})
|
||||
| - ObrimFilesystem("create", map[string]any{"entity":"directory","name":"example"})
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package filesystem
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go/module/essential/visible/service/helper/log"
|
||||
"go/module/essential/visible/service/helper/status"
|
||||
)
|
||||
|
||||
type ObrimFilesystemResult struct {
|
||||
Status bool `json:"status"`
|
||||
Code string `json:"code"`
|
||||
Payload any `json:"payload"`
|
||||
}
|
||||
|
||||
type obrimFilesystemEntry struct {
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Entity string `json:"entity"`
|
||||
Size int64 `json:"size"`
|
||||
Modified time.Time `json:"modified"`
|
||||
Created time.Time `json:"created"`
|
||||
IsHidden bool `json:"hidden"`
|
||||
IsSymlink bool `json:"symlink"`
|
||||
Permissions string `json:"permission"`
|
||||
}
|
||||
|
||||
var obrimFilesystemSupportedTypes = map[string]bool{
|
||||
"list": true,
|
||||
"check": true,
|
||||
"create": true,
|
||||
"delete": true,
|
||||
"permission": true,
|
||||
}
|
||||
|
||||
var obrimFilesystemAllowedKeys = map[string]map[string]bool{
|
||||
"list": {
|
||||
"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,
|
||||
},
|
||||
"check": {
|
||||
"entity": true, "strategy": true, "base": true, "name": true,
|
||||
"readable": true, "writable": true,
|
||||
},
|
||||
"create": {
|
||||
"entity": true, "strategy": true, "base": true, "name": true,
|
||||
"hidden": true,
|
||||
},
|
||||
"delete": {
|
||||
"entity": true, "strategy": true, "base": true, "name": true,
|
||||
"recursive": true,
|
||||
},
|
||||
"permission": {
|
||||
"entity": true, "strategy": true, "base": true, "name": true,
|
||||
"mode": true, "permission": true,
|
||||
},
|
||||
}
|
||||
|
||||
// ObrimFilesystem executes a filesystem operation and returns a structured result.
|
||||
func ObrimFilesystem(operationType string, config map[string]any) map[string]any {
|
||||
log.ObrimLog("INIT", fmt.Sprintf("filesystem operation: %s", operationType))
|
||||
|
||||
if err := obrimFilesystemValidate(operationType, config); err != nil {
|
||||
status.ObrimStatus("ERROR", err.Error())
|
||||
log.ObrimLog("ERROR", err.Error())
|
||||
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": "FAILED_VALIDATION",
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
|
||||
switch operationType {
|
||||
case "list":
|
||||
return obrimFilesystemList(config)
|
||||
|
||||
case "check":
|
||||
return obrimFilesystemCheck(config)
|
||||
|
||||
case "create":
|
||||
return obrimFilesystemCreate(config)
|
||||
|
||||
case "delete":
|
||||
return obrimFilesystemDelete(config)
|
||||
|
||||
case "permission":
|
||||
return obrimFilesystemPermission(config)
|
||||
|
||||
default:
|
||||
status.ObrimStatus("ERROR", "Unsupported operation.")
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": "FAILED_UNSUPPORTED_OPERATION",
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// obrimFilesystemValidate validates operation type and configuration.
|
||||
func obrimFilesystemValidate(operationType string, config map[string]any) error {
|
||||
if !obrimFilesystemSupportedTypes[operationType] {
|
||||
return errors.New("unsupported operation type")
|
||||
}
|
||||
|
||||
allowed := obrimFilesystemAllowedKeys[operationType]
|
||||
|
||||
for key := range config {
|
||||
if !allowed[key] {
|
||||
return fmt.Errorf("unsupported config key: %s", key)
|
||||
}
|
||||
}
|
||||
|
||||
if operationType != "list" {
|
||||
if _, exists := config["name"]; !exists {
|
||||
return errors.New("name is required")
|
||||
}
|
||||
}
|
||||
|
||||
if operationType == "create" || operationType == "delete" {
|
||||
entity := fmt.Sprintf("%v", config["entity"])
|
||||
|
||||
if entity != "file" && entity != "directory" {
|
||||
return errors.New("invalid entity")
|
||||
}
|
||||
}
|
||||
|
||||
if operationType == "permission" {
|
||||
mode := fmt.Sprintf("%v", config["mode"])
|
||||
|
||||
if mode != "read" && mode != "write" {
|
||||
return errors.New("invalid permission mode")
|
||||
}
|
||||
|
||||
if mode == "write" {
|
||||
if err := obrimFilesystemPermissionValidate(config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// obrimFilesystemResolve resolves and normalizes filesystem paths.
|
||||
func obrimFilesystemResolve(config map[string]any) (string, error) {
|
||||
strategy := fmt.Sprintf("%v", config["strategy"])
|
||||
|
||||
var base string
|
||||
|
||||
switch strategy {
|
||||
case "", "user":
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
base = home
|
||||
|
||||
case "custom":
|
||||
base = fmt.Sprintf("%v", config["base"])
|
||||
|
||||
if base == "" {
|
||||
return "", errors.New("base path required")
|
||||
}
|
||||
|
||||
default:
|
||||
return "", errors.New("invalid strategy")
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%v", config["name"])
|
||||
|
||||
return filepath.Clean(filepath.Join(base, name)), nil
|
||||
}
|
||||
|
||||
// obrimFilesystemPayload builds standardized payload structures.
|
||||
func obrimFilesystemPayload(data map[string]any) map[string]any {
|
||||
return data
|
||||
}
|
||||
|
||||
// obrimFilesystemEntityType determines filesystem entity type.
|
||||
func obrimFilesystemEntityType(path string) string {
|
||||
info, err := os.Stat(path)
|
||||
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
return "directory"
|
||||
}
|
||||
|
||||
return "file"
|
||||
}
|
||||
|
||||
// obrimFilesystemPermissionValidate validates permission specifications.
|
||||
func obrimFilesystemPermissionValidate(config map[string]any) error {
|
||||
permission := fmt.Sprintf("%v", config["permission"])
|
||||
|
||||
if permission == "" {
|
||||
return errors.New("permission is required")
|
||||
}
|
||||
|
||||
_, err := strconv.ParseUint(permission, 8, 32)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// obrimFilesystemList executes filesystem listing operations.
|
||||
func obrimFilesystemList(config map[string]any) map[string]any {
|
||||
base, err := obrimFilesystemResolve(map[string]any{
|
||||
"strategy": config["strategy"],
|
||||
"base": config["base"],
|
||||
"name": "",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": "FAILED_PATH_RESOLUTION",
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
|
||||
entries, err := obrimFilesystemListTraverse(base, config)
|
||||
|
||||
if err != nil {
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": "FAILED_LIST",
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
|
||||
entries = obrimFilesystemListFilter(entries, config)
|
||||
entries = obrimFilesystemListSort(entries, config)
|
||||
|
||||
status.ObrimStatus("SUCCESS", "Filesystem listing completed.")
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": "SUCCESS_LIST",
|
||||
"payload": obrimFilesystemPayload(map[string]any{
|
||||
"entries": entries,
|
||||
"total": len(entries),
|
||||
"recursive": config["recursive"] == true,
|
||||
"base_path": base,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// obrimFilesystemListTraverse traverses filesystem entities.
|
||||
func obrimFilesystemListTraverse(base string, config map[string]any) ([]obrimFilesystemEntry, error) {
|
||||
recursive := config["recursive"] == true
|
||||
includeHidden := config["include_hidden"] == true
|
||||
followSymlink := config["follow_symlink"] == true
|
||||
absolute := config["absolute_path"] == true
|
||||
|
||||
var entries []obrimFilesystemEntry
|
||||
|
||||
if recursive {
|
||||
err := filepath.Walk(base, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if path == base {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !includeHidden && strings.HasPrefix(info.Name(), ".") {
|
||||
if info.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if info.Mode()&os.ModeSymlink != 0 && !followSymlink {
|
||||
return nil
|
||||
}
|
||||
|
||||
entryPath := path
|
||||
|
||||
if !absolute {
|
||||
entryPath = info.Name()
|
||||
}
|
||||
|
||||
entries = append(entries, obrimFilesystemEntry{
|
||||
Name: info.Name(),
|
||||
Path: entryPath,
|
||||
Entity: obrimFilesystemEntityType(path),
|
||||
Size: info.Size(),
|
||||
Modified: info.ModTime(),
|
||||
Created: info.ModTime(),
|
||||
IsHidden: strings.HasPrefix(info.Name(), "."),
|
||||
IsSymlink: info.Mode()&os.ModeSymlink != 0,
|
||||
Permissions: info.Mode().Perm().String(),
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return entries, err
|
||||
}
|
||||
|
||||
list, err := os.ReadDir(base)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, item := range list {
|
||||
if !includeHidden && strings.HasPrefix(item.Name(), ".") {
|
||||
continue
|
||||
}
|
||||
|
||||
info, err := item.Info()
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
path := filepath.Join(base, item.Name())
|
||||
|
||||
entryPath := path
|
||||
|
||||
if !absolute {
|
||||
entryPath = item.Name()
|
||||
}
|
||||
|
||||
entries = append(entries, obrimFilesystemEntry{
|
||||
Name: item.Name(),
|
||||
Path: entryPath,
|
||||
Entity: obrimFilesystemEntityType(path),
|
||||
Size: info.Size(),
|
||||
Modified: info.ModTime(),
|
||||
Created: info.ModTime(),
|
||||
IsHidden: strings.HasPrefix(item.Name(), "."),
|
||||
IsSymlink: info.Mode()&os.ModeSymlink != 0,
|
||||
Permissions: info.Mode().Perm().String(),
|
||||
})
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
// obrimFilesystemListFilter applies entity and pattern filtering.
|
||||
func obrimFilesystemListFilter(entries []obrimFilesystemEntry, config map[string]any) []obrimFilesystemEntry {
|
||||
entity := fmt.Sprintf("%v", config["entity"])
|
||||
pattern := fmt.Sprintf("%v", config["filter_pattern"])
|
||||
|
||||
var filtered []obrimFilesystemEntry
|
||||
|
||||
for _, entry := range entries {
|
||||
if entity != "" && entry.Entity != entity {
|
||||
continue
|
||||
}
|
||||
|
||||
if pattern != "" {
|
||||
match, _ := filepath.Match(pattern, entry.Name)
|
||||
|
||||
if !match {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
filtered = append(filtered, entry)
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
||||
// obrimFilesystemListSort applies result sorting behavior.
|
||||
func obrimFilesystemListSort(entries []obrimFilesystemEntry, config map[string]any) []obrimFilesystemEntry {
|
||||
sortBy := fmt.Sprintf("%v", config["sort_by"])
|
||||
order := fmt.Sprintf("%v", config["sort_order"])
|
||||
|
||||
sort.Slice(entries, func(i, j int) bool {
|
||||
result := false
|
||||
|
||||
switch sortBy {
|
||||
case "size":
|
||||
result = entries[i].Size < entries[j].Size
|
||||
|
||||
case "modified":
|
||||
result = entries[i].Modified.Before(entries[j].Modified)
|
||||
|
||||
case "created":
|
||||
result = entries[i].Created.Before(entries[j].Created)
|
||||
|
||||
default:
|
||||
result = entries[i].Name < entries[j].Name
|
||||
}
|
||||
|
||||
if order == "desc" {
|
||||
return !result
|
||||
}
|
||||
|
||||
return result
|
||||
})
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
// obrimFilesystemCheck executes filesystem 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": "FAILED_PATH_RESOLUTION", "payload": nil}
|
||||
}
|
||||
|
||||
_, err = os.Stat(path)
|
||||
|
||||
exists := err == nil
|
||||
|
||||
readable, writable := obrimFilesystemCheckAccess(path)
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": "SUCCESS_CHECK",
|
||||
"payload": map[string]any{
|
||||
"path": path,
|
||||
"exists": exists,
|
||||
"entity": obrimFilesystemEntityType(path),
|
||||
"readable": readable,
|
||||
"writable": writable,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// obrimFilesystemCheckAccess verifies filesystem accessibility.
|
||||
func obrimFilesystemCheckAccess(path string) (bool, bool) {
|
||||
readable := true
|
||||
writable := true
|
||||
|
||||
file, err := os.Open(path)
|
||||
|
||||
if err != nil {
|
||||
readable = false
|
||||
} else {
|
||||
_ = file.Close()
|
||||
}
|
||||
|
||||
file, err = os.OpenFile(path, os.O_WRONLY, 0)
|
||||
|
||||
if err != nil {
|
||||
writable = false
|
||||
} else {
|
||||
_ = file.Close()
|
||||
}
|
||||
|
||||
return readable, writable
|
||||
}
|
||||
|
||||
// obrimFilesystemCreate executes filesystem entity creation operations.
|
||||
func obrimFilesystemCreate(config map[string]any) map[string]any {
|
||||
path, err := obrimFilesystemResolve(config)
|
||||
|
||||
if err != nil {
|
||||
return map[string]any{"status": false, "code": "FAILED_PATH_RESOLUTION", "payload": nil}
|
||||
}
|
||||
|
||||
entity := fmt.Sprintf("%v", config["entity"])
|
||||
|
||||
if entity == "file" {
|
||||
err = obrimFilesystemCreateFile(path)
|
||||
} else {
|
||||
err = obrimFilesystemCreateDirectory(path)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return map[string]any{"status": false, "code": "FAILED_CREATE", "payload": nil}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": "SUCCESS_CREATE",
|
||||
"payload": map[string]any{
|
||||
"path": path,
|
||||
"entity": entity,
|
||||
"hidden": config["hidden"] == true,
|
||||
"created": true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// obrimFilesystemCreateFile creates a filesystem file.
|
||||
func obrimFilesystemCreateFile(path string) error {
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := os.Create(path)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return file.Close()
|
||||
}
|
||||
|
||||
// obrimFilesystemCreateDirectory creates a filesystem directory.
|
||||
func obrimFilesystemCreateDirectory(path string) error {
|
||||
return os.MkdirAll(path, 0755)
|
||||
}
|
||||
|
||||
// obrimFilesystemDelete executes filesystem entity deletion operations.
|
||||
func obrimFilesystemDelete(config map[string]any) map[string]any {
|
||||
path, err := obrimFilesystemResolve(config)
|
||||
|
||||
if err != nil {
|
||||
return map[string]any{"status": false, "code": "FAILED_PATH_RESOLUTION", "payload": nil}
|
||||
}
|
||||
|
||||
entity := fmt.Sprintf("%v", config["entity"])
|
||||
|
||||
if entity == "file" {
|
||||
err = obrimFilesystemDeleteFile(path)
|
||||
} else {
|
||||
err = obrimFilesystemDeleteDirectory(path, config["recursive"] == true)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return map[string]any{"status": false, "code": "FAILED_DELETE", "payload": nil}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": "SUCCESS_DELETE",
|
||||
"payload": map[string]any{
|
||||
"path": path,
|
||||
"entity": entity,
|
||||
"deleted": true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// obrimFilesystemDeleteFile deletes a filesystem file.
|
||||
func obrimFilesystemDeleteFile(path string) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// obrimFilesystemDeleteDirectory deletes a filesystem directory.
|
||||
func obrimFilesystemDeleteDirectory(path string, recursive bool) error {
|
||||
if recursive {
|
||||
return os.RemoveAll(path)
|
||||
}
|
||||
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// obrimFilesystemPermission executes filesystem permission operations.
|
||||
func obrimFilesystemPermission(config map[string]any) map[string]any {
|
||||
path, err := obrimFilesystemResolve(config)
|
||||
|
||||
if err != nil {
|
||||
return map[string]any{"status": false, "code": "FAILED_PATH_RESOLUTION", "payload": nil}
|
||||
}
|
||||
|
||||
mode := fmt.Sprintf("%v", config["mode"])
|
||||
|
||||
if mode == "read" {
|
||||
return obrimFilesystemPermissionRead(path)
|
||||
}
|
||||
|
||||
return obrimFilesystemPermissionWrite(path, fmt.Sprintf("%v", config["permission"]))
|
||||
}
|
||||
|
||||
// obrimFilesystemPermissionRead retrieves filesystem permissions.
|
||||
func obrimFilesystemPermissionRead(path string) map[string]any {
|
||||
info, err := os.Stat(path)
|
||||
|
||||
if err != nil {
|
||||
return map[string]any{"status": false, "code": "FAILED_PERMISSION_READ", "payload": nil}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": "SUCCESS_PERMISSION_READ",
|
||||
"payload": map[string]any{
|
||||
"path": path,
|
||||
"permission": info.Mode().Perm().String(),
|
||||
"mode": "read",
|
||||
"updated": false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// obrimFilesystemPermissionWrite updates filesystem permissions.
|
||||
func obrimFilesystemPermissionWrite(path string, permission string) map[string]any {
|
||||
if runtime.GOOS == "windows" {
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": "FAILED_PERMISSION_UNSUPPORTED",
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
|
||||
value, err := strconv.ParseUint(permission, 8, 32)
|
||||
|
||||
if err != nil {
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": "FAILED_PERMISSION_VALIDATION",
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
|
||||
err = os.Chmod(path, os.FileMode(value))
|
||||
|
||||
if err != nil {
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": "FAILED_PERMISSION_WRITE",
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": "SUCCESS_PERMISSION_WRITE",
|
||||
"payload": map[string]any{
|
||||
"path": path,
|
||||
"permission": permission,
|
||||
"mode": "write",
|
||||
"updated": true,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,507 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Hash
|
||||
|
|
||||
| Purpose:
|
||||
| - Generate and verify cryptographic hash values using standard or
|
||||
| salted hashing methods.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use for deterministic hashing workflows.
|
||||
| - Use for salted hashing workflows requiring verification support.
|
||||
| - Use for integrity verification and fingerprint generation.
|
||||
| - Accept exactly two primary parameters: type and config.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimHash("calculate", config)
|
||||
| - ObrimHash("compare", config)
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package hash
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"go/module/essential/visible/service/helper/log"
|
||||
"go/module/essential/visible/service/helper/retriever"
|
||||
"go/module/essential/visible/service/helper/status"
|
||||
)
|
||||
|
||||
// ObrimHash processes hash generation and verification requests.
|
||||
func ObrimHash(
|
||||
hashType string,
|
||||
config map[string]any,
|
||||
) map[string]any {
|
||||
status.ObrimStatus("INFO", "Hash utility execution started.")
|
||||
log.ObrimLog("INIT", "Hash utility execution started.")
|
||||
|
||||
_, _ = retriever.ObrimRetriever(
|
||||
"json",
|
||||
map[string]any{
|
||||
"resource": "framework/metadata",
|
||||
"path": "name",
|
||||
},
|
||||
)
|
||||
|
||||
if !obrimHashValidateType(hashType) {
|
||||
status.ObrimStatus("ERROR", "Invalid hash type.")
|
||||
log.ObrimLog("ERROR", "Invalid hash type.")
|
||||
return obrimHashBuildErrorPayload("FAILED_INVALID_TYPE")
|
||||
}
|
||||
|
||||
if !obrimHashValidateConfig(hashType, config) {
|
||||
status.ObrimStatus("ERROR", "Invalid configuration.")
|
||||
log.ObrimLog("ERROR", "Invalid configuration.")
|
||||
return obrimHashBuildErrorPayload("FAILED_INVALID_CONFIG")
|
||||
}
|
||||
|
||||
mode := config["mode"].(string)
|
||||
|
||||
if !obrimHashValidateMode(mode) {
|
||||
status.ObrimStatus("ERROR", "Invalid mode.")
|
||||
log.ObrimLog("ERROR", "Invalid mode.")
|
||||
return obrimHashBuildErrorPayload("FAILED_INVALID_MODE")
|
||||
}
|
||||
|
||||
algorithm := config["algorithm"].(string)
|
||||
|
||||
if !obrimHashValidateAlgorithm(mode, algorithm) {
|
||||
status.ObrimStatus("ERROR", "Invalid algorithm.")
|
||||
log.ObrimLog("ERROR", "Invalid algorithm.")
|
||||
return obrimHashBuildErrorPayload("FAILED_INVALID_ALGORITHM")
|
||||
}
|
||||
|
||||
switch hashType {
|
||||
case "calculate":
|
||||
return obrimHashCalculate(config)
|
||||
|
||||
case "compare":
|
||||
return obrimHashCompare(config)
|
||||
|
||||
default:
|
||||
return obrimHashBuildErrorPayload("FAILED_INVALID_TYPE")
|
||||
}
|
||||
}
|
||||
|
||||
// obrimHashValidateType validates operation type.
|
||||
func obrimHashValidateType(hashType string) bool {
|
||||
switch hashType {
|
||||
case "calculate", "compare":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// obrimHashValidateMode validates hashing mode.
|
||||
func obrimHashValidateMode(mode string) bool {
|
||||
switch mode {
|
||||
case "standard", "salted":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// obrimHashValidateConfig validates configuration keys and values.
|
||||
func obrimHashValidateConfig(
|
||||
hashType string,
|
||||
config map[string]any,
|
||||
) bool {
|
||||
if config == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Mutable variable holding supported keys.
|
||||
supportedKeys := map[string]bool{
|
||||
"mode": true,
|
||||
"algorithm": true,
|
||||
"value": true,
|
||||
"hash": true,
|
||||
"salt": true,
|
||||
}
|
||||
|
||||
for key := range config {
|
||||
if !supportedKeys[key] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
modeValue, modeExists := config["mode"]
|
||||
algorithmValue, algorithmExists := config["algorithm"]
|
||||
valueValue, valueExists := config["value"]
|
||||
|
||||
if !modeExists || !algorithmExists || !valueExists {
|
||||
return false
|
||||
}
|
||||
|
||||
mode, modeOK := modeValue.(string)
|
||||
algorithm, algorithmOK := algorithmValue.(string)
|
||||
value, valueOK := valueValue.(string)
|
||||
|
||||
if !modeOK || !algorithmOK || !valueOK {
|
||||
return false
|
||||
}
|
||||
|
||||
if mode == "" || algorithm == "" || value == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if hashType == "calculate" {
|
||||
if mode == "standard" {
|
||||
if _, exists := config["salt"]; exists {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if hashType == "compare" {
|
||||
hashValue, hashExists := config["hash"]
|
||||
|
||||
if !hashExists {
|
||||
return false
|
||||
}
|
||||
|
||||
hashString, hashOK := hashValue.(string)
|
||||
|
||||
if !hashOK || hashString == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if mode == "standard" {
|
||||
if _, exists := config["salt"]; exists {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if mode == "salted" {
|
||||
saltValue, saltExists := config["salt"]
|
||||
|
||||
if !saltExists {
|
||||
return false
|
||||
}
|
||||
|
||||
saltString, saltOK := saltValue.(string)
|
||||
|
||||
if !saltOK || saltString == "" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// obrimHashValidateAlgorithm validates hashing algorithm selection.
|
||||
func obrimHashValidateAlgorithm(
|
||||
mode string,
|
||||
algorithm string,
|
||||
) bool {
|
||||
if mode == "standard" {
|
||||
switch algorithm {
|
||||
case "sha256", "sha512":
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if mode == "salted" {
|
||||
switch algorithm {
|
||||
case "salted_sha256", "salted_sha512":
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// obrimHashGenerateHash executes the selected hashing algorithm.
|
||||
func obrimHashGenerateHash(
|
||||
algorithm string,
|
||||
value string,
|
||||
salt string,
|
||||
) (string, bool) {
|
||||
switch algorithm {
|
||||
case "sha256":
|
||||
sum := sha256.Sum256([]byte(value))
|
||||
return hex.EncodeToString(sum[:]), true
|
||||
|
||||
case "sha512":
|
||||
sum := sha512.Sum512([]byte(value))
|
||||
return hex.EncodeToString(sum[:]), true
|
||||
|
||||
case "salted_sha256":
|
||||
sum := sha256.Sum256([]byte(value + salt))
|
||||
return hex.EncodeToString(sum[:]), true
|
||||
|
||||
case "salted_sha512":
|
||||
sum := sha512.Sum512([]byte(value + salt))
|
||||
return hex.EncodeToString(sum[:]), true
|
||||
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
// obrimHashBuildSuccessPayload constructs success response payloads.
|
||||
func obrimHashBuildSuccessPayload(
|
||||
code string,
|
||||
payload map[string]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,
|
||||
}
|
||||
}
|
||||
|
||||
// obrimHashCalculate processes hash generation requests.
|
||||
func obrimHashCalculate(
|
||||
config map[string]any,
|
||||
) map[string]any {
|
||||
mode := config["mode"].(string)
|
||||
|
||||
switch mode {
|
||||
case "standard":
|
||||
return obrimHashCalculateStandard(config)
|
||||
|
||||
case "salted":
|
||||
return obrimHashCalculateSalted(config)
|
||||
|
||||
default:
|
||||
return obrimHashBuildErrorPayload("FAILED_INVALID_MODE")
|
||||
}
|
||||
}
|
||||
|
||||
// obrimHashCalculateStandard generates a deterministic hash.
|
||||
func obrimHashCalculateStandard(
|
||||
config map[string]any,
|
||||
) map[string]any {
|
||||
algorithm := config["algorithm"].(string)
|
||||
value := config["value"].(string)
|
||||
|
||||
hashValue, success := obrimHashGenerateHash(
|
||||
algorithm,
|
||||
value,
|
||||
"",
|
||||
)
|
||||
|
||||
if !success {
|
||||
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
|
||||
}
|
||||
|
||||
payload := map[string]any{
|
||||
"algorithm": algorithm,
|
||||
"hash": hashValue,
|
||||
}
|
||||
|
||||
status.ObrimStatus("SUCCESS", "Hash generated.")
|
||||
log.ObrimLog("SUCCESS", "Standard hash generated.")
|
||||
|
||||
return obrimHashBuildSuccessPayload(
|
||||
"SUCCESS_CALCULATE_STANDARD",
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimHashCalculateSalted generates a salted hash and salt pair.
|
||||
func obrimHashCalculateSalted(
|
||||
config map[string]any,
|
||||
) map[string]any {
|
||||
algorithm := config["algorithm"].(string)
|
||||
value := config["value"].(string)
|
||||
|
||||
// Mutable variable holding salt value.
|
||||
saltValue := ""
|
||||
|
||||
if suppliedSalt, exists := config["salt"]; exists {
|
||||
saltString, ok := suppliedSalt.(string)
|
||||
|
||||
if !ok || saltString == "" {
|
||||
return obrimHashBuildErrorPayload("FAILED_INVALID_SALT")
|
||||
}
|
||||
|
||||
saltValue = saltString
|
||||
} else {
|
||||
generatedSalt, success := obrimHashGenerateSalt()
|
||||
|
||||
if !success {
|
||||
return obrimHashBuildErrorPayload("FAILED_SALT_GENERATION")
|
||||
}
|
||||
|
||||
saltValue = generatedSalt
|
||||
}
|
||||
|
||||
hashValue, success := obrimHashGenerateHash(
|
||||
algorithm,
|
||||
value,
|
||||
saltValue,
|
||||
)
|
||||
|
||||
if !success {
|
||||
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
|
||||
}
|
||||
|
||||
payload := map[string]any{
|
||||
"algorithm": algorithm,
|
||||
"hash": hashValue,
|
||||
"salt": saltValue,
|
||||
}
|
||||
|
||||
status.ObrimStatus("SUCCESS", "Salted hash generated.")
|
||||
log.ObrimLog("SUCCESS", "Salted hash generated.")
|
||||
|
||||
return obrimHashBuildSuccessPayload(
|
||||
"SUCCESS_CALCULATE_SALTED",
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimHashGenerateSalt generates a cryptographically secure salt.
|
||||
func obrimHashGenerateSalt() (string, bool) {
|
||||
// Mutable variable holding salt bytes.
|
||||
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 map[string]any,
|
||||
) map[string]any {
|
||||
mode := config["mode"].(string)
|
||||
|
||||
switch mode {
|
||||
case "standard":
|
||||
return obrimHashCompareStandard(config)
|
||||
|
||||
case "salted":
|
||||
return obrimHashCompareSalted(config)
|
||||
|
||||
default:
|
||||
return obrimHashBuildErrorPayload("FAILED_INVALID_MODE")
|
||||
}
|
||||
}
|
||||
|
||||
// obrimHashCompareStandard regenerates a standard hash for verification.
|
||||
func obrimHashCompareStandard(
|
||||
config map[string]any,
|
||||
) map[string]any {
|
||||
algorithm := config["algorithm"].(string)
|
||||
value := config["value"].(string)
|
||||
hashValue := config["hash"].(string)
|
||||
|
||||
regeneratedHash, success := obrimHashGenerateHash(
|
||||
algorithm,
|
||||
value,
|
||||
"",
|
||||
)
|
||||
|
||||
if !success {
|
||||
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
|
||||
}
|
||||
|
||||
matched := obrimHashVerify(
|
||||
regeneratedHash,
|
||||
hashValue,
|
||||
)
|
||||
|
||||
payload := map[string]any{
|
||||
"algorithm": algorithm,
|
||||
"matched": matched,
|
||||
"hash": hashValue,
|
||||
}
|
||||
|
||||
return obrimHashBuildSuccessPayload(
|
||||
"SUCCESS_COMPARE_STANDARD",
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimHashCompareSalted regenerates a salted hash for verification.
|
||||
func obrimHashCompareSalted(
|
||||
config map[string]any,
|
||||
) map[string]any {
|
||||
algorithm := config["algorithm"].(string)
|
||||
value := config["value"].(string)
|
||||
hashValue := config["hash"].(string)
|
||||
saltValue := config["salt"].(string)
|
||||
|
||||
regeneratedHash, success := obrimHashGenerateHash(
|
||||
algorithm,
|
||||
value,
|
||||
saltValue,
|
||||
)
|
||||
|
||||
if !success {
|
||||
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
|
||||
}
|
||||
|
||||
matched := obrimHashVerify(
|
||||
regeneratedHash,
|
||||
hashValue,
|
||||
)
|
||||
|
||||
payload := map[string]any{
|
||||
"algorithm": algorithm,
|
||||
"matched": matched,
|
||||
"hash": hashValue,
|
||||
"salt": saltValue,
|
||||
}
|
||||
|
||||
return obrimHashBuildSuccessPayload(
|
||||
"SUCCESS_COMPARE_SALTED",
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimHashVerify compares regenerated and supplied hash values.
|
||||
func obrimHashVerify(
|
||||
regeneratedHash string,
|
||||
suppliedHash string,
|
||||
) bool {
|
||||
return strings.Compare(
|
||||
regeneratedHash,
|
||||
suppliedHash,
|
||||
) == 0
|
||||
}
|
||||
@ -0,0 +1,348 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Key
|
||||
|
|
||||
| Purpose:
|
||||
| - Generate cryptographic key material using a type-driven dispatch model.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use explicit configuration values only.
|
||||
| - Validate all inputs before generation.
|
||||
| - Reject unsupported or irrelevant configuration fields.
|
||||
| - Use centralized dispatch for workflow execution.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimKey("symmetric", map[string]any{
|
||||
| "algorithm": "aes",
|
||||
| "key_size": 256,
|
||||
| })
|
||||
|
|
||||
| - ObrimKey("asymmetric", map[string]any{
|
||||
| "algorithm": "ecc",
|
||||
| })
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package key
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go/module/essential/visible/service/helper/log"
|
||||
"go/module/essential/visible/service/helper/status"
|
||||
)
|
||||
|
||||
const (
|
||||
obrimKeyTypeSymmetric = "symmetric"
|
||||
obrimKeyTypeAsymmetric = "asymmetric"
|
||||
|
||||
obrimKeyAlgorithmAES = "aes"
|
||||
obrimKeyAlgorithmECC = "ecc"
|
||||
|
||||
obrimKeyCurveEdDSA = "eddsa"
|
||||
)
|
||||
|
||||
// ObrimKey dispatches key generation requests and orchestrates validation, generation, and response construction.
|
||||
func ObrimKey(keyType string, config map[string]any) map[string]any {
|
||||
log.ObrimLog("INIT", "Key generation request received.")
|
||||
status.ObrimStatus("INFO", "Validating key generation request.")
|
||||
|
||||
if response := obrimKeyValidate(keyType, config); response != nil {
|
||||
return response
|
||||
}
|
||||
|
||||
return obrimKeyDispatch(keyType, config)
|
||||
}
|
||||
|
||||
// obrimKeyValidate validates common request structure and schema integrity.
|
||||
func obrimKeyValidate(keyType string, config map[string]any) map[string]any {
|
||||
if strings.TrimSpace(keyType) == "" {
|
||||
return obrimKeyBuildError("FAILED_TYPE_REQUIRED")
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
return obrimKeyBuildError("FAILED_CONFIG_REQUIRED")
|
||||
}
|
||||
|
||||
normalizedType := strings.ToLower(strings.TrimSpace(keyType))
|
||||
|
||||
switch normalizedType {
|
||||
case obrimKeyTypeSymmetric:
|
||||
return obrimKeyValidateSymmetricConfig(config)
|
||||
|
||||
case obrimKeyTypeAsymmetric:
|
||||
return obrimKeyValidateAsymmetricConfig(config)
|
||||
|
||||
default:
|
||||
return obrimKeyBuildError("FAILED_UNSUPPORTED_TYPE")
|
||||
}
|
||||
}
|
||||
|
||||
// obrimKeyDispatch routes execution to the appropriate cryptographic workflow.
|
||||
func obrimKeyDispatch(keyType string, config map[string]any) map[string]any {
|
||||
normalizedType := strings.ToLower(strings.TrimSpace(keyType))
|
||||
|
||||
switch normalizedType {
|
||||
case obrimKeyTypeSymmetric:
|
||||
return obrimKeyGenerateSymmetric(config)
|
||||
|
||||
case obrimKeyTypeAsymmetric:
|
||||
return obrimKeyGenerateAsymmetric(config)
|
||||
|
||||
default:
|
||||
return obrimKeyBuildError("FAILED_UNSUPPORTED_TYPE")
|
||||
}
|
||||
}
|
||||
|
||||
// obrimKeyValidateSymmetricConfig validates symmetric configuration values.
|
||||
func obrimKeyValidateSymmetricConfig(config map[string]any) map[string]any {
|
||||
if len(config) != 2 {
|
||||
return obrimKeyBuildError("FAILED_INVALID_CONFIGURATION")
|
||||
}
|
||||
|
||||
for key := range config {
|
||||
if key != "algorithm" && key != "key_size" {
|
||||
return obrimKeyBuildError("FAILED_UNSUPPORTED_CONFIGURATION_FIELD")
|
||||
}
|
||||
}
|
||||
|
||||
algorithmValue, exists := config["algorithm"]
|
||||
if !exists {
|
||||
return obrimKeyBuildError("FAILED_ALGORITHM_REQUIRED")
|
||||
}
|
||||
|
||||
algorithm, ok := algorithmValue.(string)
|
||||
if !ok {
|
||||
return obrimKeyBuildError("FAILED_INVALID_ALGORITHM")
|
||||
}
|
||||
|
||||
normalizedConfig := obrimKeyNormalizeSymmetricConfig(config)
|
||||
|
||||
if strings.ToLower(strings.TrimSpace(algorithm)) != obrimKeyAlgorithmAES {
|
||||
return obrimKeyBuildError("FAILED_UNSUPPORTED_ALGORITHM")
|
||||
}
|
||||
|
||||
keySizeValue, exists := normalizedConfig["key_size"]
|
||||
if !exists {
|
||||
return obrimKeyBuildError("FAILED_KEY_SIZE_REQUIRED")
|
||||
}
|
||||
|
||||
keySize, ok := keySizeValue.(int)
|
||||
if !ok {
|
||||
return obrimKeyBuildError("FAILED_INVALID_KEY_SIZE")
|
||||
}
|
||||
|
||||
if keySize != 128 && keySize != 192 && keySize != 256 {
|
||||
return obrimKeyBuildError("FAILED_UNSUPPORTED_KEY_SIZE")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// obrimKeyValidateAsymmetricConfig validates asymmetric configuration values.
|
||||
func obrimKeyValidateAsymmetricConfig(config map[string]any) map[string]any {
|
||||
if len(config) != 1 {
|
||||
return obrimKeyBuildError("FAILED_INVALID_CONFIGURATION")
|
||||
}
|
||||
|
||||
for key := range config {
|
||||
if key != "algorithm" {
|
||||
return obrimKeyBuildError("FAILED_UNSUPPORTED_CONFIGURATION_FIELD")
|
||||
}
|
||||
}
|
||||
|
||||
algorithmValue, exists := config["algorithm"]
|
||||
if !exists {
|
||||
return obrimKeyBuildError("FAILED_ALGORITHM_REQUIRED")
|
||||
}
|
||||
|
||||
algorithm, ok := algorithmValue.(string)
|
||||
if !ok {
|
||||
return obrimKeyBuildError("FAILED_INVALID_ALGORITHM")
|
||||
}
|
||||
|
||||
if strings.ToLower(strings.TrimSpace(algorithm)) != obrimKeyAlgorithmECC {
|
||||
return obrimKeyBuildError("FAILED_UNSUPPORTED_ALGORITHM")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// obrimKeyGenerateSymmetric generates symmetric key material.
|
||||
func obrimKeyGenerateSymmetric(config map[string]any) map[string]any {
|
||||
log.ObrimLog("INIT", "Generating symmetric key material.")
|
||||
|
||||
normalizedConfig := obrimKeyNormalizeSymmetricConfig(config)
|
||||
|
||||
payload, err := obrimKeyGenerateAES(normalizedConfig)
|
||||
if err != nil {
|
||||
log.ObrimLog("ERROR", err.Error())
|
||||
return obrimKeyBuildError("FAILED_KEY_GENERATION")
|
||||
}
|
||||
|
||||
log.ObrimLog("SUCCESS", "Symmetric key material generated.")
|
||||
status.ObrimStatus("SUCCESS", "Key generation completed.")
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": "SUCCESS_KEY_GENERATED",
|
||||
"payload": payload,
|
||||
}
|
||||
}
|
||||
|
||||
// obrimKeyGenerateAES generates AES key material.
|
||||
func obrimKeyGenerateAES(config map[string]any) (map[string]any, error) {
|
||||
// Mutable variable holding key size.
|
||||
keySize := config["key_size"].(int)
|
||||
|
||||
// Mutable variable holding key bytes.
|
||||
keyBytes := make([]byte, keySize/8)
|
||||
|
||||
if _, err := rand.Read(keyBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := aes.NewCipher(keyBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payload := map[string]any{
|
||||
"type": obrimKeyTypeSymmetric,
|
||||
"algorithm": obrimKeyAlgorithmAES,
|
||||
"key_size": keySize,
|
||||
"key_material": base64.StdEncoding.EncodeToString(keyBytes),
|
||||
"generated_at": time.Now().UTC().Format(time.RFC3339),
|
||||
}
|
||||
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// obrimKeyNormalizeSymmetricConfig normalizes symmetric configuration values.
|
||||
func obrimKeyNormalizeSymmetricConfig(config map[string]any) map[string]any {
|
||||
normalized := map[string]any{}
|
||||
|
||||
if value, exists := config["algorithm"]; exists {
|
||||
if algorithm, ok := value.(string); ok {
|
||||
normalized["algorithm"] = strings.ToLower(strings.TrimSpace(algorithm))
|
||||
}
|
||||
}
|
||||
|
||||
if value, exists := config["key_size"]; exists {
|
||||
switch typed := value.(type) {
|
||||
case int:
|
||||
normalized["key_size"] = typed
|
||||
case int8:
|
||||
normalized["key_size"] = int(typed)
|
||||
case int16:
|
||||
normalized["key_size"] = int(typed)
|
||||
case int32:
|
||||
normalized["key_size"] = int(typed)
|
||||
case int64:
|
||||
normalized["key_size"] = int(typed)
|
||||
case float32:
|
||||
normalized["key_size"] = int(typed)
|
||||
case float64:
|
||||
normalized["key_size"] = int(typed)
|
||||
}
|
||||
}
|
||||
|
||||
return normalized
|
||||
}
|
||||
|
||||
// obrimKeyGenerateAsymmetric generates asymmetric key material.
|
||||
func obrimKeyGenerateAsymmetric(config map[string]any) map[string]any {
|
||||
log.ObrimLog("INIT", "Generating asymmetric key material.")
|
||||
|
||||
normalizedConfig := obrimKeyNormalizeAsymmetricConfig(config)
|
||||
|
||||
payload, err := obrimKeyGenerateECC(normalizedConfig)
|
||||
if err != nil {
|
||||
log.ObrimLog("ERROR", err.Error())
|
||||
return obrimKeyBuildError("FAILED_KEY_GENERATION")
|
||||
}
|
||||
|
||||
log.ObrimLog("SUCCESS", "Asymmetric key material generated.")
|
||||
status.ObrimStatus("SUCCESS", "Key generation completed.")
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": "SUCCESS_KEY_GENERATED",
|
||||
"payload": payload,
|
||||
}
|
||||
}
|
||||
|
||||
// obrimKeyGenerateECC generates ECC key pair material.
|
||||
func obrimKeyGenerateECC(config map[string]any) (map[string]any, error) {
|
||||
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payload := 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),
|
||||
}
|
||||
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// obrimKeyNormalizeAsymmetricConfig normalizes asymmetric configuration values.
|
||||
func obrimKeyNormalizeAsymmetricConfig(config map[string]any) map[string]any {
|
||||
normalized := map[string]any{}
|
||||
|
||||
if value, exists := config["algorithm"]; exists {
|
||||
if algorithm, ok := value.(string); ok {
|
||||
normalized["algorithm"] = strings.ToLower(strings.TrimSpace(algorithm))
|
||||
}
|
||||
}
|
||||
|
||||
return normalized
|
||||
}
|
||||
|
||||
// obrimKeyBuildPayload constructs standardized success payloads.
|
||||
func obrimKeyBuildPayload(payload map[string]any) map[string]any {
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": "SUCCESS",
|
||||
"payload": payload,
|
||||
}
|
||||
}
|
||||
|
||||
// obrimKeyBuildError constructs standardized error responses.
|
||||
func obrimKeyBuildError(code string) map[string]any {
|
||||
log.ObrimLog("ERROR", fmt.Sprintf("Key generation failed: %s", code))
|
||||
status.ObrimStatus("ERROR", code)
|
||||
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": code,
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,259 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Log
|
||||
|
|
||||
| Purpose:
|
||||
| - Provide framework-level structured plaintext logging with
|
||||
| deterministic timestamping and persistent platform-aware storage.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use for framework and software logging.
|
||||
| - Writes append-only UTF-8 log entries.
|
||||
| - Preserves existing log content.
|
||||
| - Uses application metadata to determine storage location.
|
||||
| - Does not implement rotation, retention, archival, or compression.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimLog("SERVICE/FEATURE", "Operation completed.")
|
||||
| - ObrimLog("HELPER/LOG", "Log initialized.")
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go/module/essential/visible/service/helper/retriever"
|
||||
)
|
||||
|
||||
// ObrimLog writes a structured log entry.
|
||||
func ObrimLog(label string, message string) {
|
||||
applicationName := obrimLogApplicationResolve()
|
||||
|
||||
timestamp := obrimLogTimestampGenerate()
|
||||
|
||||
entry := obrimLogEntryBuild(
|
||||
timestamp,
|
||||
label,
|
||||
message,
|
||||
)
|
||||
|
||||
logDirectory := obrimLogDirectoryResolve(applicationName)
|
||||
|
||||
logFile := obrimLogFileResolve(
|
||||
logDirectory,
|
||||
applicationName,
|
||||
)
|
||||
|
||||
if !obrimLogFileEnsure(logDirectory, logFile) {
|
||||
return
|
||||
}
|
||||
|
||||
obrimLogWrite(logFile, entry)
|
||||
}
|
||||
|
||||
// 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",
|
||||
timestamp,
|
||||
label,
|
||||
message,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimLogApplicationResolve resolves the application name.
|
||||
func obrimLogApplicationResolve() string {
|
||||
value := retriever.ObrimRetriever(
|
||||
"json",
|
||||
map[string]any{
|
||||
"resource": "application/metadata",
|
||||
"path": "application.lower",
|
||||
},
|
||||
)
|
||||
|
||||
name := strings.TrimSpace(fmt.Sprintf("%v", value))
|
||||
|
||||
if name == "" {
|
||||
return "application"
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
// obrimLogDirectoryResolve resolves platform-specific log directory paths.
|
||||
func obrimLogDirectoryResolve(applicationName string) string {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
return obrimLogDirectoryResolveWindows(applicationName)
|
||||
|
||||
case "darwin":
|
||||
return obrimLogDirectoryResolveMacOS(applicationName)
|
||||
|
||||
default:
|
||||
return obrimLogDirectoryResolveLinux(applicationName)
|
||||
}
|
||||
}
|
||||
|
||||
// obrimLogDirectoryResolveLinux resolves Linux log directory paths.
|
||||
func obrimLogDirectoryResolveLinux(applicationName string) string {
|
||||
xdgStateHome := strings.TrimSpace(os.Getenv("XDG_STATE_HOME"))
|
||||
|
||||
if xdgStateHome != "" {
|
||||
return filepath.Join(
|
||||
xdgStateHome,
|
||||
"."+applicationName,
|
||||
"logs",
|
||||
)
|
||||
}
|
||||
|
||||
homeDirectory, errorValue := os.UserHomeDir()
|
||||
|
||||
if errorValue != nil {
|
||||
return filepath.Join(
|
||||
".",
|
||||
"."+applicationName,
|
||||
"logs",
|
||||
)
|
||||
}
|
||||
|
||||
return filepath.Join(
|
||||
homeDirectory,
|
||||
".local",
|
||||
"state",
|
||||
"."+applicationName,
|
||||
"logs",
|
||||
)
|
||||
}
|
||||
|
||||
// obrimLogDirectoryResolveWindows resolves Windows log directory paths.
|
||||
func obrimLogDirectoryResolveWindows(applicationName string) string {
|
||||
localApplicationData := strings.TrimSpace(
|
||||
os.Getenv("LOCALAPPDATA"),
|
||||
)
|
||||
|
||||
if localApplicationData == "" {
|
||||
homeDirectory, errorValue := os.UserHomeDir()
|
||||
|
||||
if errorValue == nil {
|
||||
localApplicationData = homeDirectory
|
||||
}
|
||||
}
|
||||
|
||||
return filepath.Join(
|
||||
localApplicationData,
|
||||
applicationName,
|
||||
"Logs",
|
||||
)
|
||||
}
|
||||
|
||||
// obrimLogDirectoryResolveMacOS resolves macOS log directory paths.
|
||||
func obrimLogDirectoryResolveMacOS(applicationName string) string {
|
||||
homeDirectory, errorValue := os.UserHomeDir()
|
||||
|
||||
if errorValue != nil {
|
||||
return filepath.Join(
|
||||
".",
|
||||
"."+applicationName,
|
||||
)
|
||||
}
|
||||
|
||||
return filepath.Join(
|
||||
homeDirectory,
|
||||
"Library",
|
||||
"Logs",
|
||||
"."+applicationName,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimLogFileResolve resolves platform-specific log file paths.
|
||||
func obrimLogFileResolve(
|
||||
logDirectory string,
|
||||
applicationName string,
|
||||
) string {
|
||||
return filepath.Join(
|
||||
logDirectory,
|
||||
applicationName+".log",
|
||||
)
|
||||
}
|
||||
|
||||
// obrimLogFileEnsure creates and verifies required log directories and files.
|
||||
func obrimLogFileEnsure(
|
||||
logDirectory string,
|
||||
logFile string,
|
||||
) bool {
|
||||
errorValue := os.MkdirAll(
|
||||
logDirectory,
|
||||
0755,
|
||||
)
|
||||
|
||||
if errorValue != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
fileHandle, errorValue := os.OpenFile(
|
||||
logFile,
|
||||
os.O_CREATE,
|
||||
0644,
|
||||
)
|
||||
|
||||
if errorValue != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_ = fileHandle.Close()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// obrimLogWrite persists log entries to the filesystem.
|
||||
func obrimLogWrite(
|
||||
logFile string,
|
||||
entry string,
|
||||
) {
|
||||
fileHandle, errorValue := os.OpenFile(
|
||||
logFile,
|
||||
os.O_CREATE|os.O_WRONLY|os.O_APPEND,
|
||||
0644,
|
||||
)
|
||||
|
||||
if errorValue != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer fileHandle.Close()
|
||||
|
||||
_, _ = fileHandle.WriteString(entry)
|
||||
}
|
||||
@ -0,0 +1,500 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Marker
|
||||
|
|
||||
| Purpose:
|
||||
| - Provide a unified utility for generating unique markers through
|
||||
| time-based, random, and encoded generation strategies.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use ObrimMarker as the single entry point.
|
||||
| - Validate marker type before processing.
|
||||
| - Maintain standardized response structures.
|
||||
| - Use isolated workflows for each marker type.
|
||||
| - Support future marker extensions without modifying existing workflows.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimMarker("time", map[string]any{})
|
||||
| - ObrimMarker("random", map[string]any{"length":16})
|
||||
| - ObrimMarker("encoded", map[string]any{"data":"example"})
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package marker
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go/module/essential/visible/service/helper/log"
|
||||
"go/module/essential/visible/service/helper/status"
|
||||
)
|
||||
|
||||
const (
|
||||
obrimMarkerTypeTime = "time"
|
||||
obrimMarkerTypeRandom = "random"
|
||||
obrimMarkerTypeEncoded = "encoded"
|
||||
|
||||
obrimMarkerDefaultEpoch int64 = 0
|
||||
obrimMarkerDefaultLength = 16
|
||||
|
||||
obrimMarkerDefaultCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
)
|
||||
|
||||
// ObrimMarker routes marker generation requests and returns a standardized marker response.
|
||||
func ObrimMarker(markerType string, config map[string]any) map[string]any {
|
||||
log.ObrimLog("INIT", "Marker utility initialized.")
|
||||
status.ObrimStatus("INFO", "Processing marker generation request.")
|
||||
|
||||
if !obrimMarkerValidateType(markerType) {
|
||||
log.ObrimLog("ERROR", "Unsupported marker type.")
|
||||
status.ObrimStatus("ERROR", "Unsupported marker type.")
|
||||
|
||||
return obrimMarkerBuildResponse(
|
||||
false,
|
||||
"FAILED_UNSUPPORTED_TYPE",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
response := obrimMarkerRoute(markerType, config)
|
||||
|
||||
if statusValue, ok := response["status"].(bool); ok && statusValue {
|
||||
log.ObrimLog("SUCCESS", "Marker generated successfully.")
|
||||
status.ObrimStatus("SUCCESS", "Marker generated successfully.")
|
||||
} else {
|
||||
log.ObrimLog("ERROR", "Marker generation failed.")
|
||||
status.ObrimStatus("ERROR", "Marker generation failed.")
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
// obrimMarkerValidateType validates supported marker generation types.
|
||||
func obrimMarkerValidateType(markerType string) bool {
|
||||
switch markerType {
|
||||
case obrimMarkerTypeTime,
|
||||
obrimMarkerTypeRandom,
|
||||
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,
|
||||
"FAILED_UNSUPPORTED_TYPE",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// obrimMarkerBuildResponse builds standardized success and error responses.
|
||||
func obrimMarkerBuildResponse(
|
||||
statusValue bool,
|
||||
code string,
|
||||
payload any,
|
||||
) map[string]any {
|
||||
return map[string]any{
|
||||
"status": statusValue,
|
||||
"code": code,
|
||||
"payload": payload,
|
||||
}
|
||||
}
|
||||
|
||||
// obrimMarkerTime generates time-based unique markers.
|
||||
func obrimMarkerTime(config map[string]any) map[string]any {
|
||||
if err := obrimMarkerValidateTime(config); err != nil {
|
||||
return obrimMarkerBuildResponse(
|
||||
false,
|
||||
"FAILED_VALIDATION",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
// Mutable variable storing effective epoch.
|
||||
var epoch int64 = obrimMarkerDefaultEpoch
|
||||
|
||||
if value, ok := config["epoch"]; ok {
|
||||
switch typed := value.(type) {
|
||||
case int64:
|
||||
epoch = typed
|
||||
case int:
|
||||
epoch = int64(typed)
|
||||
case float64:
|
||||
epoch = int64(typed)
|
||||
}
|
||||
}
|
||||
|
||||
// Mutable variable storing instance identifier.
|
||||
var instance string
|
||||
|
||||
if value, ok := config["instance"].(string); ok {
|
||||
instance = value
|
||||
}
|
||||
|
||||
marker, err := obrimMarkerTimeGenerate(epoch, instance)
|
||||
if err != nil {
|
||||
return obrimMarkerBuildResponse(
|
||||
false,
|
||||
"FAILED_GENERATION",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
payload := map[string]any{
|
||||
"marker": marker,
|
||||
"epoch": epoch,
|
||||
"instance": instance,
|
||||
}
|
||||
|
||||
return obrimMarkerBuildResponse(
|
||||
true,
|
||||
"SUCCESS_TIME_GENERATED",
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimMarkerValidateTime validates time marker configuration parameters.
|
||||
func obrimMarkerValidateTime(config map[string]any) error {
|
||||
if value, ok := config["epoch"]; ok {
|
||||
switch typed := value.(type) {
|
||||
case int64:
|
||||
if typed < 0 {
|
||||
return fmt.Errorf("invalid epoch")
|
||||
}
|
||||
case int:
|
||||
if typed < 0 {
|
||||
return fmt.Errorf("invalid epoch")
|
||||
}
|
||||
case float64:
|
||||
if typed < 0 {
|
||||
return fmt.Errorf("invalid epoch")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("invalid epoch type")
|
||||
}
|
||||
}
|
||||
|
||||
if value, ok := config["instance"]; ok {
|
||||
instance, valid := value.(string)
|
||||
if !valid || strings.TrimSpace(instance) == "" {
|
||||
return fmt.Errorf("invalid instance")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// obrimMarkerTimeGenerate produces the final time-based marker value.
|
||||
func obrimMarkerTimeGenerate(epoch int64, instance string) (string, error) {
|
||||
// Mutable variable storing current timestamp.
|
||||
var currentTimestamp int64 = time.Now().UnixMilli()
|
||||
|
||||
// Mutable variable storing relative timestamp.
|
||||
var relativeTimestamp int64 = currentTimestamp - epoch
|
||||
|
||||
if relativeTimestamp < 0 {
|
||||
return "", fmt.Errorf("invalid timestamp")
|
||||
}
|
||||
|
||||
source := fmt.Sprintf("%d:%s", relativeTimestamp, instance)
|
||||
|
||||
hash := sha256.Sum256([]byte(source))
|
||||
|
||||
return strings.ToUpper(base64.RawURLEncoding.EncodeToString(hash[:])), nil
|
||||
}
|
||||
|
||||
// obrimMarkerRandom generates random collision-resistant markers.
|
||||
func obrimMarkerRandom(config map[string]any) map[string]any {
|
||||
if err := obrimMarkerValidateRandom(config); err != nil {
|
||||
return obrimMarkerBuildResponse(
|
||||
false,
|
||||
"FAILED_VALIDATION",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
// Mutable variable storing desired length.
|
||||
var length int = obrimMarkerDefaultLength
|
||||
|
||||
if value, ok := config["length"]; ok {
|
||||
switch typed := value.(type) {
|
||||
case int:
|
||||
length = typed
|
||||
case int64:
|
||||
length = int(typed)
|
||||
case float64:
|
||||
length = int(typed)
|
||||
}
|
||||
}
|
||||
|
||||
// Mutable variable storing charset.
|
||||
var charset string = obrimMarkerDefaultCharset
|
||||
|
||||
if value, ok := config["charset"].(string); ok {
|
||||
charset = value
|
||||
}
|
||||
|
||||
marker, err := obrimMarkerRandomGenerate(length, charset)
|
||||
if err != nil {
|
||||
return obrimMarkerBuildResponse(
|
||||
false,
|
||||
"FAILED_GENERATION",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
payload := map[string]any{
|
||||
"marker": marker,
|
||||
"length": length,
|
||||
"charset": charset,
|
||||
}
|
||||
|
||||
return obrimMarkerBuildResponse(
|
||||
true,
|
||||
"SUCCESS_RANDOM_GENERATED",
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimMarkerValidateRandom validates random marker configuration parameters.
|
||||
func obrimMarkerValidateRandom(config map[string]any) error {
|
||||
if value, ok := config["length"]; ok {
|
||||
switch typed := value.(type) {
|
||||
case int:
|
||||
if typed <= 0 {
|
||||
return fmt.Errorf("invalid length")
|
||||
}
|
||||
case int64:
|
||||
if typed <= 0 {
|
||||
return fmt.Errorf("invalid length")
|
||||
}
|
||||
case float64:
|
||||
if typed <= 0 {
|
||||
return fmt.Errorf("invalid length")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("invalid length type")
|
||||
}
|
||||
}
|
||||
|
||||
if value, ok := config["charset"]; ok {
|
||||
charset, valid := value.(string)
|
||||
|
||||
if !valid || len(charset) == 0 {
|
||||
return fmt.Errorf("invalid charset")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// obrimMarkerRandomGenerate produces the final random marker value.
|
||||
func obrimMarkerRandomGenerate(length int, charset string) (string, error) {
|
||||
// Mutable variable storing generated marker bytes.
|
||||
var markerBuilder strings.Builder
|
||||
|
||||
charsetLength := len(charset)
|
||||
|
||||
for index := 0; index < length; index++ {
|
||||
randomIndex, err := obrimMarkerRandomIndex(charsetLength)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
markerBuilder.WriteByte(charset[randomIndex])
|
||||
}
|
||||
|
||||
return markerBuilder.String(), nil
|
||||
}
|
||||
|
||||
// obrimMarkerRandomIndex generates a secure random index.
|
||||
func obrimMarkerRandomIndex(limit int) (int, error) {
|
||||
randomBytes := make([]byte, 8)
|
||||
|
||||
if _, err := rand.Read(randomBytes); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
randomValue := binary.BigEndian.Uint64(randomBytes)
|
||||
|
||||
return int(randomValue % uint64(limit)), nil
|
||||
}
|
||||
|
||||
// obrimMarkerEncoded generates deterministic encoded markers.
|
||||
func obrimMarkerEncoded(config map[string]any) map[string]any {
|
||||
if err := obrimMarkerValidateEncoded(config); err != nil {
|
||||
return obrimMarkerBuildResponse(
|
||||
false,
|
||||
"FAILED_VALIDATION",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
source := config["data"].(string)
|
||||
|
||||
// Mutable variable storing desired length.
|
||||
var length int = obrimMarkerDefaultLength
|
||||
|
||||
if value, ok := config["length"]; ok {
|
||||
switch typed := value.(type) {
|
||||
case int:
|
||||
length = typed
|
||||
case int64:
|
||||
length = int(typed)
|
||||
case float64:
|
||||
length = int(typed)
|
||||
}
|
||||
}
|
||||
|
||||
// Mutable variable storing charset.
|
||||
var charset string = obrimMarkerDefaultCharset
|
||||
|
||||
if value, ok := config["charset"].(string); ok {
|
||||
charset = value
|
||||
}
|
||||
|
||||
// Mutable variable storing optional salt.
|
||||
var salt string
|
||||
|
||||
if value, ok := config["salt"].(string); ok {
|
||||
salt = value
|
||||
}
|
||||
|
||||
marker, err := obrimMarkerEncodedGenerate(
|
||||
source,
|
||||
length,
|
||||
charset,
|
||||
salt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return obrimMarkerBuildResponse(
|
||||
false,
|
||||
"FAILED_GENERATION",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
payload := map[string]any{
|
||||
"marker": marker,
|
||||
"source": source,
|
||||
"length": length,
|
||||
}
|
||||
|
||||
return obrimMarkerBuildResponse(
|
||||
true,
|
||||
"SUCCESS_ENCODED_GENERATED",
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimMarkerValidateEncoded validates encoded marker configuration parameters.
|
||||
func obrimMarkerValidateEncoded(config map[string]any) error {
|
||||
data, ok := config["data"].(string)
|
||||
|
||||
if !ok || strings.TrimSpace(data) == "" {
|
||||
return fmt.Errorf("invalid data")
|
||||
}
|
||||
|
||||
if value, ok := config["length"]; ok {
|
||||
switch typed := value.(type) {
|
||||
case int:
|
||||
if typed <= 0 {
|
||||
return fmt.Errorf("invalid length")
|
||||
}
|
||||
case int64:
|
||||
if typed <= 0 {
|
||||
return fmt.Errorf("invalid length")
|
||||
}
|
||||
case float64:
|
||||
if typed <= 0 {
|
||||
return fmt.Errorf("invalid length")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("invalid length type")
|
||||
}
|
||||
}
|
||||
|
||||
if value, ok := config["charset"]; ok {
|
||||
charset, valid := value.(string)
|
||||
|
||||
if !valid || len(charset) == 0 {
|
||||
return fmt.Errorf("invalid charset")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// obrimMarkerEncodedGenerate produces the final encoded marker value.
|
||||
func obrimMarkerEncodedGenerate(
|
||||
source string,
|
||||
length int,
|
||||
charset string,
|
||||
salt string,
|
||||
) (string, error) {
|
||||
hash := sha256.Sum256([]byte(source + salt))
|
||||
|
||||
charsetLength := len(charset)
|
||||
|
||||
if charsetLength == 0 {
|
||||
return "", fmt.Errorf("invalid charset")
|
||||
}
|
||||
|
||||
// Mutable variable storing generated marker bytes.
|
||||
var markerBuilder strings.Builder
|
||||
|
||||
for _, value := range hash {
|
||||
index := int(math.Abs(float64(value))) % charsetLength
|
||||
markerBuilder.WriteByte(charset[index])
|
||||
|
||||
if markerBuilder.Len() >= length {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for markerBuilder.Len() < length {
|
||||
markerBuilder.WriteByte(charset[0])
|
||||
}
|
||||
|
||||
return markerBuilder.String(), nil
|
||||
}
|
||||
@ -0,0 +1,443 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Progress
|
||||
|
|
||||
| Purpose:
|
||||
| - Manage, monitor, and report task progress through standardized
|
||||
| lifecycle-aware progress tracking.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use countable progress when current and target values are available.
|
||||
| - Use uncountable progress when only activity status is available.
|
||||
| - Always provide a valid lifecycle state.
|
||||
| - Use standardized response structures for all executions.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimProgress("countable", map[string]any{
|
||||
| "state":"running",
|
||||
| "current":25,
|
||||
| "target":100,
|
||||
| })
|
||||
|
|
||||
| - ObrimProgress("uncountable", map[string]any{
|
||||
| "state":"running",
|
||||
| "placeholder":"Synchronizing resources",
|
||||
| })
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package progress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go/module/essential/visible/service/helper/log"
|
||||
"go/module/essential/visible/service/helper/status"
|
||||
)
|
||||
|
||||
const (
|
||||
obrimProgressTypeCountable = "countable"
|
||||
obrimProgressTypeUncountable = "uncountable"
|
||||
|
||||
obrimProgressStateStarted = "started"
|
||||
obrimProgressStateRunning = "running"
|
||||
obrimProgressStateCompleted = "completed"
|
||||
obrimProgressStateCanceled = "canceled"
|
||||
|
||||
obrimProgressVisualWidth = 20
|
||||
)
|
||||
|
||||
var (
|
||||
// obrimProgressStateMutex protects lifecycle transitions.
|
||||
obrimProgressStateMutex sync.Mutex
|
||||
)
|
||||
|
||||
// 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,
|
||||
"FAILED_PROGRESS_MISCONFIGURED",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
// lifecycleState stores validated lifecycle state.
|
||||
lifecycleState := strings.ToLower(fmt.Sprintf("%v", config["state"]))
|
||||
|
||||
if !obrimProgressHandleState(lifecycleState) {
|
||||
return obrimProgressBuildResponse(
|
||||
false,
|
||||
"FAILED_PROGRESS_MISCONFIGURED",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
switch progressType {
|
||||
case obrimProgressTypeCountable:
|
||||
return obrimProgressCountable(config)
|
||||
|
||||
case obrimProgressTypeUncountable:
|
||||
return obrimProgressUncountable(config)
|
||||
|
||||
default:
|
||||
return obrimProgressBuildResponse(
|
||||
false,
|
||||
"FAILED_PROGRESS_MISCONFIGURED",
|
||||
nil,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// obrimProgressValidate validates input parameters and configuration consistency.
|
||||
func obrimProgressValidate(progressType string, config map[string]any) bool {
|
||||
if strings.TrimSpace(progressType) == "" {
|
||||
log.ObrimLog("ERROR", "Progress type is missing.")
|
||||
status.ObrimStatus("ERROR", "Progress type is required.")
|
||||
return false
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
log.ObrimLog("ERROR", "Progress configuration is missing.")
|
||||
status.ObrimStatus("ERROR", "Progress configuration is required.")
|
||||
return false
|
||||
}
|
||||
|
||||
// lifecycleState stores lifecycle state.
|
||||
lifecycleState := strings.ToLower(fmt.Sprintf("%v", config["state"]))
|
||||
|
||||
switch lifecycleState {
|
||||
case obrimProgressStateStarted,
|
||||
obrimProgressStateRunning,
|
||||
obrimProgressStateCompleted,
|
||||
obrimProgressStateCanceled:
|
||||
default:
|
||||
log.ObrimLog("ERROR", "Invalid progress lifecycle state.")
|
||||
status.ObrimStatus("ERROR", "Invalid progress lifecycle state.")
|
||||
return false
|
||||
}
|
||||
|
||||
switch progressType {
|
||||
case obrimProgressTypeCountable:
|
||||
_, currentExists := config["current"]
|
||||
_, targetExists := config["target"]
|
||||
|
||||
if !currentExists || !targetExists {
|
||||
return false
|
||||
}
|
||||
|
||||
// targetValue stores target progress value.
|
||||
targetValue, ok := obrimProgressConvertToInt(config["target"])
|
||||
if !ok || targetValue <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
case obrimProgressTypeUncountable:
|
||||
placeholder, ok := config["placeholder"].(string)
|
||||
if !ok || strings.TrimSpace(placeholder) == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// obrimProgressHandleState processes lifecycle state transitions.
|
||||
func obrimProgressHandleState(state string) bool {
|
||||
switch state {
|
||||
case obrimProgressStateStarted:
|
||||
log.ObrimLog("INIT", "Progress tracking started.")
|
||||
status.ObrimStatus("INFO", "Progress started.")
|
||||
return true
|
||||
|
||||
case obrimProgressStateRunning:
|
||||
log.ObrimLog("PROGRESS", "Progress tracking updated.")
|
||||
status.ObrimStatus("INFO", "Progress running.")
|
||||
return true
|
||||
|
||||
case obrimProgressStateCompleted:
|
||||
log.ObrimLog("SUCCESS", "Progress tracking completed.")
|
||||
status.ObrimStatus("SUCCESS", "Progress completed.")
|
||||
return true
|
||||
|
||||
case obrimProgressStateCanceled:
|
||||
log.ObrimLog("WARNING", "Progress tracking canceled.")
|
||||
status.ObrimStatus("WARNING", "Progress canceled.")
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// obrimProgressCountable processes countable progress tracking workflows.
|
||||
func obrimProgressCountable(config map[string]any) map[string]any {
|
||||
// lifecycleState stores lifecycle state.
|
||||
lifecycleState := strings.ToLower(fmt.Sprintf("%v", config["state"]))
|
||||
|
||||
// currentValue stores current progress value.
|
||||
currentValue, _ := obrimProgressConvertToInt(config["current"])
|
||||
|
||||
// targetValue stores target progress value.
|
||||
targetValue, _ := obrimProgressConvertToInt(config["target"])
|
||||
|
||||
// percentage stores normalized completion percentage.
|
||||
percentage := obrimProgressCalculatePercentage(
|
||||
currentValue,
|
||||
targetValue,
|
||||
)
|
||||
|
||||
// progressMessage stores human readable progress message.
|
||||
progressMessage := obrimProgressGenerateMessage(
|
||||
obrimProgressTypeCountable,
|
||||
lifecycleState,
|
||||
percentage,
|
||||
"",
|
||||
)
|
||||
|
||||
// progressVisual stores visual progress representation.
|
||||
progressVisual := obrimProgressGenerateVisual(
|
||||
obrimProgressTypeCountable,
|
||||
percentage,
|
||||
"",
|
||||
)
|
||||
|
||||
payload := map[string]any{
|
||||
"state": lifecycleState,
|
||||
"current": currentValue,
|
||||
"target": targetValue,
|
||||
"percentage": percentage,
|
||||
"message": progressMessage,
|
||||
"visual": progressVisual,
|
||||
}
|
||||
|
||||
return obrimProgressBuildResponse(
|
||||
true,
|
||||
"SUCCESS_PROGRESS_TRACKED",
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimProgressCalculatePercentage calculates and normalizes completion percentages.
|
||||
func obrimProgressCalculatePercentage(current int, target int) int {
|
||||
if target <= 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
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) map[string]any {
|
||||
// lifecycleState stores lifecycle state.
|
||||
lifecycleState := strings.ToLower(fmt.Sprintf("%v", config["state"]))
|
||||
|
||||
// placeholder stores resolved placeholder text.
|
||||
placeholder := obrimProgressResolvePlaceholder(config)
|
||||
|
||||
// progressMessage stores human readable progress message.
|
||||
progressMessage := obrimProgressGenerateMessage(
|
||||
obrimProgressTypeUncountable,
|
||||
lifecycleState,
|
||||
0,
|
||||
placeholder,
|
||||
)
|
||||
|
||||
// progressVisual stores visual progress representation.
|
||||
progressVisual := obrimProgressGenerateVisual(
|
||||
obrimProgressTypeUncountable,
|
||||
0,
|
||||
placeholder,
|
||||
)
|
||||
|
||||
payload := map[string]any{
|
||||
"state": lifecycleState,
|
||||
"placeholder": placeholder,
|
||||
"message": progressMessage,
|
||||
"visual": progressVisual,
|
||||
}
|
||||
|
||||
return obrimProgressBuildResponse(
|
||||
true,
|
||||
"SUCCESS_PROGRESS_TRACKED",
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
// obrimProgressResolvePlaceholder validates and prepares placeholder activity messages.
|
||||
func obrimProgressResolvePlaceholder(config map[string]any) string {
|
||||
placeholder, ok := config["placeholder"].(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.TrimSpace(placeholder)
|
||||
}
|
||||
|
||||
// obrimProgressGenerateMessage generates human-readable progress messages.
|
||||
func obrimProgressGenerateMessage(
|
||||
progressType string,
|
||||
state string,
|
||||
percentage int,
|
||||
placeholder string,
|
||||
) string {
|
||||
if progressType == obrimProgressTypeCountable {
|
||||
switch state {
|
||||
case obrimProgressStateStarted:
|
||||
return fmt.Sprintf("Progress started (%d%%).", percentage)
|
||||
|
||||
case obrimProgressStateRunning:
|
||||
return fmt.Sprintf("Progress running (%d%% complete).", percentage)
|
||||
|
||||
case obrimProgressStateCompleted:
|
||||
return "Progress completed successfully."
|
||||
|
||||
case obrimProgressStateCanceled:
|
||||
return "Progress canceled."
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
percentage int,
|
||||
placeholder string,
|
||||
) string {
|
||||
if progressType == obrimProgressTypeCountable {
|
||||
filled := int(
|
||||
math.Round(
|
||||
(float64(percentage) / 100) * obrimProgressVisualWidth,
|
||||
),
|
||||
)
|
||||
|
||||
if filled > obrimProgressVisualWidth {
|
||||
filled = obrimProgressVisualWidth
|
||||
}
|
||||
|
||||
if filled < 0 {
|
||||
filled = 0
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"[%s%s] %d%%",
|
||||
strings.Repeat("#", filled),
|
||||
strings.Repeat("-", obrimProgressVisualWidth-filled),
|
||||
percentage,
|
||||
)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("[~] %s", placeholder)
|
||||
}
|
||||
|
||||
// obrimProgressBuildResponse constructs standardized utility response payloads.
|
||||
func obrimProgressBuildResponse(
|
||||
success bool,
|
||||
code string,
|
||||
payload map[string]any,
|
||||
) map[string]any {
|
||||
if !success {
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": code,
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": code,
|
||||
"payload": payload,
|
||||
}
|
||||
}
|
||||
|
||||
// obrimProgressConvertToInt safely converts supported numeric values to int.
|
||||
func obrimProgressConvertToInt(value any) (int, bool) {
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
return v, true
|
||||
case int8:
|
||||
return int(v), true
|
||||
case int16:
|
||||
return int(v), true
|
||||
case int32:
|
||||
return int(v), true
|
||||
case int64:
|
||||
return int(v), true
|
||||
case uint:
|
||||
return int(v), true
|
||||
case uint8:
|
||||
return int(v), true
|
||||
case uint16:
|
||||
return int(v), true
|
||||
case uint32:
|
||||
return int(v), true
|
||||
case uint64:
|
||||
return int(v), true
|
||||
case float32:
|
||||
return int(v), true
|
||||
case float64:
|
||||
return int(v), true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,323 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Retriever
|
||||
|
|
||||
| Purpose:
|
||||
| - Retrieve data from supported resource providers through a unified
|
||||
| retrieval interface.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use registered providers to retrieve resources.
|
||||
| - Use resource identifiers to resolve providers.
|
||||
| - Use path or fields selection for partial retrieval.
|
||||
| - Path and fields are mutually exclusive.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimRetriever("json", map[string]any{"resource": "metadata"})
|
||||
| - ObrimRetriever("json", map[string]any{
|
||||
| "resource": "metadata",
|
||||
| "path": "application.name",
|
||||
| })
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package retriever
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go/module/essential/visible/service/helper/log"
|
||||
"go/module/essential/visible/service/helper/status"
|
||||
)
|
||||
|
||||
// ObrimRetrieverResponse represents the standardized utility response.
|
||||
type ObrimRetrieverResponse struct {
|
||||
Status bool `json:"status"`
|
||||
Code string `json:"code"`
|
||||
Payload any `json:"payload"`
|
||||
}
|
||||
|
||||
// ObrimRetrieverJsonProviderRegistry stores registered JSON providers.
|
||||
var ObrimRetrieverJsonProviderRegistry = map[string]any{}
|
||||
|
||||
// ObrimRetrieverDbProviderRegistry stores registered database providers.
|
||||
var ObrimRetrieverDbProviderRegistry = map[string]any{}
|
||||
|
||||
// ObrimRetriever retrieves data using a unified retrieval interface.
|
||||
func ObrimRetriever(retrievalType string, config map[string]any) map[string]any {
|
||||
status.ObrimStatus("INFO", "Retriever started.")
|
||||
log.ObrimLog("INIT", "Retriever execution started.")
|
||||
|
||||
if !obrimRetrieverValidateType(retrievalType) {
|
||||
return obrimRetrieverBuildResponse(false, "FAILED_UNSUPPORTED_TYPE", nil)
|
||||
}
|
||||
|
||||
if !obrimRetrieverValidateConfig(retrievalType, config) {
|
||||
return obrimRetrieverBuildResponse(false, "FAILED_INVALID_CONFIGURATION", nil)
|
||||
}
|
||||
|
||||
switch retrievalType {
|
||||
case "json":
|
||||
return obrimRetrieverJson(config)
|
||||
|
||||
case "db":
|
||||
return obrimRetrieverDb(config)
|
||||
|
||||
default:
|
||||
return obrimRetrieverBuildResponse(false, "FAILED_UNSUPPORTED_TYPE", nil)
|
||||
}
|
||||
}
|
||||
|
||||
// ObrimRetrieverJsonRegister registers a JSON provider.
|
||||
func ObrimRetrieverJsonRegister(resource string, provider any) {
|
||||
ObrimRetrieverJsonProviderRegistry[resource] = provider
|
||||
}
|
||||
|
||||
// ObrimRetrieverDbRegister registers a database provider.
|
||||
func ObrimRetrieverDbRegister(resource string, provider any) {
|
||||
ObrimRetrieverDbProviderRegistry[resource] = provider
|
||||
}
|
||||
|
||||
// obrimRetrieverValidateType validates the requested retrieval type.
|
||||
func obrimRetrieverValidateType(retrievalType string) bool {
|
||||
switch retrievalType {
|
||||
case "json", "db":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// obrimRetrieverValidateConfig validates configuration by retrieval type.
|
||||
func obrimRetrieverValidateConfig(retrievalType string, config map[string]any) bool {
|
||||
switch retrievalType {
|
||||
case "json":
|
||||
return obrimRetrieverJsonValidate(config)
|
||||
|
||||
case "db":
|
||||
return obrimRetrieverDbValidate(config)
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// obrimRetrieverResolveProvider resolves a provider by resource identifier.
|
||||
func obrimRetrieverResolveProvider(
|
||||
retrievalType string,
|
||||
resource string,
|
||||
) (any, bool) {
|
||||
switch retrievalType {
|
||||
case "json":
|
||||
provider, exists := ObrimRetrieverJsonProviderRegistry[resource]
|
||||
return provider, exists
|
||||
|
||||
case "db":
|
||||
provider, exists := ObrimRetrieverDbProviderRegistry[resource]
|
||||
return provider, exists
|
||||
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// obrimRetrieverBuildResponse builds a standardized response.
|
||||
func obrimRetrieverBuildResponse(
|
||||
success bool,
|
||||
code string,
|
||||
payload any,
|
||||
) map[string]any {
|
||||
return map[string]any{
|
||||
"status": success,
|
||||
"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("json", resource)
|
||||
if !exists {
|
||||
return obrimRetrieverBuildResponse(false, "FAILED_RESOURCE_NOT_FOUND", nil)
|
||||
}
|
||||
|
||||
data, err := obrimRetrieverJsonResource(provider)
|
||||
if err != nil {
|
||||
return obrimRetrieverBuildResponse(false, "FAILED_RESOURCE_NOT_FOUND", nil)
|
||||
}
|
||||
|
||||
_, hasPath := config["path"]
|
||||
_, hasFields := config["fields"]
|
||||
|
||||
if hasPath {
|
||||
return obrimRetrieverJsonPath(data, config)
|
||||
}
|
||||
|
||||
if hasFields {
|
||||
return obrimRetrieverJsonFields(data, config)
|
||||
}
|
||||
|
||||
return obrimRetrieverBuildResponse(
|
||||
true,
|
||||
"SUCCESS_RESOURCE",
|
||||
map[string]any{
|
||||
"data": data,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// obrimRetrieverJsonResource retrieves a complete resource payload.
|
||||
func obrimRetrieverJsonResource(provider any) (any, error) {
|
||||
switch value := provider.(type) {
|
||||
case func() (any, error):
|
||||
return value()
|
||||
|
||||
case func() any:
|
||||
return value(), nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid provider")
|
||||
}
|
||||
}
|
||||
|
||||
// obrimRetrieverJsonPath retrieves a value using dot notation.
|
||||
func obrimRetrieverJsonPath(
|
||||
data any,
|
||||
config map[string]any,
|
||||
) map[string]any {
|
||||
path, _ := config["path"].(string)
|
||||
|
||||
value, found := obrimRetrieverResolvePath(data, path)
|
||||
if !found {
|
||||
return obrimRetrieverBuildResponse(false, "FAILED_PATH_NOT_FOUND", nil)
|
||||
}
|
||||
|
||||
return obrimRetrieverBuildResponse(
|
||||
true,
|
||||
"SUCCESS_PATH",
|
||||
map[string]any{
|
||||
"data": value,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// obrimRetrieverJsonFields retrieves multiple values using field selection.
|
||||
func obrimRetrieverJsonFields(
|
||||
data any,
|
||||
config map[string]any,
|
||||
) map[string]any {
|
||||
fields, ok := config["fields"].([]string)
|
||||
if !ok {
|
||||
rawFields, castOk := config["fields"].([]any)
|
||||
if !castOk {
|
||||
return obrimRetrieverBuildResponse(false, "FAILED_INVALID_CONFIGURATION", nil)
|
||||
}
|
||||
|
||||
fields = make([]string, 0, len(rawFields))
|
||||
|
||||
for _, field := range rawFields {
|
||||
fieldString, stringOk := field.(string)
|
||||
if !stringOk {
|
||||
return obrimRetrieverBuildResponse(false, "FAILED_INVALID_CONFIGURATION", nil)
|
||||
}
|
||||
|
||||
fields = append(fields, fieldString)
|
||||
}
|
||||
}
|
||||
|
||||
result := map[string]any{}
|
||||
|
||||
for _, field := range fields {
|
||||
value, found := obrimRetrieverResolvePath(data, field)
|
||||
if !found {
|
||||
return obrimRetrieverBuildResponse(false, "FAILED_FIELD_NOT_FOUND", nil)
|
||||
}
|
||||
|
||||
result[field] = value
|
||||
}
|
||||
|
||||
return obrimRetrieverBuildResponse(
|
||||
true,
|
||||
"SUCCESS_FIELDS",
|
||||
map[string]any{
|
||||
"data": result,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// obrimRetrieverJsonValidate validates JSON configuration.
|
||||
func obrimRetrieverJsonValidate(config map[string]any) bool {
|
||||
resource, exists := config["resource"]
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
|
||||
resourceString, ok := resource.(string)
|
||||
if !ok || strings.TrimSpace(resourceString) == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
_, hasPath := config["path"]
|
||||
_, hasFields := config["fields"]
|
||||
|
||||
if hasPath && hasFields {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// obrimRetrieverDb processes database retrieval requests.
|
||||
func obrimRetrieverDb(config map[string]any) map[string]any {
|
||||
return obrimRetrieverBuildResponse(false, "FAILED_NOT_IMPLEMENTED", nil)
|
||||
}
|
||||
|
||||
// obrimRetrieverDbValidate validates database configuration.
|
||||
func obrimRetrieverDbValidate(config map[string]any) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// obrimRetrieverResolvePath resolves a dot-notation path.
|
||||
func obrimRetrieverResolvePath(data any, path string) (any, bool) {
|
||||
if strings.TrimSpace(path) == "" {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
current := data
|
||||
|
||||
for _, segment := range strings.Split(path, ".") {
|
||||
object, ok := current.(map[string]any)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
value, exists := object[segment]
|
||||
if !exists {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
current = value
|
||||
}
|
||||
|
||||
return current, true
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Manifest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Status
|
||||
|
|
||||
| Purpose:
|
||||
| - Provide a framework-level CLI status utility that standardizes
|
||||
| terminal message presentation using semantic labels and visual
|
||||
| indicators to ensure consistent output across all applications.
|
||||
|
|
||||
| Guideline:
|
||||
| - Use semantic labels to classify terminal messages.
|
||||
| - Invalid, unsupported, or empty labels default to INFO.
|
||||
| - Emits exactly one terminal message per invocation.
|
||||
| - Intended for framework and software level terminal messaging.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimStatus("INFO", "Application started.")
|
||||
| - ObrimStatus("SUCCESS", "Operation completed.")
|
||||
| - ObrimStatus("WARNING", "Configuration missing.")
|
||||
| - ObrimStatus("ERROR", "Operation failed.")
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Scionite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package status
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ObrimStatus emits a standardized CLI status message.
|
||||
func ObrimStatus(label string, message string) {
|
||||
normalizedLabel := obrimStatusNormalizeLabel(label)
|
||||
formattedLabel := obrimStatusFormatLabel(normalizedLabel)
|
||||
indicator := obrimStatusFormatIndicator(normalizedLabel)
|
||||
finalMessage := obrimStatusBuildMessage(
|
||||
formattedLabel,
|
||||
indicator,
|
||||
message,
|
||||
)
|
||||
|
||||
fmt.Println(finalMessage)
|
||||
}
|
||||
|
||||
// obrimStatusNormalizeLabel normalizes and validates status labels.
|
||||
func obrimStatusNormalizeLabel(label string) string {
|
||||
normalizedLabel := strings.ToUpper(strings.TrimSpace(label))
|
||||
|
||||
switch normalizedLabel {
|
||||
case "INFO":
|
||||
return "INFO"
|
||||
case "WARNING":
|
||||
return "WARNING"
|
||||
case "SUCCESS":
|
||||
return "SUCCESS"
|
||||
case "ERROR":
|
||||
return "ERROR"
|
||||
default:
|
||||
return "INFO"
|
||||
}
|
||||
}
|
||||
|
||||
// obrimStatusFormatLabel formats semantic status labels.
|
||||
func obrimStatusFormatLabel(label string) string {
|
||||
return "[" + label + "]"
|
||||
}
|
||||
|
||||
// obrimStatusFormatIndicator generates visual status indicators.
|
||||
func obrimStatusFormatIndicator(label string) string {
|
||||
switch label {
|
||||
case "INFO":
|
||||
return "ℹ"
|
||||
case "WARNING":
|
||||
return "⚠"
|
||||
case "SUCCESS":
|
||||
return "✓"
|
||||
case "ERROR":
|
||||
return "✖"
|
||||
default:
|
||||
return "ℹ"
|
||||
}
|
||||
}
|
||||
|
||||
// obrimStatusBuildMessage constructs the final terminal message.
|
||||
func obrimStatusBuildMessage(
|
||||
label string,
|
||||
indicator string,
|
||||
message string,
|
||||
) string {
|
||||
return fmt.Sprintf("%s %s %s", indicator, label, message)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user