From 93a5d8826d1a0947b247c907a9ca844f5bc55209 Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Tue, 28 Oct 2025 10:39:59 -0400 Subject: [PATCH 1/5] > Ran tool: `github_create_or_update_file` > > *Failed*: > ``` > failed to create/update file: PUT https://api.github.com/repos/sonr-io/sonr-io.github.io/contents/docs/guides/decentralized-authentication.mdx: 401 Bad credentials [] > ``` > Ran tool: `github_create_or_update_file` > > *Failed*: > ``` > failed to create/update file: PUT https://api.github.com/repos/sonr-io/sonr-io.github.io/contents/docs/guides/decentralized-authentication.mdx: 401 Bad credentials [] > ``` docs: Remove decentralized authentication guide --- docs/guides/decentralized-authentication.mdx | 191 ------------------ docs/guides/decentralized-identity.mdx | 129 ------------ ...igrate-to-decentralized-authentication.mdx | 191 ------------------ 3 files changed, 511 deletions(-) delete mode 100644 docs/guides/decentralized-authentication.mdx delete mode 100644 docs/guides/decentralized-identity.mdx delete mode 100644 docs/guides/migrate-to-decentralized-authentication.mdx diff --git a/docs/guides/decentralized-authentication.mdx b/docs/guides/decentralized-authentication.mdx deleted file mode 100644 index f58ab5aea..000000000 --- a/docs/guides/decentralized-authentication.mdx +++ /dev/null @@ -1,191 +0,0 @@ ---- -title: "Migrating from Centralized to Decentralized Authentication" -description: "A comprehensive guide to migrating from centralized 8787 endpoints to decentralized OIDC authentication with WebAuthn" -sidebarTitle: "Decentralized Authentication" -icon: "key" ---- - -# Migrating from Centralized to Decentralized Authentication - -## Overview - -Sonr is transitioning from a centralized authentication model using 8787 endpoints to a fully decentralized, privacy-preserving authentication system leveraging OpenID Connect (OIDC), Self-Issued OpenID Provider (SIOP), and WebAuthn technologies. - -### Key Improvements - -- **Decentralization**: Move from centralized identity management to self-sovereign identity -- **WebAuthn Integration**: Hardware-backed, phishing-resistance authentication -- **Gasless Onboarding**: Zero-cost user registration and transactions -- **Automatic Vault Creation**: Seamless user experience with instant identity setup -- **Enhanced Privacy**: DID-based authentication with verifiable presentations - -## Architecture Comparison - -### Old Architecture: Centralized 8787 Endpoints - -- Centralized authentication server -- Fixed credential storage -- Limited authentication methods -- Higher security risks - -### New Architecture: Decentralized OIDC Provider - -```mermaid -graph TD - A[User Device] --> B{WebAuthn Registration} - B --> |Credential Generation| C[Blockchain Bridge] - C --> |Broadcast Credential| D[Sonr Blockchain] - D --> |Create DID| E[User's Decentralized Identity] - E --> |SIOP Flow| F[OIDC Provider] - F --> |Verifiable Presentation| G[Service Provider] -``` - -## Migration Steps - -### 1. Prerequisites - -- Go 1.24.1+ -- Cosmos SDK v0.50.14 -- WebAuthn-compatible browser/device -- Updated Sonr SDK - -### 2. Configuration Changes - -#### Environment Variables - - -```bash title="Old Configuration" -# Centralized auth endpoints -AUTH_ENDPOINT=https://8787.sonr.io/auth -AUTH_CLIENT_ID=legacy-client-id -``` - -```bash title="New Configuration" -# Decentralized OIDC configuration -OIDC_PROVIDER_URL=https://oidc.sonr.network -WEBAUTHN_ORIGIN=https://your-app.com -DID_RESOLVER_URL=https://did.sonr.network -``` - - - -### 3. Endpoint Migration - -| Old Endpoint | New Endpoint | Changes | -| ---------------- | -------------------- | ----------------------- | -| `/auth/login` | `/oidc/authorize` | OIDC authorization flow | -| `/auth/register` | `/webauthn/register` | WebAuthn registration | -| `/auth/token` | `/oidc/token` | Token issuance via SIOP | - -### 4. API Changes - -#### Request Format - - -```json title="Legacy Request" -{ - "username": "user@example.com", - "password": "legacy-password" -} -``` - -```json title="New WebAuthn Request" -{ - "challenge": "base64-encoded-challenge", - "attestation": { - "type": "public-key", - "id": "credential-id", - "rawId": "base64-encoded-raw-credential", - "response": { - "clientDataJSON": "...", - "attestationObject": "..." - } - } -} -``` - - - -### 5. WebAuthn Integration - -#### Registration Flow - -1. Generate registration challenge -2. Create WebAuthn credential -3. Broadcast credential to blockchain -4. Automatically create user vault -5. Issue decentralized identifier (DID) - -#### Code Example - -```go title="WebAuthn Registration Handler" -func (s *Server) HandleWebAuthnRegistration(w http.ResponseWriter, r *http.Request) { - // 1. Validate WebAuthn attestation - credential, err := s.webAuthnService.VerifyRegistration(attestationData) - - // 2. Broadcast to blockchain - didDoc, err := s.blockchainBridge.CreateDID(credential) - - // 3. Create user vault - vault, err := s.vaultService.CreateVault(didDoc) - - // 4. Issue OIDC token - token := s.oidcService.IssueToken(didDoc) -} -``` - -### 6. SIOP (Self-Issued OpenID Provider) - -#### Key Concepts - -- Verifiable Presentations -- Decentralized Identifiers (DIDs) -- User-controlled authentication - -### 7. Error Handling - -#### Migration Errors - -| Error Code | Description | Mitigation | -| ------------------------ | ---------------------- | -------------------- | -| `AUTH_LEGACY_DEPRECATED` | Legacy auth method | Upgrade client | -| `WEBAUTHN_UNSUPPORTED` | Device incompatibility | Use alternative auth | -| `DID_RESOLUTION_FAILED` | Identity verification | Retry registration | - -### 8. Testing Migration - -```bash -# Validate WebAuthn registration -sonr webauthn test-registration - -# Verify OIDC provider -sonr oidc validate-provider - -# Check DID resolution -sonr did resolve did:sonr:example -``` - -### 9. Breaking Changes - -- Legacy password authentication removed -- Token format changed to JWT with DID claims -- New client libraries required -- WebAuthn mandatory for registration - -## Rollback Procedure - -If issues arise: - -1. Maintain legacy user mappings -2. Provide fallback authentication -3. Gradual, opt-in migration - -## Conclusion - -This migration represents a significant leap in authentication security and user privacy. By adopting WebAuthn, SIOP, and blockchain-backed identities, we're creating a more robust, user-controlled authentication ecosystem. - -## Support - -- [Sonr Developer Docs](/docs) -- [WebAuthn Specification](https://www.w3.org/TR/webauthn-2/) -- [OIDC Community](https://openid.net/developers/specs/) diff --git a/docs/guides/decentralized-identity.mdx b/docs/guides/decentralized-identity.mdx deleted file mode 100644 index 56afd2a0b..000000000 --- a/docs/guides/decentralized-identity.mdx +++ /dev/null @@ -1,129 +0,0 @@ ---- -title: "DID Generation and Management" -description: "Learn how to generate and manage Decentralized Identifiers (DIDs) using advanced crypto interfaces" -sidebarTitle: "Identity Generation" -icon: "signature" ---- - -# DID Generation Patterns - -The Sonr project provides a robust and flexible DID (Decentralized Identifier) generation system supporting multiple key types and cryptographic methods. - -## Supported Key Types - -The `didkey.go` interface supports the following key types: - -- RSA Public Keys -- Ed25519 Public Keys -- Secp256k1 Public Keys - -## Basic DID Generation - -### Creating a DID from a Public Key - -```go -import ( - "github.com/libp2p/go-libp2p/core/crypto" - "github.com/sonr-io/crypto/keys" -) - -// Generate a new key pair -privateKey, publicKey, err := crypto.GenerateKeyPair(crypto.Ed25519, -1) - -// Create a DID -did, err := keys.NewDID(publicKey) -``` - -### Parsing an Existing DID - -```go -// Parse a DID string -did, err := keys.Parse("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGTsyDFWYviJr4") -``` - -## Advanced DID Operations - -### Address Derivation - -```go -// Get a blockchain-compatible address from a DID -address, err := did.Address() -``` - -### Compressed Public Key Retrieval - -```go -// Get a compressed public key (for Secp256k1) -compressedPubKey, err := did.CompressedPubKey() -``` - -## MPC Enclave DID Generation - -For MPC (Multi-Party Computation) enclaves, use a specialized method: - -```go -// Create a DID from MPC enclave public key bytes -did, err := keys.NewFromMPCPubKey(enclavePublicKeyBytes) -``` - -## DID Validation - -```go -// Validate a DID format -err := keys.ValidateFormat("did:key:example123") -``` - -## Multicodec Support - -The library supports various multicodec prefixes for different key types: - -- RSA: `0x1205` -- Ed25519: `0xed` -- Secp256k1: `0xe7` - -## Security Considerations - -- Always generate keys using cryptographically secure methods -- Validate DIDs before using them in critical operations -- Use the appropriate key type for your security requirements - -## Example: Complete DID Workflow - -```go -package main - -import ( - "fmt" - "github.com/libp2p/go-libp2p/core/crypto" - "github.com/sonr-io/crypto/keys" -) - -func main() { - // Generate a new key pair - privateKey, publicKey, err := crypto.GenerateKeyPair(crypto.Ed25519, -1) - if err != nil { - panic(err) - } - - // Create a DID - did, err := keys.NewDID(publicKey) - if err != nil { - panic(err) - } - - // Get the DID string - didString := did.String() - fmt.Println("Generated DID:", didString) - - // Derive blockchain address - address, err := did.Address() - if err != nil { - panic(err) - } - fmt.Println("Blockchain Address:", address) -} -``` - -## Compatibility and Interoperability - -The Sonr DID implementation follows the W3C DID specification, ensuring broad compatibility with other decentralized identity systems. diff --git a/docs/guides/migrate-to-decentralized-authentication.mdx b/docs/guides/migrate-to-decentralized-authentication.mdx deleted file mode 100644 index f58ab5aea..000000000 --- a/docs/guides/migrate-to-decentralized-authentication.mdx +++ /dev/null @@ -1,191 +0,0 @@ ---- -title: "Migrating from Centralized to Decentralized Authentication" -description: "A comprehensive guide to migrating from centralized 8787 endpoints to decentralized OIDC authentication with WebAuthn" -sidebarTitle: "Decentralized Authentication" -icon: "key" ---- - -# Migrating from Centralized to Decentralized Authentication - -## Overview - -Sonr is transitioning from a centralized authentication model using 8787 endpoints to a fully decentralized, privacy-preserving authentication system leveraging OpenID Connect (OIDC), Self-Issued OpenID Provider (SIOP), and WebAuthn technologies. - -### Key Improvements - -- **Decentralization**: Move from centralized identity management to self-sovereign identity -- **WebAuthn Integration**: Hardware-backed, phishing-resistance authentication -- **Gasless Onboarding**: Zero-cost user registration and transactions -- **Automatic Vault Creation**: Seamless user experience with instant identity setup -- **Enhanced Privacy**: DID-based authentication with verifiable presentations - -## Architecture Comparison - -### Old Architecture: Centralized 8787 Endpoints - -- Centralized authentication server -- Fixed credential storage -- Limited authentication methods -- Higher security risks - -### New Architecture: Decentralized OIDC Provider - -```mermaid -graph TD - A[User Device] --> B{WebAuthn Registration} - B --> |Credential Generation| C[Blockchain Bridge] - C --> |Broadcast Credential| D[Sonr Blockchain] - D --> |Create DID| E[User's Decentralized Identity] - E --> |SIOP Flow| F[OIDC Provider] - F --> |Verifiable Presentation| G[Service Provider] -``` - -## Migration Steps - -### 1. Prerequisites - -- Go 1.24.1+ -- Cosmos SDK v0.50.14 -- WebAuthn-compatible browser/device -- Updated Sonr SDK - -### 2. Configuration Changes - -#### Environment Variables - - -```bash title="Old Configuration" -# Centralized auth endpoints -AUTH_ENDPOINT=https://8787.sonr.io/auth -AUTH_CLIENT_ID=legacy-client-id -``` - -```bash title="New Configuration" -# Decentralized OIDC configuration -OIDC_PROVIDER_URL=https://oidc.sonr.network -WEBAUTHN_ORIGIN=https://your-app.com -DID_RESOLVER_URL=https://did.sonr.network -``` - - - -### 3. Endpoint Migration - -| Old Endpoint | New Endpoint | Changes | -| ---------------- | -------------------- | ----------------------- | -| `/auth/login` | `/oidc/authorize` | OIDC authorization flow | -| `/auth/register` | `/webauthn/register` | WebAuthn registration | -| `/auth/token` | `/oidc/token` | Token issuance via SIOP | - -### 4. API Changes - -#### Request Format - - -```json title="Legacy Request" -{ - "username": "user@example.com", - "password": "legacy-password" -} -``` - -```json title="New WebAuthn Request" -{ - "challenge": "base64-encoded-challenge", - "attestation": { - "type": "public-key", - "id": "credential-id", - "rawId": "base64-encoded-raw-credential", - "response": { - "clientDataJSON": "...", - "attestationObject": "..." - } - } -} -``` - - - -### 5. WebAuthn Integration - -#### Registration Flow - -1. Generate registration challenge -2. Create WebAuthn credential -3. Broadcast credential to blockchain -4. Automatically create user vault -5. Issue decentralized identifier (DID) - -#### Code Example - -```go title="WebAuthn Registration Handler" -func (s *Server) HandleWebAuthnRegistration(w http.ResponseWriter, r *http.Request) { - // 1. Validate WebAuthn attestation - credential, err := s.webAuthnService.VerifyRegistration(attestationData) - - // 2. Broadcast to blockchain - didDoc, err := s.blockchainBridge.CreateDID(credential) - - // 3. Create user vault - vault, err := s.vaultService.CreateVault(didDoc) - - // 4. Issue OIDC token - token := s.oidcService.IssueToken(didDoc) -} -``` - -### 6. SIOP (Self-Issued OpenID Provider) - -#### Key Concepts - -- Verifiable Presentations -- Decentralized Identifiers (DIDs) -- User-controlled authentication - -### 7. Error Handling - -#### Migration Errors - -| Error Code | Description | Mitigation | -| ------------------------ | ---------------------- | -------------------- | -| `AUTH_LEGACY_DEPRECATED` | Legacy auth method | Upgrade client | -| `WEBAUTHN_UNSUPPORTED` | Device incompatibility | Use alternative auth | -| `DID_RESOLUTION_FAILED` | Identity verification | Retry registration | - -### 8. Testing Migration - -```bash -# Validate WebAuthn registration -sonr webauthn test-registration - -# Verify OIDC provider -sonr oidc validate-provider - -# Check DID resolution -sonr did resolve did:sonr:example -``` - -### 9. Breaking Changes - -- Legacy password authentication removed -- Token format changed to JWT with DID claims -- New client libraries required -- WebAuthn mandatory for registration - -## Rollback Procedure - -If issues arise: - -1. Maintain legacy user mappings -2. Provide fallback authentication -3. Gradual, opt-in migration - -## Conclusion - -This migration represents a significant leap in authentication security and user privacy. By adopting WebAuthn, SIOP, and blockchain-backed identities, we're creating a more robust, user-controlled authentication ecosystem. - -## Support - -- [Sonr Developer Docs](/docs) -- [WebAuthn Specification](https://www.w3.org/TR/webauthn-2/) -- [OIDC Community](https://openid.net/developers/specs/) From 99167120dccf0b181e4d609ecfa5bd7b9c6a433c Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Wed, 5 Nov 2025 15:03:16 -0500 Subject: [PATCH 2/5] chore(.gitignore): add .claude to ignore list --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cb33c8319..032d1f01b 100755 --- a/.gitignore +++ b/.gitignore @@ -122,3 +122,4 @@ tmp-openapi-gen/**/*.json !docs/static/openapi.yml .mcp.json node_modules +.claude From 28eba5a3f366d598fb9cc5469a81873f282e4a5b Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Tue, 18 Nov 2025 12:19:21 -0500 Subject: [PATCH 3/5] feat(cmd): add ASCII art logo to snrd cli tool --- cmd/snrd/main.go | 16 ++++++++++++++++ cmd/snrd/root.go | 1 + 2 files changed, 17 insertions(+) diff --git a/cmd/snrd/main.go b/cmd/snrd/main.go index 5cce560ae..3483fc378 100755 --- a/cmd/snrd/main.go +++ b/cmd/snrd/main.go @@ -11,6 +11,7 @@ import ( ) func main() { + fmt.Print(sonrLogo()) setupSDKConfig() // Standard snrd execution @@ -35,3 +36,18 @@ func SetBech32Prefixes(config *sdk.Config) { config.SetBech32PrefixForValidator(app.Bech32PrefixValAddr, app.Bech32PrefixValPub) config.SetBech32PrefixForConsensusNode(app.Bech32PrefixConsAddr, app.Bech32PrefixConsPub) } + +func sonrLogo() string { + lines := []string{ + "██████████░ ██████████░ ██████░ ██░ ██████████░", + "██░ ██░ ██░ ██░ ██░ ██░ ██░ ██░", + "██████████░ ██░ ██░ ██░ ██░ ██░ ██████████░", + " ██░ ██░ ██░ ██░ ██░ ██░ ██░ ", + "██████████░ ██████████░ ██░ ██████░ ██░ ██████░", + } + var logo string + for _, line := range lines { + logo += line + "\n" + } + return logo +} diff --git a/cmd/snrd/root.go b/cmd/snrd/root.go index 086c0eef4..62adcd965 100755 --- a/cmd/snrd/root.go +++ b/cmd/snrd/root.go @@ -61,6 +61,7 @@ func NewRootCmd() *cobra.Command { rootCmd := &cobra.Command{ Use: version.AppName, Short: version.AppName + " Daemon (server)", + Long: sonrLogo(), SilenceErrors: true, PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { // set the default command outputs From ad69f0ac8080b9ceed0074808a87baf1b5617cab Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Tue, 18 Nov 2025 12:20:40 -0500 Subject: [PATCH 4/5] refactor(cmd): remove unnecessary logo print statement from main function --- cmd/snrd/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/snrd/main.go b/cmd/snrd/main.go index 3483fc378..217cb3365 100755 --- a/cmd/snrd/main.go +++ b/cmd/snrd/main.go @@ -11,7 +11,6 @@ import ( ) func main() { - fmt.Print(sonrLogo()) setupSDKConfig() // Standard snrd execution From f71193674bf9f41b6aa7956b0dcec9e58dc81934 Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Tue, 18 Nov 2025 12:27:01 -0500 Subject: [PATCH 5/5] feat(cmd): add ASCII art logo to CLI output --- cmd/snrd/main.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/cmd/snrd/main.go b/cmd/snrd/main.go index 217cb3365..01d6b037d 100755 --- a/cmd/snrd/main.go +++ b/cmd/snrd/main.go @@ -3,6 +3,7 @@ package main import ( "fmt" "os" + "strings" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" sdk "github.com/cosmos/cosmos-sdk/types" @@ -38,15 +39,22 @@ func SetBech32Prefixes(config *sdk.Config) { func sonrLogo() string { lines := []string{ - "██████████░ ██████████░ ██████░ ██░ ██████████░", - "██░ ██░ ██░ ██░ ██░ ██░ ██░ ██░", - "██████████░ ██░ ██░ ██░ ██░ ██░ ██████████░", - " ██░ ██░ ██░ ██░ ██░ ██░ ██░ ", - "██████████░ ██████████░ ██░ ██████░ ██░ ██████░", + "[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m░[0m [38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m░[0m [38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m░[0m [38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m░[0m [38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m█[0m[38;2;153;255;255m░[0m", + "[38;2;119;233;242m█[0m[38;2;119;233;242m█[0m[38;2;119;233;242m░[0m [38;2;119;233;242m█[0m[38;2;119;233;242m█[0m[38;2;119;233;242m░[0m [38;2;119;233;242m█[0m[38;2;119;233;242m█[0m[38;2;119;233;242m░[0m [38;2;119;233;242m█[0m[38;2;119;233;242m█[0m[38;2;119;233;242m░[0m [38;2;119;233;242m█[0m[38;2;119;233;242m█[0m[38;2;119;233;242m░[0m [38;2;119;233;242m█[0m[38;2;119;233;242m█[0m[38;2;119;233;242m░[0m [38;2;119;233;242m█[0m[38;2;119;233;242m█[0m[38;2;119;233;242m░[0m [38;2;119;233;242m█[0m[38;2;119;233;242m█[0m[38;2;119;233;242m░[0m", + "[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m░[0m [38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m░[0m [38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m░[0m [38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m░[0m [38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m░[0m [38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m░[0m [38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m█[0m[38;2;85;211;230m░[0m", + " [38;2;51;189;217m█[0m[38;2;51;189;217m█[0m[38;2;51;189;217m░[0m [38;2;51;189;217m█[0m[38;2;51;189;217m█[0m[38;2;51;189;217m░[0m [38;2;51;189;217m█[0m[38;2;51;189;217m█[0m[38;2;51;189;217m░[0m [38;2;51;189;217m█[0m[38;2;51;189;217m█[0m[38;2;51;189;217m░[0m [38;2;51;189;217m█[0m[38;2;51;189;217m█[0m[38;2;51;189;217m░[0m [38;2;51;189;217m█[0m[38;2;51;189;217m█[0m[38;2;51;189;217m░[0m [38;2;51;189;217m█[0m[38;2;51;189;217m█[0m[38;2;51;189;217m░[0m ", + "[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m░[0m [38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m░[0m [38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m░[0m [38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m░[0m [38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m░[0m [38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m█[0m[38;2;17;168;205m░[0m", } var logo string + // Add top padding + logo += "\n" for _, line := range lines { - logo += line + "\n" + // Replace [ with \x1b[ to make valid ANSI escape sequences + line = strings.ReplaceAll(line, "[", "\x1b[") + // Add horizontal padding + logo += " " + line + "\n" } + // Add bottom padding + logo += "\n" return logo }