├── .dockerignore ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── config.yml │ └── feature_request.yml ├── workflows │ ├── assets │ │ └── utils.sh │ ├── dependency-review.yml │ └── maintenance.yml ├── PULL_REQUEST_TEMPLATE.md ├── SECURITY.md └── dependabot.yml ├── .pre-commit.sh ├── .semgrepignore ├── proto └── sample │ └── v1 │ ├── image.bin │ ├── doc.go │ ├── model.proto │ ├── model.swagger.json │ └── bar_api.proto ├── cli ├── doc.go ├── konf │ ├── doc.go │ ├── testdata │ │ └── config.yaml │ ├── config_test.go │ └── options.go ├── viper │ ├── doc.go │ └── testdata │ │ └── config.yaml ├── params_test.go ├── read_test.go ├── shell │ ├── doc.go │ └── command.go ├── spinner.go └── read.go ├── .devcontainer └── devcontainer.json ├── internal ├── json │ └── doc.go ├── crypto │ ├── doc.go │ └── utils.go └── doc.go ├── log ├── doc.go ├── discard.go ├── discard_1_16.go └── utils.go ├── net ├── middleware │ ├── cors │ │ └── doc.go │ ├── logging │ │ └── doc.go │ ├── hsts │ │ └── doc.go │ ├── gzip │ │ ├── doc.go │ │ └── handler.go │ ├── recovery │ │ ├── doc.go │ │ └── handler.go │ ├── doc.go │ ├── headers │ │ ├── doc.go │ │ └── handler.go │ ├── proxy │ │ └── doc.go │ ├── metadata │ │ ├── doc.go │ │ └── handler.go │ ├── rate │ │ ├── doc.go │ │ └── handler.go │ └── csrf │ │ ├── options.go │ │ ├── doc.go │ │ ├── handler_prev.go │ │ └── handler.go ├── drpc │ ├── middleware │ │ ├── client │ │ │ ├── doc.go │ │ │ ├── interface.go │ │ │ ├── metadata.go │ │ │ ├── rate.go │ │ │ └── panic.go │ │ └── server │ │ │ ├── doc.go │ │ │ ├── interface.go │ │ │ ├── panic.go │ │ │ ├── rate.go │ │ │ └── auth_token.go │ ├── testdata │ │ ├── ca.sample_key │ │ ├── bad.sample_key │ │ ├── server.sample_key │ │ ├── ca.sample_cer │ │ └── server.sample_cer │ ├── ws │ │ ├── doc.go │ │ ├── error.go │ │ └── options.go │ ├── utils.go │ ├── client_tls.go │ └── client_options.go ├── http │ ├── sample-openapi │ │ ├── petstore │ │ │ ├── oas_interfaces_gen.go │ │ │ ├── oas_middleware_gen.go │ │ │ ├── oas_operations_gen.go │ │ │ ├── oas_request_encoders_gen.go │ │ │ ├── oas_validators_gen.go │ │ │ ├── oas_labeler_gen.go │ │ │ ├── oas_unimplemented_gen.go │ │ │ ├── oas_server_gen.go │ │ │ ├── oas_response_encoders_gen.go │ │ │ └── oas_request_decoders_gen.go │ │ ├── README.md │ │ └── go.mod │ ├── testdata │ │ ├── ca.sample_key │ │ ├── server.sample_key │ │ ├── ca.sample_cer │ │ └── server.sample_cer │ ├── README.md │ ├── doc.go │ ├── client_options.go │ ├── server.go │ └── options.go ├── rpc │ ├── testdata │ │ ├── bad.sample_key │ │ ├── ca.sample_key │ │ ├── server.sample_key │ │ ├── ca.sample_cer │ │ └── server.sample_cer │ ├── resource_limits.go │ ├── ws │ │ ├── doc.go │ │ ├── response.go │ │ └── utils.go │ ├── rate.go │ ├── token.go │ ├── mw_recovery.go │ ├── service.go │ ├── client_tls.go │ └── mw_protovalidate.go ├── sse │ ├── doc.go │ ├── subscription.go │ ├── stream_options.go │ ├── README.md │ ├── client.go │ └── http.go └── csp │ ├── doc.go │ ├── policy_test.go │ └── options.go ├── otel ├── grpc │ ├── doc.go │ └── utils.go ├── http │ ├── doc.go │ ├── utils.go │ └── options.go ├── temporal │ ├── doc.go │ └── span.go ├── gorm │ ├── doc.go │ ├── logger.go │ ├── options.go │ └── main.go ├── testdata │ ├── prometheus.yaml │ ├── otel-js │ │ └── api.js │ ├── docker-compose.yaml │ └── otel-collector-config.yaml ├── sdk │ ├── doc.go │ ├── no_op.go │ └── setup_test.go ├── api │ ├── doc.go │ ├── span_options.go │ └── span_kind.go ├── mongodb │ ├── doc.go │ └── monitor.go ├── sentry │ ├── doc.go │ └── span_map.go └── doc.go ├── metadata └── doc.go ├── prometheus └── doc.go ├── jose ├── amr │ └── doc.go ├── jwa │ └── doc.go ├── jwk │ ├── doc.go │ └── key_test.go └── jwt │ ├── validator_options.go │ ├── generator_options.go │ ├── validator_test.go │ ├── README.md │ ├── validator.go │ └── doc.go ├── amqp ├── utils.go ├── producer.go ├── options_test.go ├── state_test.go ├── publisher_test.go ├── consumer_test.go └── dispatcher.go ├── doc.go ├── .gitignore ├── .editorconfig ├── buf.yaml ├── .pre-commit-config.yaml ├── errors ├── codec.go ├── doc.go ├── panic_test.go ├── codec_json.go └── redactable_test.go ├── buf.lock ├── ulid ├── id_test.go ├── README.md └── doc.go ├── crypto ├── shamir │ ├── doc.go │ └── polynomial_test.go ├── ed25519 │ ├── keypair.go │ └── doc.go ├── x25519 │ ├── keypair_js.go │ ├── doc.go │ └── keypair.go ├── tred │ ├── config.go │ ├── manifest.go │ ├── header.go │ └── doc.go └── pow │ └── main_test.go ├── .gitleaksignore ├── storage └── orm │ ├── pipeline.go │ ├── utils.go │ └── transaction.go ├── buf.gen.yaml ├── LICENSE └── README.md /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @bcessa 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.pre-commit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | make lint 3 | make test 4 | -------------------------------------------------------------------------------- /.semgrepignore: -------------------------------------------------------------------------------- 1 | *.md 2 | **/testdata/* 3 | **/doc.go 4 | **/*_test.go 5 | -------------------------------------------------------------------------------- /proto/sample/v1/image.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bryk-io/pkg/HEAD/proto/sample/v1/image.bin -------------------------------------------------------------------------------- /cli/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package cli contains utilities for "Command Line Interface" applications. 3 | */ 4 | package cli 5 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Go 1.25", 3 | "image": "ghcr.io/bryk-io/devcontainer-go:1.25" 4 | } 5 | -------------------------------------------------------------------------------- /cli/konf/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package konf provides utilities to work with `github.com/nil-go/konf` 3 | */ 4 | package konf 5 | -------------------------------------------------------------------------------- /cli/konf/testdata/config.yaml: -------------------------------------------------------------------------------- 1 | http: 2 | port: 8080 3 | idle_timeout: 10 4 | middleware: 5 | compression: 5 6 | -------------------------------------------------------------------------------- /cli/viper/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package viper provides utilities to work with `github.com/spf13/viper` 3 | */ 4 | package viper 5 | -------------------------------------------------------------------------------- /internal/json/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package json provides private utilities when working with JSON data. 3 | */ 4 | package json 5 | -------------------------------------------------------------------------------- /log/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package log provide reusable components to support structured and leveled logging. 3 | */ 4 | package log 5 | -------------------------------------------------------------------------------- /net/middleware/cors/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package cors provides a "Cross Origin Resource Sharing" middleware. 3 | */ 4 | package cors 5 | -------------------------------------------------------------------------------- /proto/sample/v1/doc.go: -------------------------------------------------------------------------------- 1 | // Package samplev1 provides sample Protocol Buffer definitions for dummy services. 2 | package samplev1 3 | -------------------------------------------------------------------------------- /internal/crypto/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package crypto provides private utilities used by several crypto sub-packages. 3 | */ 4 | package crypto 5 | -------------------------------------------------------------------------------- /internal/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package internal groups helpers and private utilities used by several sub-packages. 3 | */ 4 | package internal 5 | -------------------------------------------------------------------------------- /net/middleware/logging/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package logging generates flexible logs from processed HTTP requests. 3 | */ 4 | package logging 5 | -------------------------------------------------------------------------------- /otel/grpc/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package otelgrpc provide instrumentation primitives for gRPC clients and servers. 3 | */ 4 | package otelgrpc 5 | -------------------------------------------------------------------------------- /metadata/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package metadata provides simple data management tools commonly used by other utilities. 3 | */ 4 | package metadata 5 | -------------------------------------------------------------------------------- /net/middleware/hsts/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package hsts provides a HTTP Strict Transport Security middleware implementation. 3 | */ 4 | package hsts 5 | -------------------------------------------------------------------------------- /net/middleware/gzip/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package gzip provides data compression of HTTP responses for clients that support it. 3 | */ 4 | package gzip 5 | -------------------------------------------------------------------------------- /net/middleware/recovery/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package recovery allows an HTTP server to recover from unhandled panic events. 3 | */ 4 | package recovery 5 | -------------------------------------------------------------------------------- /net/middleware/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package middleware provides common extensions required for production HTTP applications. 3 | */ 4 | package middleware 5 | -------------------------------------------------------------------------------- /net/middleware/headers/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package headers provides a middleware to add HTTP headers to all generated responses. 3 | */ 4 | package headers 5 | -------------------------------------------------------------------------------- /net/middleware/proxy/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package proxy adjust values managed by reverse proxy headers on incoming HTTP requests. 3 | */ 4 | package proxy 5 | -------------------------------------------------------------------------------- /prometheus/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package prometheus provides utilities to collect and consume metrics (instrumentation data). 3 | */ 4 | package prometheus 5 | -------------------------------------------------------------------------------- /net/middleware/metadata/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package metadata allows to set/get additional context details from/on HTTP requests. 3 | */ 4 | package metadata 5 | -------------------------------------------------------------------------------- /net/drpc/middleware/client/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package client provides common extensions (middleware) required for production DRPC clients. 3 | */ 4 | package client 5 | -------------------------------------------------------------------------------- /net/drpc/middleware/server/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package server provides common extensions (middleware) required for production DRPC servers. 3 | */ 4 | package server 5 | -------------------------------------------------------------------------------- /otel/http/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package otelhttp provide utilities to instrument HTTP clients and servers based on Go's net/http package. 3 | */ 4 | package otelhttp 5 | -------------------------------------------------------------------------------- /net/http/sample-openapi/petstore/oas_interfaces_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by ogen, DO NOT EDIT. 2 | package api 3 | 4 | type GetPetByIdRes interface { 5 | getPetByIdRes() 6 | } 7 | -------------------------------------------------------------------------------- /otel/temporal/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package temporal provides OTEL instrumentation for Temporal workflows. 3 | 4 | More information: https://docs.temporal.io/dev-guide/go 5 | */ 6 | package temporal 7 | -------------------------------------------------------------------------------- /otel/gorm/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package gorm provides an OpenTelemetry instrumentation for the GORM library. 3 | 4 | More information: 5 | https://github.com/go-gorm/opentelemetry 6 | */ 7 | package gorm 8 | -------------------------------------------------------------------------------- /jose/amr/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package amr provides "Authentication Method Reference" values as described by the RFC-8176. 3 | 4 | More information: 5 | https://tools.ietf.org/html/rfc8176 6 | */ 7 | package amr 8 | -------------------------------------------------------------------------------- /otel/testdata/prometheus.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | scrape_configs: 5 | - job_name: "prometheus" 6 | static_configs: 7 | - targets: ["localhost:9090"] 8 | -------------------------------------------------------------------------------- /net/middleware/rate/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package rate provides a rate limiter middleware based on a "token bucket" implementation. 3 | 4 | More information: https://en.wikipedia.org/wiki/Token_bucket 5 | */ 6 | package rate 7 | -------------------------------------------------------------------------------- /amqp/utils.go: -------------------------------------------------------------------------------- 1 | package amqp 2 | 3 | import ( 4 | "crypto/rand" 5 | "fmt" 6 | ) 7 | 8 | func getName(prefix string) string { 9 | seed := make([]byte, 4) 10 | _, _ = rand.Read(seed) 11 | return fmt.Sprintf("%s-%x", prefix, seed) 12 | } 13 | -------------------------------------------------------------------------------- /net/drpc/middleware/server/interface.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "storj.io/drpc" 5 | ) 6 | 7 | // Middleware elements allow to customize the internal requests processing 8 | // by the server. 9 | type Middleware func(drpc.Handler) drpc.Handler 10 | -------------------------------------------------------------------------------- /net/drpc/testdata/ca.sample_key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIFYgGfEIA5n5jNiVhQefD7cVBQxjVZJHB57yV5v3ezKSoAoGCCqGSM49 3 | AwEHoUQDQgAEfW23X0vMp28Z6UFzTm0b09gBlAGVHm04uKwPa3/e9eX6YOcoQfXt 4 | boeMOXqH6ECRapOrKA4mrZcPqfLuStPisA== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /net/http/testdata/ca.sample_key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIGRlNKxzi7Gmh/7ktsIzBao4HfyrwDg/3qv351sgcwlToAoGCCqGSM49 3 | AwEHoUQDQgAEHxGF4Ux/nTqT0j5hWxnILS0FFsWWyCigjiPcLEfSGMtQfAJ3Rhva 4 | 4ev63PLMbDZOtm7NG11HuqS60op6Gk3gFw== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /net/rpc/testdata/bad.sample_key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIOb3tKNa/SQI8G+m2Min9K2QcAatB3h8S0bpsaCnheZqoAoGCCqGSM49 3 | AwEHoUQDQgAEEpNgG1nquG4ea5CvPXu97MpFT1lA0+/p9FLmrj6G0FRSslIXpf4M 4 | txYWjBiG8Tdin98sA6z4lK9YxqEbYXFQ8Q== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /net/rpc/testdata/ca.sample_key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIFYgGfEIA5n5jNiVhQefD7cVBQxjVZJHB57yV5v3ezKSoAoGCCqGSM49 3 | AwEHoUQDQgAEfW23X0vMp28Z6UFzTm0b09gBlAGVHm04uKwPa3/e9eX6YOcoQfXt 4 | boeMOXqH6ECRapOrKA4mrZcPqfLuStPisA== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /net/drpc/testdata/bad.sample_key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIOb3tKNa/SQI8G+m2Min9K2QcAatB3h8S0bpsaCnheZqoAoGCCqGSM49 3 | AwEHoUQDQgAEEpNgG1nquG4ea5CvPXu97MpFT1lA0+/p9FLmrj6G0FRSslIXpf4M 4 | txYWjBiG8Tdin98sA6z4lK9YxqEbYXFQ8Q== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /net/drpc/testdata/server.sample_key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIDcXqYbkd196W9XnRFfHpB2bUXJfCYvw409axiDIhgQgoAoGCCqGSM49 3 | AwEHoUQDQgAE3CntD6zXf4sHBh8OOTxnYUEznBAEi/3FWMv6Su03Blls9YGA11vo 4 | RrjrE/+Rd0gtsYLUbevTvUIdzsLPtEIssQ== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /net/http/sample-openapi/petstore/oas_middleware_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by ogen, DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "github.com/ogen-go/ogen/middleware" 7 | ) 8 | 9 | // Middleware is middleware type. 10 | type Middleware = middleware.Middleware 11 | -------------------------------------------------------------------------------- /net/http/testdata/server.sample_key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIGS4tf7BCmN01KKpK/wJ2wDq/kaMBUyeJJH6cipzw+TyoAoGCCqGSM49 3 | AwEHoUQDQgAE22r0HhvUeK+bJ9AhQbkAZyW353xLhO0ZlOVKsCHxo1J0PJf47qol 4 | Bcbpj8fU6rlrD7fsdZ4zmr0IWtfBPMdEqw== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /net/rpc/testdata/server.sample_key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIDcXqYbkd196W9XnRFfHpB2bUXJfCYvw409axiDIhgQgoAoGCCqGSM49 3 | AwEHoUQDQgAE3CntD6zXf4sHBh8OOTxnYUEznBAEi/3FWMv6Su03Blls9YGA11vo 4 | RrjrE/+Rd0gtsYLUbevTvUIdzsLPtEIssQ== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package pkg provides a public collection of development resources and utilities. 3 | 4 | Contents on this package are to be considered under heavy development. This 5 | means interfaces (APIs) may change at any time, sometimes dramatically so. 6 | */ 7 | package pkg 8 | -------------------------------------------------------------------------------- /otel/sdk/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package sdk provides the utilities necessary to setup a monitoring implementation at runtime. 3 | 4 | Setting up a specific monitoring pipeline/stack is independent of instrumenting an 5 | application or library. For instrumentation utilities use the `api` package. 6 | */ 7 | package sdk 8 | -------------------------------------------------------------------------------- /otel/api/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package api provides the utilities necessary to instrument an application or library. 3 | 4 | The instrumentation of a piece of code is independent of setting up any specific 5 | monitoring implementation when executing it. To setup a monitoring pipeline/stack 6 | at runtime use the `sdk` package. 7 | */ 8 | package api 9 | -------------------------------------------------------------------------------- /otel/mongodb/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package mongodb provides OTEL instrumentation for the MongoDB Go Driver. 3 | 4 | This package simply provides a wrapper around the original Go-contrib version 5 | of the MongoDB instrumentation, so that it can be imported as a single dependency 6 | and avoid issues with multiple versions of the same instrumentation. 7 | */ 8 | package mongodb 9 | -------------------------------------------------------------------------------- /otel/mongodb/monitor.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "go.mongodb.org/mongo-driver/event" 5 | "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" 6 | ) 7 | 8 | // NewMonitor creates a new mongodb event CommandMonitor. 9 | func NewMonitor() *event.CommandMonitor { 10 | return otelmongo.NewMonitor(otelmongo.WithCommandAttributeDisabled(false)) 11 | } 12 | -------------------------------------------------------------------------------- /otel/sdk/no_op.go: -------------------------------------------------------------------------------- 1 | package sdk 2 | 3 | import ( 4 | "context" 5 | 6 | sdkTrace "go.opentelemetry.io/otel/sdk/trace" 7 | ) 8 | 9 | // No-op exporter. 10 | type noOpExporter struct{} 11 | 12 | func (n *noOpExporter) ExportSpans(_ context.Context, _ []sdkTrace.ReadOnlySpan) error { 13 | return nil 14 | } 15 | 16 | func (n *noOpExporter) Shutdown(_ context.Context) error { 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generals 2 | .DS_Store 3 | .idea 4 | .vscode 5 | 6 | # Deps 7 | vendor/** 8 | 9 | # NodeJS 10 | node_modules 11 | package-lock.json 12 | build 13 | 14 | # PKI 15 | *.crt 16 | *.csr 17 | *.cer 18 | *.pem 19 | *.key 20 | !**/testdata/*.cer 21 | !**/testdata/*.pem 22 | 23 | # Secret files 24 | **/*secret_* 25 | 26 | # Code coverage reports 27 | coverage.* 28 | 29 | # CodeQL 30 | .codeql 31 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | # top-most config file 3 | root = true 4 | 5 | # Default styles: 6 | # - UNIX-style newlines 7 | # - newline ending every file 8 | # - 2 space indents 9 | [*] 10 | charset = utf-8 11 | end_of_line = lf 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.go] 17 | indent_style = tab 18 | 19 | [Makefile] 20 | indent_style = tab 21 | -------------------------------------------------------------------------------- /log/discard.go: -------------------------------------------------------------------------------- 1 | //go:build !go1.16 2 | // +build !go1.16 3 | 4 | package log 5 | 6 | import ( 7 | "io/ioutil" 8 | stdL "log" 9 | ) 10 | 11 | // Discard returns a no-op handler that will discard all generated output. 12 | func Discard() Logger { 13 | return &stdLogger{ 14 | log: stdL.New(ioutil.Discard, "", 0), 15 | tags: metadata.New(), 16 | fields: metadata.New(), 17 | discard: true, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /net/http/sample-openapi/petstore/oas_operations_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by ogen, DO NOT EDIT. 2 | 3 | package api 4 | 5 | // OperationName is the ogen operation name 6 | type OperationName = string 7 | 8 | const ( 9 | AddPetOperation OperationName = "AddPet" 10 | DeletePetOperation OperationName = "DeletePet" 11 | GetPetByIdOperation OperationName = "GetPetById" 12 | UpdatePetOperation OperationName = "UpdatePet" 13 | ) 14 | -------------------------------------------------------------------------------- /log/discard_1_16.go: -------------------------------------------------------------------------------- 1 | //go:build go1.16 2 | // +build go1.16 3 | 4 | package log 5 | 6 | import ( 7 | "io" 8 | stdL "log" 9 | 10 | "go.bryk.io/pkg/metadata" 11 | ) 12 | 13 | // Discard returns a no-op handler that will discard all generated output. 14 | func Discard() Logger { 15 | return &stdLogger{ 16 | log: stdL.New(io.Discard, "", 0), 17 | tags: metadata.New(), 18 | fields: metadata.New(), 19 | discard: true, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /net/middleware/csrf/options.go: -------------------------------------------------------------------------------- 1 | package csrf 2 | 3 | // Options available to adjust the behavior of the CSRF protection 4 | // middleware. 5 | type Options struct { 6 | // Allow requests coming from specific origins. The values listed here 7 | // must of the form "scheme://host[:port]". 8 | TrustedOrigins []string 9 | 10 | // Permits all requests that match the given pattern; this is considered 11 | // insecure. 12 | BypassPattern string 13 | } 14 | -------------------------------------------------------------------------------- /jose/jwa/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package jwa provides cryptographic algorithm identifiers as described by RFC-7518. 3 | 4 | The specification registers cryptographic algorithms and identifiers 5 | to be used with the JSON Web Signature (JWS), JSON Web Encryption 6 | (JWE), and JSON Web Key (JWK) specifications. It defines several 7 | IANA registries for these identifiers. 8 | 9 | More information: 10 | https://www.rfc-editor.org/rfc/rfc7518.html 11 | */ 12 | package jwa 13 | -------------------------------------------------------------------------------- /cli/viper/testdata/config.yaml: -------------------------------------------------------------------------------- 1 | http: 2 | port: 8080 3 | idle_timeout: 10 4 | middleware: 5 | cors: 6 | allow_credentials: true 7 | ignore_options: false 8 | allowed_headers: 9 | - content-type 10 | - x-api-key 11 | allowed_methods: 12 | - get 13 | - head 14 | - post 15 | - options 16 | allowed_origins: 17 | - "*" 18 | exposed_headers: 19 | - x-api-key 20 | max_age: 300 21 | options_status_code: 200 22 | -------------------------------------------------------------------------------- /net/sse/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package sse provides a "Server-Send Events" server/client implementation. 3 | 4 | Traditionally, a web page has to send a request to the server to receive new 5 | data; that is, the page requests data from the server. With server-sent events, 6 | it's possible for a server to send new data to a web page at any time, by 7 | pushing messages to the web page. 8 | 9 | More information: 10 | https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events 11 | */ 12 | package sse 13 | -------------------------------------------------------------------------------- /buf.yaml: -------------------------------------------------------------------------------- 1 | version: v2 2 | lint: 3 | service_suffix: API 4 | rpc_allow_google_protobuf_empty_requests: true 5 | use: 6 | - STANDARD 7 | except: 8 | - RPC_REQUEST_RESPONSE_UNIQUE 9 | - RPC_RESPONSE_STANDARD_NAME 10 | #- PACKAGE_DIRECTORY_MATCH 11 | breaking: 12 | use: 13 | - FILE 14 | modules: 15 | - path: proto 16 | deps: 17 | - buf.build/googleapis/googleapis:61b203b9a9164be9a834f58c37be6f62 18 | - buf.build/bufbuild/protovalidate:v1.1.0 19 | - buf.build/grpc-ecosystem/grpc-gateway:v2.27.3 20 | -------------------------------------------------------------------------------- /net/middleware/headers/handler.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | import "net/http" 4 | 5 | // Handler can be used to add a set of HTTP headers to all responses 6 | // produced by an HTTP server. 7 | func Handler(headers map[string]string) func(http.Handler) http.Handler { 8 | return func(next http.Handler) http.Handler { 9 | fn := func(w http.ResponseWriter, r *http.Request) { 10 | for k, v := range headers { 11 | w.Header().Set(k, v) 12 | } 13 | next.ServeHTTP(w, r) 14 | } 15 | return http.HandlerFunc(fn) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/assets/utils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Setup runner environment 4 | setup() { 5 | # Configure git to access private Go modules using the 6 | # provided personal access token. 7 | # https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token 8 | git config --global \ 9 | url."https://${GITHUB_USER}:${ACCESS_TOKEN}@github.com".insteadOf "https://github.com" 10 | } 11 | 12 | case $1 in 13 | "setup") 14 | setup 15 | ;; 16 | 17 | *) 18 | echo "Invalid target: $1" 19 | ;; 20 | esac 21 | -------------------------------------------------------------------------------- /net/middleware/csrf/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package csrf provides a "Cross-site Request Forgery" protection middleware. 3 | 4 | In a cross-site request forgery (CSRF) attack, an attacker tricks the user 5 | or the browser into making an HTTP request to the target site from a malicious 6 | site. The request includes the user's credentials and causes the server to 7 | carry out some harmful action, thinking that the user intended it. 8 | 9 | More information: 10 | https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/CSRF 11 | */ 12 | package csrf 13 | -------------------------------------------------------------------------------- /net/http/sample-openapi/petstore/oas_request_encoders_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by ogen, DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "bytes" 7 | "net/http" 8 | 9 | "github.com/go-faster/jx" 10 | 11 | ht "github.com/ogen-go/ogen/http" 12 | ) 13 | 14 | func encodeAddPetRequest( 15 | req *Pet, 16 | r *http.Request, 17 | ) error { 18 | const contentType = "application/json" 19 | e := new(jx.Encoder) 20 | { 21 | req.Encode(e) 22 | } 23 | encoded := e.Bytes() 24 | ht.SetBody(r, bytes.NewReader(encoded), contentType) 25 | return nil 26 | } 27 | -------------------------------------------------------------------------------- /net/rpc/resource_limits.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | // ResourceLimits allows setting constrains for the RPC server. 4 | type ResourceLimits struct { 5 | // Maximum number of simultaneous RPC connections (clients). 6 | Connections uint32 `json:"connections" yaml:"connections" mapstructure:"connections"` 7 | 8 | // Maximum number of simultaneous RPC calls per-client. 9 | Requests uint32 `json:"requests" yaml:"requests" mapstructure:"requests"` 10 | 11 | // Maximum number of RPC calls per-second (total). 12 | Rate uint32 `json:"rate" yaml:"rate" mapstructure:"rate"` 13 | } 14 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v2.3.0 4 | hooks: 5 | - id: end-of-file-fixer 6 | - id: trailing-whitespace 7 | - repo: https://github.com/gitleaks/gitleaks 8 | rev: v8.24.2 9 | hooks: 10 | - id: gitleaks 11 | name: Gitleaks 12 | - repo: local 13 | hooks: 14 | - id: lint-and-test 15 | name: Lint and Test 16 | entry: ./.pre-commit.sh 17 | language: system 18 | always_run: true 19 | pass_filenames: false 20 | verbose: true 21 | -------------------------------------------------------------------------------- /jose/jwk/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package jwk implements JSON Web Key as described in RFC-7517. 3 | 4 | A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data 5 | structure that represents a cryptographic key. This specification 6 | also defines a JWK Set JSON data structure that represents a set of 7 | JWKs. Cryptographic algorithms and identifiers for use with this 8 | specification are described in the separate JSON Web Algorithms (JWA) 9 | specification and IANA registries established by that specification. 10 | 11 | More information: 12 | https://www.rfc-editor.org/rfc/rfc7517.html 13 | */ 14 | package jwk 15 | -------------------------------------------------------------------------------- /jose/jwt/validator_options.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "go.bryk.io/pkg/jose/jwk" 5 | ) 6 | 7 | // ValidatorOption elements provide a functional-style configuration mechanism 8 | // for token validators. 9 | type ValidatorOption func(v *Validator) error 10 | 11 | // WithValidationKeys registers the keys provided in the JWK set to be used 12 | // for token validation. 13 | func WithValidationKeys(set jwk.Set) ValidatorOption { 14 | return func(v *Validator) error { 15 | keys, err := expandSet(set) 16 | if err != nil { 17 | return err 18 | } 19 | v.keys = append(v.keys, keys...) 20 | return nil 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /net/http/README.md: -------------------------------------------------------------------------------- 1 | # Package `http` 2 | 3 | Provide common utilities when deploying a production HTTP(S) service. The 4 | main element of the package is the "Server" type. Use it to easily create 5 | and manage an HTTP(S) server instance. 6 | 7 | ```go 8 | // Server options 9 | options := []Option{ 10 | WithPort(8080), 11 | WithIdleTimeout(5 * time.Second), 12 | WithHandler(mux), 13 | } 14 | 15 | // Create and start the server in the background 16 | server, _ := NewServer(options...) 17 | go func() { 18 | _ = server.Start() 19 | }() 20 | 21 | // When no longer required, gracefully stop the server 22 | _ = server.Stop(true) 23 | ``` 24 | -------------------------------------------------------------------------------- /net/http/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package http provide common utilities when deploying a production HTTP(S) service. 3 | 4 | The main element of the package is the "Server" type. Use it to easily create 5 | and manage an HTTP(S) server instance. 6 | 7 | // Server options 8 | options := []Option{ 9 | WithPort(8080), 10 | WithIdleTimeout(5 * time.Second), 11 | WithHandler(mux), 12 | } 13 | 14 | // Create and start the server in the background 15 | server, _ := NewServer(options...) 16 | go func() { 17 | _ = server.Start() 18 | }() 19 | 20 | // When no longer required, gracefully stop the server 21 | _ = server.Stop(true) 22 | */ 23 | package http 24 | -------------------------------------------------------------------------------- /cli/params_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | ) 6 | 7 | // Register a list of parameters to a sample command. 8 | func ExampleSetupCommandParams() { 9 | sampleCmd := &cobra.Command{} 10 | parameters := []Param{ 11 | { 12 | Name: "name-of-parameter", 13 | Usage: "describe the parameter use or intent", 14 | FlagKey: "cmd.parameter.name", 15 | ByDefault: 9090, 16 | }, 17 | { 18 | Name: "bool-flag", 19 | Usage: "parameters support several basic types", 20 | FlagKey: "cmd.parameter.flag", 21 | ByDefault: false, 22 | }, 23 | } 24 | if err := SetupCommandParams(sampleCmd, parameters); err != nil { 25 | panic(err) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /net/drpc/ws/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package ws provides a WebSocket proxy with support for bidirectional streaming on DRPC servers. 3 | 4 | The proxy is intended to enhance the functionality provided by the standard 5 | DRPC packages by allowing bidirectional streaming using websockets. 6 | 7 | // Create a new proxy instance 8 | proxy, _ := New(EnableCompression()) 9 | 10 | // Obtain the original HTTP handler from your DRPC server mux 11 | handler := drpchttp.New(srv.mux) 12 | 13 | // Get a new handler enhanced with the proxy functionality 14 | enhanced := proxy.Wrap(srv.mux, drpchttp.New(srv.mux)) 15 | 16 | // Use the enhanced handler as usual 17 | return http.ListenAndServe(":9090", enhanced) 18 | */ 19 | package ws 20 | -------------------------------------------------------------------------------- /net/rpc/ws/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package ws provides a WebSocket proxy with support for bidirectional streaming. 3 | 4 | The proxy is intended to enhance the functionality provided by grpc-gateway 5 | with bidirectional streaming support. 6 | 7 | // Create a new proxy instance 8 | proxy, _ := New(EnableCompression()) 9 | 10 | // Obtain the handler from the gRPC Gateway instance 11 | handler := get_gateway_http_handler() 12 | 13 | // Get a new handler enhanced with the proxy functionality 14 | enhanced := proxy.Wrap(handler) 15 | 16 | // Use the enhanced handler as usual 17 | return http.ListenAndServe(":9090", enhanced) 18 | 19 | Original project: 20 | https://github.com/tmc/grpc-websocket-proxy 21 | */ 22 | package ws 23 | -------------------------------------------------------------------------------- /net/middleware/gzip/handler.go: -------------------------------------------------------------------------------- 1 | package gzip 2 | 3 | import ( 4 | "net/http" 5 | 6 | gmw "github.com/gorilla/handlers" 7 | ) 8 | 9 | // Handler enables gzip compression of HTTP responses for clients that 10 | // support it via the 'Accept-Encoding' header. The compression level 11 | // should be any integer value between `1` (optimal speed) and `9` 12 | // (optimal compression) inclusive. 13 | // 14 | // Compressing TLS traffic may leak the page contents to an attacker if 15 | // the page contains user input: http://security.stackexchange.com/a/102015/12208 16 | func Handler(level int) func(http.Handler) http.Handler { 17 | return func(next http.Handler) http.Handler { 18 | return gmw.CompressHandlerLevel(next, level) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /net/middleware/recovery/handler.go: -------------------------------------------------------------------------------- 1 | package recovery 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | // Handler allows the server to convert unhandled panic events into an 9 | // `internal server error`. This will prevent the server from crashing if a 10 | // handler produces a `panic` operation. 11 | func Handler() func(handler http.Handler) http.Handler { 12 | return func(next http.Handler) http.Handler { 13 | fn := func(w http.ResponseWriter, r *http.Request) { 14 | defer func() { 15 | if v := recover(); v != nil { 16 | w.WriteHeader(http.StatusInternalServerError) 17 | _, _ = fmt.Fprintf(w, "%s", v) 18 | } 19 | }() 20 | next.ServeHTTP(w, r) 21 | } 22 | return http.HandlerFunc(fn) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /errors/codec.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | // Codec implementations provide a pluggable way to manage error across 4 | // service boundaries; for example when transmitting error messages through 5 | // a network. 6 | type Codec interface { 7 | // Encodes an error instance and produce a report. 8 | Marshal(err error) ([]byte, error) 9 | 10 | // Decoded an error report and restore an error instance. 11 | // If this operation fails for whatever reason `ok` should 12 | // be `false`. 13 | Unmarshal(src []byte) (ok bool, err error) 14 | } 15 | 16 | // Report an error instance by generating a portable/transmissible 17 | // representation of it using the provided codec. 18 | func Report(err error, cc Codec) ([]byte, error) { 19 | return cc.Marshal(err) 20 | } 21 | -------------------------------------------------------------------------------- /net/drpc/testdata/ca.sample_cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB2jCCAX+gAwIBAgIUEiIJNX03RobWZd3xXgRgjcjP1RQwCgYIKoZIzj0EAwIw 3 | QjELMAkGA1UEBhMCTVgxFjAUBgNVBAoTDUJyeWsgTGFicyBMTEMxDDAKBgNVBAsM 4 | A1ImRDENMAsGA1UEAxMEYnJ5azAeFw0yNDA3MDQxODAxMDBaFw0yOTA3MDMxODAx 5 | MDBaMEIxCzAJBgNVBAYTAk1YMRYwFAYDVQQKEw1CcnlrIExhYnMgTExDMQwwCgYD 6 | VQQLDANSJkQxDTALBgNVBAMTBGJyeWswWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC 7 | AAR9bbdfS8ynbxnpQXNObRvT2AGUAZUebTi4rA9rf9715fpg5yhB9e1uh4w5eofo 8 | QJFqk6soDiatlw+p8u5K0+Kwo1MwUTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0lBAgw 9 | BgYEVR0lADAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQEWQCJhr1W0Lc0HJVZ 10 | +UwxbbDDWTAKBggqhkjOPQQDAgNJADBGAiEAxaGObYAkJie/LdozOxKOpdFvGreu 11 | DfZGSEc4li92ds4CIQCVDFNHKgL+CROilY7GKM4hEejh60Ygp/POjTx4Jpdgtg== 12 | -----END CERTIFICATE----- 13 | -------------------------------------------------------------------------------- /net/rpc/testdata/ca.sample_cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB2jCCAX+gAwIBAgIUEiIJNX03RobWZd3xXgRgjcjP1RQwCgYIKoZIzj0EAwIw 3 | QjELMAkGA1UEBhMCTVgxFjAUBgNVBAoTDUJyeWsgTGFicyBMTEMxDDAKBgNVBAsM 4 | A1ImRDENMAsGA1UEAxMEYnJ5azAeFw0yNDA3MDQxODAxMDBaFw0yOTA3MDMxODAx 5 | MDBaMEIxCzAJBgNVBAYTAk1YMRYwFAYDVQQKEw1CcnlrIExhYnMgTExDMQwwCgYD 6 | VQQLDANSJkQxDTALBgNVBAMTBGJyeWswWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC 7 | AAR9bbdfS8ynbxnpQXNObRvT2AGUAZUebTi4rA9rf9715fpg5yhB9e1uh4w5eofo 8 | QJFqk6soDiatlw+p8u5K0+Kwo1MwUTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0lBAgw 9 | BgYEVR0lADAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQEWQCJhr1W0Lc0HJVZ 10 | +UwxbbDDWTAKBggqhkjOPQQDAgNJADBGAiEAxaGObYAkJie/LdozOxKOpdFvGreu 11 | DfZGSEc4li92ds4CIQCVDFNHKgL+CROilY7GKM4hEejh60Ygp/POjTx4Jpdgtg== 12 | -----END CERTIFICATE----- 13 | -------------------------------------------------------------------------------- /net/middleware/csrf/handler_prev.go: -------------------------------------------------------------------------------- 1 | //go:build !go1.25 2 | 3 | package csrf 4 | 5 | import ( 6 | "net/http" 7 | 8 | "filippo.io/csrf" 9 | ) 10 | 11 | // Handler returns a middleware that applies cross-origin checks on incoming 12 | // requests. If a request fails cross-origin checks, the request is rejected 13 | // with a `403 Forbidden` status. 14 | func Handler(options *Options) func(http.Handler) http.Handler { 15 | ch := csrf.New() 16 | if options != nil { 17 | for _, origin := range options.TrustedOrigins { 18 | _ = ch.AddTrustedOrigin(origin) 19 | } 20 | if options.BypassPattern != "" { 21 | ch.AddUnsafeBypassPattern(options.BypassPattern) 22 | } 23 | } 24 | 25 | return func(next http.Handler) http.Handler { 26 | return ch.Handler(next) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /proto/sample/v1/model.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sample.v1; 4 | 5 | import "buf/validate/validate.proto"; 6 | 7 | // Reachability test response. 8 | message Pong { 9 | // Whether the service is 'ready-for-use' 10 | bool ok = 1; 11 | } 12 | 13 | // Health test response. 14 | message HealthResponse { 15 | // Generic availability check, set to 'false' in case of errors. 16 | bool alive = 1; 17 | } 18 | 19 | // Generic request response. 20 | message Response { 21 | // A key on the entity 22 | string name = 1 [(buf.validate.field).string = { 23 | min_len: 2 24 | max_len: 5 25 | }]; 26 | } 27 | 28 | // Sample response structure. 29 | message DummyResponse { 30 | // Generic status check, set to 'false' in case of errors. 31 | bool ok = 1; 32 | } 33 | -------------------------------------------------------------------------------- /buf.lock: -------------------------------------------------------------------------------- 1 | # Generated by buf. DO NOT EDIT. 2 | version: v2 3 | deps: 4 | - name: buf.build/bufbuild/protovalidate 5 | commit: 2a1774d888024a9b93ce7eb4b59f6a83 6 | digest: b5:6b7f9bc919b65e5b79d7b726ffc03d6f815a412d6b792970fa6f065cae162107bd0a9d47272c8ab1a2c9514e87b13d3fbf71df614374d62d2183afb64be2d30a 7 | - name: buf.build/googleapis/googleapis 8 | commit: 61b203b9a9164be9a834f58c37be6f62 9 | digest: b5:7811a98b35bd2e4ae5c3ac73c8b3d9ae429f3a790da15de188dc98fc2b77d6bb10e45711f14903af9553fa9821dff256054f2e4b7795789265bc476bec2f088c 10 | - name: buf.build/grpc-ecosystem/grpc-gateway 11 | commit: 4c5ba75caaf84e928b7137ae5c18c26a 12 | digest: b5:c113e62fb3b29289af785866cae062b55ec8ae19ab3f08f3004098928fbca657730a06810b2012951294326b95669547194fa84476b9e9b688d4f8bf77a0691d 13 | -------------------------------------------------------------------------------- /otel/http/utils.go: -------------------------------------------------------------------------------- 1 | package otelhttp 2 | 3 | import "net/http" 4 | 5 | // FilterByPath will omit instrumentation for requests that match any 6 | // of the provided paths. 7 | func FilterByPath(paths []string) Filter { 8 | return func(r *http.Request) bool { 9 | for _, path := range paths { 10 | if r.URL.Path == path { 11 | return false 12 | } 13 | } 14 | return true 15 | } 16 | } 17 | 18 | // FilterByHeaders will omit instrumentation for requests that include 19 | // any of the provided key-value pairs in their headers. 20 | func FilterByHeaders(headers map[string]string) Filter { 21 | return func(r *http.Request) bool { 22 | for key, value := range headers { 23 | if r.Header.Get(key) == value { 24 | return false 25 | } 26 | } 27 | return true 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /net/drpc/middleware/client/interface.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | 6 | "storj.io/drpc" 7 | ) 8 | 9 | // Interceptor defines a simplified version of the `drpcconn.Conn` 10 | // interface for elements wishing to extend the client's RPC processing 11 | // functionality using middleware pattern. 12 | type Interceptor interface { 13 | // Invoke issues a unary RPC to the remote. 14 | Invoke(ctx context.Context, rpc string, enc drpc.Encoding, in, out drpc.Message) error 15 | 16 | // NewStream starts a stream with the remote. 17 | NewStream(ctx context.Context, rpc string, enc drpc.Encoding) (drpc.Stream, error) 18 | } 19 | 20 | // Middleware elements allow to customize and extend the RPC requests 21 | // processing by the client. 22 | type Middleware func(Interceptor) Interceptor 23 | -------------------------------------------------------------------------------- /net/rpc/ws/response.go: -------------------------------------------------------------------------------- 1 | package ws 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | ) 7 | 8 | type responseWriter struct { 9 | header http.Header 10 | code int 11 | closed chan bool 12 | io.Writer 13 | } 14 | 15 | func newResponseWriter(w io.Writer) *responseWriter { 16 | return &responseWriter{ 17 | Writer: w, 18 | header: http.Header{}, 19 | closed: make(chan bool, 1), 20 | } 21 | } 22 | 23 | func (w *responseWriter) Write(b []byte) (int, error) { 24 | return w.Writer.Write(b) 25 | } 26 | 27 | func (w *responseWriter) Header() http.Header { 28 | return w.header 29 | } 30 | 31 | func (w *responseWriter) WriteHeader(code int) { 32 | w.code = code 33 | } 34 | 35 | func (w *responseWriter) CloseNotify() <-chan bool { 36 | return w.closed 37 | } 38 | 39 | func (w *responseWriter) Flush() {} 40 | -------------------------------------------------------------------------------- /otel/temporal/span.go: -------------------------------------------------------------------------------- 1 | package temporal 2 | 3 | import ( 4 | apiTrace "go.bryk.io/pkg/otel/api" 5 | "go.opentelemetry.io/otel/trace" 6 | "go.temporal.io/sdk/interceptor" 7 | ) 8 | 9 | type spanContextKey struct{} 10 | 11 | type tracerSpanRef struct{ trace.SpanContext } 12 | 13 | type tracerSpan struct{ apiTrace.Span } 14 | 15 | func (t *tracerSpan) Finish(opts *interceptor.TracerFinishSpanOptions) { 16 | t.End(opts.Error) 17 | } 18 | 19 | type textMapCarrier map[string]string 20 | 21 | func (t textMapCarrier) Get(key string) string { return t[key] } 22 | func (t textMapCarrier) Set(key string, value string) { t[key] = value } 23 | func (t textMapCarrier) Keys() []string { 24 | ret := make([]string, 0, len(t)) 25 | for k := range t { 26 | ret = append(ret, k) 27 | } 28 | return ret 29 | } 30 | -------------------------------------------------------------------------------- /net/middleware/csrf/handler.go: -------------------------------------------------------------------------------- 1 | //go:build go1.25 2 | 3 | package csrf 4 | 5 | import "net/http" 6 | 7 | // Reference: 8 | // https://words.filippo.io/csrf/ 9 | 10 | // Handler returns a middleware that applies cross-origin checks on incoming 11 | // requests. If a request fails cross-origin checks, the request is rejected 12 | // with a `403 Forbidden` status. 13 | func Handler(options *Options) func(http.Handler) http.Handler { 14 | ch := new(http.CrossOriginProtection) 15 | if options != nil { 16 | for _, origin := range options.TrustedOrigins { 17 | _ = ch.AddTrustedOrigin(origin) 18 | } 19 | if options.BypassPattern != "" { 20 | ch.AddInsecureBypassPattern(options.BypassPattern) 21 | } 22 | } 23 | 24 | return func(next http.Handler) http.Handler { 25 | return ch.Handler(next) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /net/rpc/rate.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "context" 5 | 6 | "golang.org/x/time/rate" 7 | "google.golang.org/grpc/codes" 8 | "google.golang.org/grpc/status" 9 | "google.golang.org/grpc/tap" 10 | ) 11 | 12 | type rateTap struct { 13 | limit *rate.Limiter 14 | } 15 | 16 | func (t *rateTap) handler(ctx context.Context, info *tap.Info) (context.Context, error) { 17 | if !t.limit.Allow() { 18 | return nil, status.Errorf(codes.ResourceExhausted, "service rate limit exceeded: %s", info.FullMethodName) 19 | } 20 | return ctx, nil 21 | } 22 | 23 | // WithRateLimit will attach a simple rate limit handler on the server with a burst 24 | // of 20% on the provided value. 25 | func newRateTap(limit uint32) *rateTap { 26 | return &rateTap{ 27 | limit: rate.NewLimiter(rate.Limit(limit), int(limit/20)), 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /otel/testdata/otel-js/api.js: -------------------------------------------------------------------------------- 1 | import opentelemetry from '@opentelemetry/api'; 2 | 3 | // API is required to instrument an application manually. 4 | // https://opentelemetry.io/docs/instrumentation/js/manual 5 | 6 | const tracerName = '@bryk-io/otel'; 7 | const tracerVersion = '0.1.0'; 8 | 9 | /** 10 | * Start a new span with the given name and execute the provided function. 11 | * The span will be automatically closed once the function returns. 12 | * @param {string} name Span name. 13 | * @returns {object} 14 | */ 15 | export function Start(name) { 16 | return opentelemetry.trace.getTracer(tracerName, tracerVersion).startSpan(name); 17 | } 18 | 19 | /** 20 | * Retrieve the currently active span. 21 | * @returns {object} 22 | */ 23 | export function GetActiveSpan() { 24 | return opentelemetry.trace.getActiveSpan(); 25 | } 26 | -------------------------------------------------------------------------------- /net/http/testdata/ca.sample_cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICDTCCAbOgAwIBAgIUZb7pUqzXaZ0PqA1PCphaw0R6P54wCgYIKoZIzj0EAwIw 3 | ZDELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFUJyeWsgVGVjaG5vbG9naWVzIExMQzEX 4 | MBUGA1UECxMOU2FtcGxlIFJvb3QgQ0ExHDAaBgNVBAMTE0JyeWsgU2FtcGxlIFJv 5 | b3QgQ0EwHhcNMTkwNjEzMDM0NjAwWhcNMjQwNjExMDM0NjAwWjBkMQswCQYDVQQG 6 | EwJVUzEeMBwGA1UEChMVQnJ5ayBUZWNobm9sb2dpZXMgTExDMRcwFQYDVQQLEw5T 7 | YW1wbGUgUm9vdCBDQTEcMBoGA1UEAxMTQnJ5ayBTYW1wbGUgUm9vdCBDQTBZMBMG 8 | ByqGSM49AgEGCCqGSM49AwEHA0IABB8RheFMf506k9I+YVsZyC0tBRbFlsgooI4j 9 | 3CxH0hjLUHwCd0Yb2uHr+tzyzGw2TrZuzRtdR7qkutKKehpN4BejQzBBMA8GA1Ud 10 | JQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUaUQYhiGWLuou 11 | M499lchwXKtqoCAwCgYIKoZIzj0EAwIDSAAwRQIhAPfJz0qNnidANjwjT9roxoWU 12 | jZUyqyws+v+MMfrJOH7WAiBKBxhlDFlnKfsfEO/5OeFI5Rpgl0LvhJ82XspL0NxR 13 | 4g== 14 | -----END CERTIFICATE----- 15 | -------------------------------------------------------------------------------- /net/drpc/middleware/server/panic.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "fmt" 5 | 6 | "storj.io/drpc" 7 | ) 8 | 9 | // PanicRecovery allows the server to convert unhandled panic events into an 10 | // "internal" RPC error. This will prevent the server from crashing if a handler 11 | // produces a `panic` operation. 12 | func PanicRecovery() Middleware { 13 | return func(next drpc.Handler) drpc.Handler { 14 | return panicRecovery{ 15 | tag: "internal error", 16 | next: next, 17 | } 18 | } 19 | } 20 | 21 | type panicRecovery struct { 22 | next drpc.Handler 23 | tag string 24 | } 25 | 26 | func (md panicRecovery) HandleRPC(stream drpc.Stream, rpc string) (err error) { 27 | defer func() { 28 | if v := recover(); v != nil { 29 | err = fmt.Errorf("%s: %s", md.tag, v) 30 | } 31 | }() 32 | err = md.next.HandleRPC(stream, rpc) 33 | return 34 | } 35 | -------------------------------------------------------------------------------- /net/drpc/middleware/server/rate.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "go.bryk.io/pkg/errors" 5 | "golang.org/x/time/rate" 6 | "storj.io/drpc" 7 | ) 8 | 9 | // RateLimit enforce a maximum limit of RPC requests per-second on the 10 | // server. It is implemented as a `token bucket` instance. 11 | // More information: https://en.wikipedia.org/wiki/Token_bucket 12 | func RateLimit(limit int) Middleware { 13 | return func(next drpc.Handler) drpc.Handler { 14 | return rateLimit{ 15 | check: rate.NewLimiter(rate.Limit(limit), limit), 16 | next: next, 17 | } 18 | } 19 | } 20 | 21 | type rateLimit struct { 22 | check *rate.Limiter 23 | next drpc.Handler 24 | } 25 | 26 | func (md rateLimit) HandleRPC(stream drpc.Stream, rpc string) error { 27 | if !md.check.Allow() { 28 | return errors.New("rate: limit exceeded") 29 | } 30 | return md.next.HandleRPC(stream, rpc) 31 | } 32 | -------------------------------------------------------------------------------- /net/rpc/token.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "strings" 7 | 8 | "google.golang.org/grpc/credentials" 9 | ) 10 | 11 | // Provides the `credentials.PerRPCCredentials` interface for regular 12 | // text tokens. 13 | type authToken struct { 14 | kind string 15 | value string 16 | } 17 | 18 | func (at authToken) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { 19 | ri, _ := credentials.RequestInfoFromContext(ctx) 20 | if err := credentials.CheckSecurityLevel(ri.AuthInfo, credentials.PrivacyAndIntegrity); err != nil { 21 | return nil, fmt.Errorf("invalid connection security level: %w", err) 22 | } 23 | return map[string]string{ 24 | "authorization": at.kind + " " + at.value, 25 | "uri": strings.Join(uri, ","), 26 | }, nil 27 | } 28 | 29 | func (at authToken) RequireTransportSecurity() bool { 30 | return true 31 | } 32 | -------------------------------------------------------------------------------- /otel/sentry/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package sentry provides an OpenTelemetry exporter for Sentry. 3 | 4 | An OpenTelemetry `Span` becomes a Sentry Transaction or Span. The 5 | first Span sent through the Sentry `SpanProcessor` is a `Transaction`, 6 | and any child Span gets attached to the first Transaction upon checking 7 | the parent Span context. This is true for the OpenTelemetry root Span 8 | and any top level Span in the system. 9 | 10 | For example, a request sent from frontend to backend will create an 11 | OpenTelemetry root Span with a corresponding Sentry Transaction. The 12 | backend request will create a new Sentry Transaction for the OpenTelemetry 13 | Span. The Sentry Transaction and Span are linked as a trace for navigation 14 | and error tracking purposes. 15 | 16 | More information: 17 | https://docs.sentry.io/platforms/go/performance/instrumentation/opentelemetry 18 | */ 19 | package sentry 20 | -------------------------------------------------------------------------------- /ulid/id_test.go: -------------------------------------------------------------------------------- 1 | package ulid 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | tdd "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestNew(t *testing.T) { 11 | assert := tdd.New(t) 12 | 13 | var ( 14 | id ULID 15 | prev ULID 16 | err error 17 | ) 18 | prev, _ = New() 19 | for i := 0; i < 10; i++ { 20 | <-time.After(100 * time.Millisecond) 21 | 22 | // Create and use new instance 23 | id, err = New() 24 | assert.Nil(err) 25 | t.Logf("id: %s", id.String()) 26 | t.Logf("bytes: %x", id.Bytes()) 27 | t.Logf("stamp: %v", id.Timestamp()) 28 | t.Logf("time: %v", id.Time()) 29 | t.Logf("entropy: %v", id.Entropy()) 30 | assert.True(id.Compare(id) == 0) 31 | assert.True(id.Compare(prev) >= 1) 32 | assert.True(prev.Compare(id) < 0) 33 | 34 | // Recover instance using 'Parse' 35 | rec, err := Parse(id.String()) 36 | assert.Nil(err, "parse") 37 | assert.Equal(id, rec) 38 | prev = id 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /internal/crypto/utils.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/sha512" 6 | "fmt" 7 | "io" 8 | 9 | "go.bryk.io/pkg/errors" 10 | "golang.org/x/crypto/hkdf" 11 | ) 12 | 13 | // Expand the provided `secret` material to the requested `size` in bytes; 14 | // optionally using context `info` (if not nil). 15 | func Expand(secret []byte, size int, info []byte) ([]byte, error) { 16 | salt := sha512.Sum512(secret) 17 | for i := 0; i <= 100; i++ { 18 | salt = sha512.Sum512(salt[:]) 19 | } 20 | res := make([]byte, size) 21 | h := hkdf.New(sha512.New, secret, salt[:], info) 22 | if _, err := io.ReadFull(h, res); err != nil { 23 | return nil, errors.Errorf("failed to expand key: %w", err) 24 | } 25 | return res, nil 26 | } 27 | 28 | // RandomID returns a short random ID string. 29 | func RandomID() string { 30 | seed := make([]byte, 6) 31 | _, _ = rand.Read(seed) 32 | return fmt.Sprintf("%X-%X", seed[:3], seed[3:]) 33 | } 34 | -------------------------------------------------------------------------------- /net/http/testdata/server.sample_cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICZDCCAgqgAwIBAgIUMdnIZNRyeDdkLSunZvUCBktTos8wCgYIKoZIzj0EAwIw 3 | ZDELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFUJyeWsgVGVjaG5vbG9naWVzIExMQzEX 4 | MBUGA1UECxMOU2FtcGxlIFJvb3QgQ0ExHDAaBgNVBAMTE0JyeWsgU2FtcGxlIFJv 5 | b3QgQ0EwHhcNMTkwNjEzMDM1NzAwWhcNMjQwNjExMDM1NzAwWjBYMQswCQYDVQQG 6 | EwJVUzEeMBwGA1UEChMVQnJ5ayBUZWNobm9sb2dpZXMgTExDMRcwFQYDVQQLEw5T 7 | YW1wbGUgTmV0d29yazEQMA4GA1UEAxMHbm9kZS0wMTBZMBMGByqGSM49AgEGCCqG 8 | SM49AwEHA0IABNtq9B4b1HivmyfQIUG5AGclt+d8S4TtGZTlSrAh8aNSdDyX+O6q 9 | JQXG6Y/H1Oq5aw+37HWeM5q9CFrXwTzHRKujgaUwgaIwDgYDVR0PAQH/BAQDAgWg 10 | MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0G 11 | A1UdDgQWBBQmljPevaDtdEY34SWrWRDfi3qmqTAfBgNVHSMEGDAWgBRpRBiGIZYu 12 | 6i4zj32VyHBcq2qgIDAjBgNVHREEHDAaggdub2RlLTAxgglsb2NhbGhvc3SHBH8A 13 | AAEwCgYIKoZIzj0EAwIDSAAwRQIhAPo8OLkjHL5QDQbsUDR6TCjayFPyzdPiuqK4 14 | /eupSpiLAiA8Tn/6bJJYSd/xtedvBvYatEKTSWITCiqkQI57HtCyiw== 15 | -----END CERTIFICATE----- 16 | -------------------------------------------------------------------------------- /cli/read_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "syscall" 7 | ) 8 | 9 | func ExampleReadSecure() { 10 | // Interactively prompt the user to enter a value. The value provided won't be 11 | // displayed on the screen. 12 | password, err := ReadSecure("Enter your password: ") 13 | if err != nil { 14 | // Handle error 15 | panic(err) 16 | } 17 | log.Printf("you entered: %s", password) 18 | } 19 | 20 | func ExampleReadPipedInput() { 21 | // Read a maximum of 32 bytes from standard input 22 | input, err := ReadPipedInput(32) 23 | if len(input) > 0 && err != nil { 24 | // Handle error 25 | panic(err) 26 | } 27 | log.Printf("data received: %s", input) 28 | } 29 | 30 | func ExampleSignalsHandler() { 31 | // Register the signals to look for and wait for one 32 | s := <-SignalsHandler([]os.Signal{ 33 | syscall.SIGHUP, 34 | syscall.SIGINT, 35 | syscall.SIGTERM, 36 | syscall.SIGQUIT, 37 | }) 38 | log.Printf("signal received: %s", s) 39 | } 40 | -------------------------------------------------------------------------------- /otel/testdata/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | name: "otel-test" 2 | services: 3 | otel-collector: 4 | image: otel/opentelemetry-collector-contrib:0.141.0 5 | command: ["--config=/etc/otel-collector-config.yaml"] 6 | volumes: 7 | - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml 8 | ports: 9 | - "13133:13133" # health_check extension 10 | - "4317:4317" # default grpc receiver endpoint 11 | - "4318:4318" # default http receiver endpoint 12 | depends_on: 13 | - jaeger 14 | - zipkin 15 | - prometheus 16 | jaeger: 17 | image: jaegertracing/all-in-one:1.75.0 18 | ports: 19 | - "16686:16686" # ui 20 | - "14250" # grpc receiver endpoint 21 | zipkin: 22 | image: openzipkin/zipkin:3.5 23 | ports: 24 | - "9411:9411" # ui and HTTP API 25 | prometheus: 26 | image: prom/prometheus:v3.8.0 27 | volumes: 28 | - ./prometheus.yaml:/etc/prometheus/prometheus.yml 29 | ports: 30 | - "9090:9090" 31 | -------------------------------------------------------------------------------- /net/drpc/ws/error.go: -------------------------------------------------------------------------------- 1 | package ws 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "storj.io/drpc/drpcerr" 8 | ) 9 | 10 | type proxyErr struct { 11 | status int 12 | err error 13 | } 14 | 15 | func newProxyErr(status int, format string, args ...interface{}) *proxyErr { 16 | return wrapErr(status, fmt.Errorf(format, args...)) 17 | } 18 | 19 | func wrapErr(status int, err error) *proxyErr { 20 | return &proxyErr{status: status, err: err} 21 | } 22 | 23 | func (pe *proxyErr) Error() string { 24 | return pe.err.Error() 25 | } 26 | 27 | func (pe *proxyErr) Cause() error { 28 | return pe.err 29 | } 30 | 31 | func (pe *proxyErr) Unwrap() error { 32 | return pe.err 33 | } 34 | 35 | func (pe *proxyErr) JSON() string { 36 | code := "unknown" 37 | if dc := drpcerr.Code(pe.err); dc != 0 { 38 | code = fmt.Sprintf("drpcerr(%d)", dc) 39 | } 40 | data, _ := json.Marshal(map[string]interface{}{ 41 | "code": code, 42 | "msg": pe.err.Error(), 43 | }) 44 | return string(data) 45 | } 46 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Please explain the changes you made here: 4 | 5 | - [ ] A description of the problem you're trying to solve 6 | - [ ] An overview of the suggested solution 7 | - [ ] If the feature changes current behavior, reasons why your solution is better 8 | 9 | ### Checklist 10 | 11 | Before you submit a pull request, please make sure you have to following: 12 | 13 | - [ ] Make sure you are requesting to **pull a topic/feature/bugfix branch** (right side). Don't request your master! 14 | - [ ] Make sure you are making a pull request against the **canary branch** (left side). Also you should start *your branch* off *our canary* 15 | - [ ] Code compiles correctly 16 | - [ ] All existing (and new) tests passed 17 | - [ ] Your code should contain tests relevant for the problem you are solving 18 | - [ ] Extend or adjust the documentation, if necessary 19 | - [ ] All commit messages are properly formatted and descriptive 20 | - [ ] Code complies with existing style guides 21 | -------------------------------------------------------------------------------- /net/drpc/middleware/client/metadata.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | 6 | "storj.io/drpc" 7 | "storj.io/drpc/drpcmetadata" 8 | ) 9 | 10 | // Metadata middleware adds the provided payload data to the context 11 | // of every request (unary and stream) before sending it to the server. 12 | func Metadata(payload map[string]string) Middleware { 13 | return func(next Interceptor) Interceptor { 14 | return md{ 15 | payload: payload, 16 | next: next, 17 | } 18 | } 19 | } 20 | 21 | type md struct { 22 | payload map[string]string 23 | next Interceptor 24 | } 25 | 26 | func (m md) Invoke(ctx context.Context, rpc string, enc drpc.Encoding, in, out drpc.Message) error { 27 | ctx = drpcmetadata.AddPairs(ctx, m.payload) 28 | return m.next.Invoke(ctx, rpc, enc, in, out) 29 | } 30 | 31 | func (m md) NewStream(ctx context.Context, rpc string, enc drpc.Encoding) (drpc.Stream, error) { 32 | ctx = drpcmetadata.AddPairs(ctx, m.payload) 33 | return m.next.NewStream(ctx, rpc, enc) 34 | } 35 | -------------------------------------------------------------------------------- /crypto/shamir/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package shamir provides a simple implementation for the Shamir's Secret Sharing algorithm. 3 | 4 | Shamir's Secret Sharing is a cryptographic algorithm created by Adi Shamir. It is a form of 5 | secret sharing, where a secret is divided into several unique parts (shares). To reconstruct 6 | the original secret, a minimum number (threshold) of parts is required. In the threshold scheme 7 | this number is less than the total number of parts. Otherwise all participants are needed to 8 | reconstruct the original secret. 9 | 10 | Use 'Split' to obtain the shares of a given secret. 11 | 12 | secret := []byte("super-secure-secret") 13 | shares, err := Split(secret, 5, 3) 14 | 15 | Use 'Combine' to restore the original secret from a list of shares. 16 | 17 | secret, err := Combine(shares) 18 | 19 | More information: 20 | https://cs.jhu.edu/~sdoshi/crypto/papers/shamirturing.pdf 21 | 22 | Based on the original implementation by Hashicorp: 23 | https://www.hashicorp.com/ 24 | */ 25 | package shamir 26 | -------------------------------------------------------------------------------- /proto/sample/v1/model.swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "sample/v1/model.proto", 5 | "version": "version not set" 6 | }, 7 | "consumes": [ 8 | "application/json" 9 | ], 10 | "produces": [ 11 | "application/json" 12 | ], 13 | "paths": {}, 14 | "definitions": { 15 | "protobufAny": { 16 | "type": "object", 17 | "properties": { 18 | "@type": { 19 | "type": "string" 20 | } 21 | }, 22 | "additionalProperties": {} 23 | }, 24 | "rpcStatus": { 25 | "type": "object", 26 | "properties": { 27 | "code": { 28 | "type": "integer", 29 | "format": "int32" 30 | }, 31 | "message": { 32 | "type": "string" 33 | }, 34 | "details": { 35 | "type": "array", 36 | "items": { 37 | "type": "object", 38 | "$ref": "#/definitions/protobufAny" 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /otel/grpc/utils.go: -------------------------------------------------------------------------------- 1 | package otelgrpc 2 | 3 | import ( 4 | lib "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" 5 | "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/filters" 6 | "google.golang.org/grpc" 7 | ) 8 | 9 | // ClientInstrumentation can be used to easily instrument any gRPC client connection. 10 | func ClientInstrumentation() grpc.DialOption { 11 | opts := []lib.Option{ 12 | lib.WithFilter(filters.Not(filters.HealthCheck())), 13 | lib.WithMessageEvents(lib.ReceivedEvents, lib.SentEvents), 14 | } 15 | sh := lib.NewClientHandler(opts...) 16 | return grpc.WithStatsHandler(sh) 17 | } 18 | 19 | // ServerInstrumentation can be used to easily instrument any gRPC server instance. 20 | func ServerInstrumentation() grpc.ServerOption { 21 | opts := []lib.Option{ 22 | lib.WithFilter(filters.Not(filters.HealthCheck())), 23 | lib.WithMessageEvents(lib.ReceivedEvents, lib.SentEvents), 24 | } 25 | sh := lib.NewServerHandler(opts...) 26 | return grpc.StatsHandler(sh) 27 | } 28 | -------------------------------------------------------------------------------- /crypto/ed25519/keypair.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | // +build !js 3 | 4 | package ed25519 5 | 6 | import ( 7 | e "crypto/ed25519" 8 | ) 9 | 10 | // KeyPair represents a Ed25519 (Sign/Verify) public/private key. 11 | type KeyPair struct { 12 | pub [32]byte 13 | priv e.PrivateKey 14 | } 15 | 16 | // PrivateKey returns the private key bytes of the key pair instance. Using 17 | // this method may unintentionally expose secret material outside the security 18 | // memory segment managed by the instance. Don't use it unless you really know 19 | // what you are doing. 20 | func (k *KeyPair) PrivateKey() []byte { 21 | return k.priv 22 | } 23 | 24 | // Destroy will safely release the allocated mlock/VirtualLock memory. 25 | func (k *KeyPair) Destroy() { 26 | k.priv = nil 27 | } 28 | 29 | // Setup a key pair instance from the provided private key. 30 | func fromPrivateKey(priv e.PrivateKey) (*KeyPair, error) { 31 | // Load public key to a sized byte 32 | pub := [32]byte{} 33 | copy(pub[:], priv[32:]) 34 | return &KeyPair{ 35 | pub: pub, 36 | priv: priv, 37 | }, nil 38 | } 39 | -------------------------------------------------------------------------------- /.gitleaksignore: -------------------------------------------------------------------------------- 1 | 4b14aa74b3347c928b8bd70114dfe362a6ba0353:net/drpc/testdata/server.sample_key:private-key:1 2 | 4b14aa74b3347c928b8bd70114dfe362a6ba0353:net/drpc/testdata/ca.sample_key:private-key:1 3 | 4b14aa74b3347c928b8bd70114dfe362a6ba0353:net/drpc/testdata/bad.sample_key:private-key:1 4 | 0cda6a8918625e28ce256d15572c36588eaab413:did/key_type.go:generic-api-key:28 5 | 97f3b9cf16c95dd95126df996450f3bbd5a226fb:net/rpc/testdata/server.sample_key:private-key:1 6 | 97f3b9cf16c95dd95126df996450f3bbd5a226fb:net/rpc/testdata/ca.sample_key:private-key:1 7 | 97f3b9cf16c95dd95126df996450f3bbd5a226fb:net/rpc/testdata/bad.sample_key:private-key:1 8 | 4213b06c2ecb968182d8d13343be82ca9e5a365c:net/http/testdata/ca.sample_key:private-key:1 9 | 4213b06c2ecb968182d8d13343be82ca9e5a365c:net/http/testdata/server.sample_key:private-key:1 10 | 2096763359dba6025823f5676a0eb092f8caebee:net/loader/testdata/server.sample_key:private-key:1 11 | 2096763359dba6025823f5676a0eb092f8caebee:net/loader/testdata/ca.sample_key:private-key:1 12 | 73c3f9b6f09f1bf8361ef60719791364eec14b87:buf.yaml:generic-api-key:17 13 | -------------------------------------------------------------------------------- /net/drpc/testdata/server.sample_cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICwjCCAmigAwIBAgIUC42U78Au6wszDbJLlvue9vZOSpowCgYIKoZIzj0EAwIw 3 | QjELMAkGA1UEBhMCTVgxFjAUBgNVBAoTDUJyeWsgTGFicyBMTEMxDDAKBgNVBAsM 4 | A1ImRDENMAsGA1UEAxMEYnJ5azAeFw0yNDA3MDQyMzM0MDBaFw0zNDA3MDIyMzM0 5 | MDBaMIG6MQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExEjAQBgNVBAcT 6 | CUFybGluZ3RvbjEYMBYGA1UECRMPMTQwMCBTIEpveWNlIFN0MQ4wDAYDVQQREwUy 7 | MjIwMjEeMBwGA1UEChMVQnJ5ayBUZWNobm9sb2dpZXMgTExDMRQwEgYDVQQLEwtE 8 | ZXZlbG9wbWVudDEkMCIGA1UEAxMbc2FtcGxlLW5vZGUtMDEuYnJ5ay5uZXR3b3Jr 9 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3CntD6zXf4sHBh8OOTxnYUEznBAE 10 | i/3FWMv6Su03Blls9YGA11voRrjrE/+Rd0gtsYLUbevTvUIdzsLPtEIssaOBwjCB 11 | vzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC 12 | MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFNBvjMmElt59mes5XZs4VYonDUoEMB8G 13 | A1UdIwQYMBaAFARZAImGvVbQtzQclVn5TDFtsMNZMEAGA1UdEQQ5MDeCG3NhbXBs 14 | ZS1ub2RlLTAxLmJyeWsubmV0d29ya4IHbm9kZS0wMYIJbG9jYWxob3N0hwR/AAAB 15 | MAoGCCqGSM49BAMCA0gAMEUCIQCFSjAEoMZFwF/zJ8WolYmXJqp2BAgsMhvqWx5E 16 | H2xvwwIgZ9/jqtRuQ+p2B33E/k1DM/B8Mc72A42ByafFVoXaUc4= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /net/rpc/testdata/server.sample_cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICwjCCAmigAwIBAgIUC42U78Au6wszDbJLlvue9vZOSpowCgYIKoZIzj0EAwIw 3 | QjELMAkGA1UEBhMCTVgxFjAUBgNVBAoTDUJyeWsgTGFicyBMTEMxDDAKBgNVBAsM 4 | A1ImRDENMAsGA1UEAxMEYnJ5azAeFw0yNDA3MDQyMzM0MDBaFw0zNDA3MDIyMzM0 5 | MDBaMIG6MQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExEjAQBgNVBAcT 6 | CUFybGluZ3RvbjEYMBYGA1UECRMPMTQwMCBTIEpveWNlIFN0MQ4wDAYDVQQREwUy 7 | MjIwMjEeMBwGA1UEChMVQnJ5ayBUZWNobm9sb2dpZXMgTExDMRQwEgYDVQQLEwtE 8 | ZXZlbG9wbWVudDEkMCIGA1UEAxMbc2FtcGxlLW5vZGUtMDEuYnJ5ay5uZXR3b3Jr 9 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3CntD6zXf4sHBh8OOTxnYUEznBAE 10 | i/3FWMv6Su03Blls9YGA11voRrjrE/+Rd0gtsYLUbevTvUIdzsLPtEIssaOBwjCB 11 | vzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC 12 | MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFNBvjMmElt59mes5XZs4VYonDUoEMB8G 13 | A1UdIwQYMBaAFARZAImGvVbQtzQclVn5TDFtsMNZMEAGA1UdEQQ5MDeCG3NhbXBs 14 | ZS1ub2RlLTAxLmJyeWsubmV0d29ya4IHbm9kZS0wMYIJbG9jYWxob3N0hwR/AAAB 15 | MAoGCCqGSM49BAMCA0gAMEUCIQCFSjAEoMZFwF/zJ8WolYmXJqp2BAgsMhvqWx5E 16 | H2xvwwIgZ9/jqtRuQ+p2B33E/k1DM/B8Mc72A42ByafFVoXaUc4= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /net/rpc/mw_recovery.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "context" 5 | 6 | "google.golang.org/grpc" 7 | "google.golang.org/grpc/codes" 8 | "google.golang.org/grpc/status" 9 | ) 10 | 11 | func rcvUnaryServerInterceptor() grpc.UnaryServerInterceptor { 12 | return func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (_ any, err error) { 13 | panicked := true 14 | 15 | defer func() { 16 | if r := recover(); r != nil || panicked { 17 | err = status.Errorf(codes.Internal, "%v", r) 18 | } 19 | }() 20 | 21 | resp, err := handler(ctx, req) 22 | panicked = false 23 | return resp, err 24 | } 25 | } 26 | 27 | func rcvStreamServerInterceptor() grpc.StreamServerInterceptor { 28 | return func(srv any, stream grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) (err error) { 29 | panicked := true 30 | 31 | defer func() { 32 | if r := recover(); r != nil || panicked { 33 | err = status.Errorf(codes.Internal, "%v", r) 34 | } 35 | }() 36 | 37 | err = handler(srv, stream) 38 | panicked = false 39 | return err 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part 4 | # of a Pull Request, surfacing known-vulnerable versions of the packages 5 | # declared or updated in the PR. 6 | name: "Dependency review" 7 | on: [pull_request] 8 | permissions: 9 | contents: read 10 | jobs: 11 | dependency-review: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # Harden workflow runner 15 | - name: Harden workflow runner (audit all outbound calls) 16 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 17 | with: 18 | egress-policy: audit 19 | 20 | # Checkout code 21 | - name: Checkout repository 22 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 23 | with: 24 | persist-credentials: false 25 | 26 | # Scan dependencies 27 | # https://github.com/actions/dependency-review-action 28 | - name: Dependency review 29 | uses: actions/dependency-review-action@40c09b7dc99638e5ddb0bfd91c1673effc064d8a # v4.8.1 30 | -------------------------------------------------------------------------------- /net/rpc/service.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" 7 | "google.golang.org/grpc" 8 | ) 9 | 10 | // GatewayRegisterFunc provides a mechanism to set up an HTTP mux 11 | // for a gRPC server. 12 | type GatewayRegisterFunc = func(context.Context, *runtime.ServeMux, *grpc.ClientConn) error 13 | 14 | // ServiceProvider is an entity that provides functionality to be exposed 15 | // through an RPC server. 16 | type ServiceProvider interface { 17 | // Services should return the service identifier(s) supported by 18 | // the provider. 19 | Services() []string 20 | 21 | // ServerSetup should perform any initialization requirements for the 22 | // particular service and register it with the provided server instance. 23 | ServerSetup(server *grpc.Server) 24 | } 25 | 26 | // HTTPServiceProvider is an entity that provides functionality to be 27 | // exposed through an RPC server and an HTTP gateway. 28 | type HTTPServiceProvider interface { 29 | ServiceProvider 30 | 31 | // GatewaySetup return the HTTP Gateway setup method. 32 | GatewaySetup() GatewayRegisterFunc 33 | } 34 | -------------------------------------------------------------------------------- /jose/jwt/generator_options.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "go.bryk.io/pkg/jose/jwk" 5 | ) 6 | 7 | // GeneratorOption elements provide a functional-style configuration mechanism 8 | // for token generators. 9 | type GeneratorOption func(g *Generator) error 10 | 11 | // WithSupportForNone enables support for the 'NONE' JWA algorithm; this 12 | // is disabled by default. 'NONE' tokens are considered insecure. 13 | func WithSupportForNone() GeneratorOption { 14 | return func(g *Generator) error { 15 | g.none = true 16 | return nil 17 | } 18 | } 19 | 20 | // WithKey registers a cryptographic key on the generator instance. 21 | func WithKey(k jwk.Key) GeneratorOption { 22 | return func(g *Generator) error { 23 | return g.AddKey(k) 24 | } 25 | } 26 | 27 | // WithKeySet registers a JWK set of keys on the generator instance. 28 | func WithKeySet(set jwk.Set) GeneratorOption { 29 | return func(g *Generator) error { 30 | keys, err := expandSet(set) 31 | if err != nil { 32 | return err 33 | } 34 | for _, k := range keys { 35 | if err = g.AddKey(k); err != nil { 36 | return err 37 | } 38 | } 39 | return nil 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /net/http/sample-openapi/petstore/oas_validators_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by ogen, DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "github.com/go-faster/errors" 7 | 8 | "github.com/ogen-go/ogen/validate" 9 | ) 10 | 11 | func (s *Pet) Validate() error { 12 | if s == nil { 13 | return validate.ErrNilPointer 14 | } 15 | 16 | var failures []validate.FieldError 17 | if err := func() error { 18 | if value, ok := s.Status.Get(); ok { 19 | if err := func() error { 20 | if err := value.Validate(); err != nil { 21 | return err 22 | } 23 | return nil 24 | }(); err != nil { 25 | return err 26 | } 27 | } 28 | return nil 29 | }(); err != nil { 30 | failures = append(failures, validate.FieldError{ 31 | Name: "status", 32 | Error: err, 33 | }) 34 | } 35 | if len(failures) > 0 { 36 | return &validate.Error{Fields: failures} 37 | } 38 | return nil 39 | } 40 | 41 | func (s PetStatus) Validate() error { 42 | switch s { 43 | case "available": 44 | return nil 45 | case "pending": 46 | return nil 47 | case "sold": 48 | return nil 49 | default: 50 | return errors.Errorf("invalid value: %v", s) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /net/middleware/rate/handler.go: -------------------------------------------------------------------------------- 1 | package rate 2 | 3 | import ( 4 | "net/http" 5 | 6 | lib "golang.org/x/time/rate" 7 | ) 8 | 9 | // Handler provides a rate limiter middleware based on a "token bucket" 10 | // implementation. A rate limiter controls how frequently HTTP requests 11 | // are allowed to happen. The "token bucket" is of size `limit`, initially 12 | // full and refilled at rate `burst` tokens per second. 13 | // 14 | // The rate limiter is applied to all incoming requests and will reject, with 15 | // status 429, those that exceed the configured limit. 16 | // 17 | // More information: https://www.rfc-editor.org/rfc/rfc6585.html#section-4 18 | func Handler(limit, burst uint) func(http.Handler) http.Handler { 19 | rl := lib.NewLimiter(lib.Limit(limit), int(burst)) 20 | return func(next http.Handler) http.Handler { 21 | fn := func(w http.ResponseWriter, r *http.Request) { 22 | if err := rl.Wait(r.Context()); err != nil { 23 | http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) 24 | return 25 | } 26 | // Call the next handler in the chain. 27 | next.ServeHTTP(w, r) 28 | } 29 | return http.HandlerFunc(fn) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /net/drpc/middleware/client/rate.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | 6 | "go.bryk.io/pkg/errors" 7 | "golang.org/x/time/rate" 8 | "storj.io/drpc" 9 | ) 10 | 11 | // RateLimit enforce a maximum limit of RPC requests per-second on the 12 | // client. It is implemented as a `token bucket` instance. 13 | // More information: https://en.wikipedia.org/wiki/Token_bucket 14 | func RateLimit(limit int) Middleware { 15 | return func(next Interceptor) Interceptor { 16 | return rateLimit{ 17 | check: rate.NewLimiter(rate.Limit(limit), limit), 18 | next: next, 19 | } 20 | } 21 | } 22 | 23 | type rateLimit struct { 24 | check *rate.Limiter 25 | next Interceptor 26 | } 27 | 28 | func (md rateLimit) Invoke(ctx context.Context, rpc string, enc drpc.Encoding, in, out drpc.Message) error { 29 | if !md.check.Allow() { 30 | return errors.New("rate: limit exceeded") 31 | } 32 | return md.next.Invoke(ctx, rpc, enc, in, out) 33 | } 34 | 35 | func (md rateLimit) NewStream(ctx context.Context, rpc string, enc drpc.Encoding) (drpc.Stream, error) { 36 | if !md.check.Allow() { 37 | return nil, errors.New("rate: limit exceeded") 38 | } 39 | return md.next.NewStream(ctx, rpc, enc) 40 | } 41 | -------------------------------------------------------------------------------- /crypto/ed25519/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package ed25519 provides a EdDSA (Edwards-curve Digital Signature Algorithm) handler for Curve25519. 3 | 4 | The main component in the package is the 'KeyPair' instance. All functionality 5 | to generate and validate digital signatures is available by its methods. 6 | 7 | # Key Creation 8 | 9 | There are 3 mechanisms to create a new key pair. 10 | 11 | // 1. Create a completely random new key 12 | rk, _ := New() 13 | 14 | // 2. Key using a given seed material 15 | sk, _ := FromSeed([]byte("material")) 16 | 17 | // 3. Load from PEM-encoded content 18 | pk, _ := Unmarshal(pemBinData) 19 | 20 | However created, the key pair instance always use a locked memory buffer to securely 21 | hold private information. Is mandatory to properly release the memory buffer after 22 | using the key by calling the 'Destroy' method. 23 | 24 | // Securely release in-memory secrets 25 | kp.Destroy() 26 | 27 | # Key Usage 28 | 29 | A key pair can be used to produce and verify digital signatures. 30 | 31 | msg := []byte("message-to-sign") 32 | kp, _ := New() 33 | signature := kp.Sign(msg) 34 | log.Printf("verification result: %v", kp.Verify(msg, signature)) 35 | */ 36 | package ed25519 37 | -------------------------------------------------------------------------------- /storage/orm/pipeline.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "bytes" 5 | "text/template" 6 | 7 | "go.mongodb.org/mongo-driver/bson" 8 | "go.mongodb.org/mongo-driver/bson/primitive" 9 | "go.mongodb.org/mongo-driver/mongo" 10 | ) 11 | 12 | var tplUpdateDocument *template.Template 13 | var updateDocument = `[{ 14 | "$match": { 15 | "operationType": "update", 16 | "fullDocument._id": {{.ID}} 17 | } 18 | }]` 19 | 20 | // Parse built-in templates. 21 | func init() { 22 | tplUpdateDocument, _ = template.New("updateID").Parse(updateDocument) 23 | } 24 | 25 | // PipelineCollection is a helper function to setup a pipeline to 26 | // receive all change events for a specific MongoDB collection. 27 | func PipelineCollection() mongo.Pipeline { 28 | return mongo.Pipeline{} 29 | } 30 | 31 | // PipelineUpdateDocument returns a pipeline to receive update notifications 32 | // for a specific document based on its '_id' field. 33 | func PipelineUpdateDocument(oid primitive.ObjectID) mongo.Pipeline { 34 | var doc mongo.Pipeline 35 | buf := bytes.NewBuffer(nil) 36 | _ = tplUpdateDocument.Execute(buf, map[string]interface{}{"ID": oid}) 37 | _ = bson.UnmarshalExtJSON(buf.Bytes(), false, &doc) 38 | return doc 39 | } 40 | -------------------------------------------------------------------------------- /amqp/producer.go: -------------------------------------------------------------------------------- 1 | package amqp 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/google/uuid" 7 | ) 8 | 9 | // Producer instances simplify the process of generating multiple message 10 | // wrappers with consistent properties and behavior. 11 | type Producer struct { 12 | // Content encoding code. 13 | Encoding string 14 | 15 | // Content type code. 16 | ContentType string 17 | 18 | // Message kind identifier. 19 | MessageType string 20 | 21 | // Application contextual identifier. 22 | AppID string 23 | 24 | // Add the timestamp value when creating a new message. 25 | SetTime bool 26 | 27 | // Add a randomly-generated, unique ID to each message. 28 | SetID bool 29 | } 30 | 31 | // Message returns a message wrapper for the provided content based on the 32 | // producer instance settings. 33 | func (p *Producer) Message(content []byte) Message { 34 | msg := Message{ 35 | AppId: p.AppID, 36 | ContentType: p.ContentType, 37 | ContentEncoding: p.Encoding, 38 | Body: content, 39 | Type: p.MessageType, 40 | } 41 | if p.SetID { 42 | msg.MessageId = uuid.New().String() 43 | } 44 | if p.SetTime { 45 | msg.Timestamp = time.Now().UTC() 46 | } 47 | return msg 48 | } 49 | -------------------------------------------------------------------------------- /buf.gen.yaml: -------------------------------------------------------------------------------- 1 | version: v2 2 | inputs: 3 | - directory: proto 4 | managed: 5 | enabled: true 6 | override: 7 | - file_option: go_package_prefix 8 | value: go.bryk.io/pkg 9 | disable: 10 | - file_option: go_package 11 | module: buf.build/bufbuild/protovalidate 12 | - file_option: go_package_prefix 13 | module: buf.build/googleapis/googleapis 14 | - file_option: go_package_prefix 15 | module: buf.build/grpc-ecosystem/grpc-gateway 16 | plugins: 17 | # ! with >=v1.36.4 the pb.go files generated break when using the 18 | # ! protoc_gen_openapiv2 annotations. 19 | - remote: buf.build/protocolbuffers/go:v1.36.3 20 | out: . 21 | opt: 22 | - paths=source_relative 23 | - remote: buf.build/grpc/go:v1.5.1 24 | out: . 25 | opt: 26 | - paths=source_relative 27 | - require_unimplemented_servers=true 28 | - remote: buf.build/grpc-ecosystem/openapiv2:v2.27.3 29 | out: . 30 | opt: 31 | - logtostderr=true 32 | - remote: buf.build/grpc-ecosystem/gateway:v2.27.3 33 | out: . 34 | opt: 35 | - paths=source_relative 36 | - logtostderr=true 37 | # - local: go-drpc 38 | # out: . 39 | # opt: 40 | # - paths=source_relative 41 | -------------------------------------------------------------------------------- /net/sse/subscription.go: -------------------------------------------------------------------------------- 1 | package sse 2 | 3 | import ( 4 | "context" 5 | "sync" 6 | ) 7 | 8 | // Subscription instances can be used to receive events published by the 9 | // originating stream operator. 10 | type Subscription struct { 11 | id string // unique identifier 12 | ctx context.Context // underlying context 13 | halt context.CancelFunc // cancel context function 14 | sink chan Event // delivery channel 15 | wg *sync.WaitGroup // in-process tasks 16 | } 17 | 18 | // ID returns the subscriber's unique identifier. 19 | func (sb *Subscription) ID() string { 20 | return sb.id 21 | } 22 | 23 | // Receive any events published by the stream. 24 | func (sb *Subscription) Receive() <-chan Event { 25 | return sb.sink 26 | } 27 | 28 | // Done returns a channel that's closed when the subscription is being 29 | // terminated. No further activity should be expected on `Receive`. 30 | func (sb *Subscription) Done() <-chan struct{} { 31 | return sb.ctx.Done() 32 | } 33 | 34 | // Free subscriber resources. 35 | func (sb *Subscription) close() { 36 | sb.halt() // trigger 'done' signal 37 | sb.wg.Wait() // wait for in-flight messages 38 | close(sb.sink) // close event receiver channel 39 | } 40 | -------------------------------------------------------------------------------- /net/drpc/middleware/client/panic.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "storj.io/drpc" 8 | ) 9 | 10 | // PanicRecovery allows the client to convert unhandled panic events into an 11 | // "internal" RPC error. This will prevent the client from crashing if a handler 12 | // produces a `panic` operation. 13 | func PanicRecovery() Middleware { 14 | return func(next Interceptor) Interceptor { 15 | return panicRecovery{ 16 | tag: "internal error", 17 | next: next, 18 | } 19 | } 20 | } 21 | 22 | type panicRecovery struct { 23 | tag string 24 | next Interceptor 25 | } 26 | 27 | func (md panicRecovery) Invoke(ctx context.Context, rpc string, enc drpc.Encoding, in, out drpc.Message) (err error) { 28 | defer func() { 29 | if v := recover(); v != nil { 30 | err = fmt.Errorf("%s: %s", md.tag, v) 31 | } 32 | }() 33 | err = md.next.Invoke(ctx, rpc, enc, in, out) 34 | return 35 | } 36 | 37 | func (md panicRecovery) NewStream(ctx context.Context, rpc string, enc drpc.Encoding) (st drpc.Stream, err error) { 38 | defer func() { 39 | if v := recover(); v != nil { 40 | err = fmt.Errorf("%s: %s", md.tag, v) 41 | } 42 | }() 43 | st, err = md.next.NewStream(ctx, rpc, enc) 44 | return 45 | } 46 | -------------------------------------------------------------------------------- /storage/orm/utils.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "go.mongodb.org/mongo-driver/bson" 8 | "go.mongodb.org/mongo-driver/bson/primitive" 9 | ) 10 | 11 | // ParseID returns a MongoDB objectID instance from its hex-encoded 12 | // representation. 13 | func ParseID(id string) (primitive.ObjectID, error) { 14 | return primitive.ObjectIDFromHex(id) 15 | } 16 | 17 | // Filter provides a simple shortcut for a commonly used filter value 18 | // when no fields are specified. 19 | func Filter() map[string]interface{} { 20 | return map[string]interface{}{} 21 | } 22 | 23 | // Returns a properly encoded BSON document. 24 | func doc(filter map[string]interface{}) (bson.D, error) { 25 | data, err := bson.Marshal(filter) 26 | if err != nil { 27 | return nil, err 28 | } 29 | f := bson.D{} 30 | if err = bson.Unmarshal(data, &f); err != nil { 31 | return nil, err 32 | } 33 | return f, nil 34 | } 35 | 36 | // Verify the provided element is of the expected kind. 37 | func checkType(el interface{}, expected reflect.Kind, desc string) error { 38 | rv := reflect.ValueOf(el) 39 | if rv.Kind() != expected { 40 | return fmt.Errorf("target must be a %s, but was a %s", desc, rv.Kind()) 41 | } 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /net/sse/stream_options.go: -------------------------------------------------------------------------------- 1 | package sse 2 | 3 | import ( 4 | "time" 5 | 6 | xlog "go.bryk.io/pkg/log" 7 | ) 8 | 9 | // StreamOption provide a functional-style mechanism to adjust the behavior 10 | // of a stream operator instance. 11 | type StreamOption func(st *Stream) error 12 | 13 | // WithMessageRetry adjust the `retry` message value, in milliseconds, set 14 | // by the stream for all send messages and events. Default value is `2000`. 15 | func WithMessageRetry(retry uint) StreamOption { 16 | return func(st *Stream) error { 17 | st.mu.Lock() 18 | st.retry = retry 19 | st.mu.Unlock() 20 | return nil 21 | } 22 | } 23 | 24 | // WithSendTimeout adjust the maximum time to wait for message delivery on 25 | // send operations. Default value is 2 seconds. 26 | func WithSendTimeout(timeout time.Duration) StreamOption { 27 | return func(st *Stream) error { 28 | st.mu.Lock() 29 | st.timeout = timeout 30 | st.mu.Unlock() 31 | return nil 32 | } 33 | } 34 | 35 | // WithLogger set the log handler for the stream operator. Logs are discarded 36 | // by default. 37 | func WithLogger(logger xlog.Logger) StreamOption { 38 | return func(st *Stream) error { 39 | st.mu.Lock() 40 | st.log = logger 41 | st.mu.Unlock() 42 | return nil 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cli/shell/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package shell provides an interactive client for CLI-based applications. 3 | 4 | The main point of interaction is a shell 'Instance'. Specific functionality 5 | is registered with the instance in the form of commands. Commands will be 6 | executed when the user invokes them as part of an active interactive session. 7 | 8 | // Create a new shell instance with basic configuration options 9 | options := []Option{ 10 | WithPrompt("sample shell > "), 11 | WithStartMessage("this is just a sample shell"), 12 | WithExitMessage("exiting sample shell..."), 13 | } 14 | sh, err := New(options...) 15 | if err != nil { 16 | panic(err) 17 | } 18 | 19 | // Register commands 20 | sh.AddCommand(&Command{ 21 | Name: "sample-command", 22 | Description: "this is just a sample command", 23 | Usage: "sample", 24 | Run: func(_ string) string { 25 | // Read secure user input 26 | pass, err := sh.ReadSecret("enter password:") 27 | if err != nil { 28 | return fmt.Sprintf("an error occurred: %s", err) 29 | } 30 | // Return final result, it will be displayed back to the user 31 | return fmt.Sprintf("the password entered is: %s", pass) 32 | }, 33 | }) 34 | 35 | // Start interactive session 36 | sh.Start() 37 | */ 38 | package shell 39 | -------------------------------------------------------------------------------- /net/drpc/utils.go: -------------------------------------------------------------------------------- 1 | package drpc 2 | 3 | import ( 4 | "context" 5 | "crypto/tls" 6 | "os" 7 | 8 | "go.bryk.io/pkg/errors" 9 | "storj.io/drpc/drpcmetadata" 10 | ) 11 | 12 | // Helper method to determine if a path exists and is a regular file. 13 | func exists(name string) bool { 14 | info, err := os.Stat(name) 15 | return err == nil && !info.IsDir() 16 | } 17 | 18 | // LoadCertificate provides a helper method to conveniently parse and existing 19 | // certificate and corresponding private key. 20 | func LoadCertificate(cert []byte, key []byte) (tls.Certificate, error) { 21 | c, err := tls.X509KeyPair(cert, key) 22 | return c, errors.Wrap(err, "failed to load key pair") 23 | } 24 | 25 | // ContextWithMetadata adds custom data to a given context. This is particularly 26 | // useful when sending outgoing requests on the client side. 27 | func ContextWithMetadata(ctx context.Context, data map[string]string) context.Context { 28 | return drpcmetadata.AddPairs(ctx, data) 29 | } 30 | 31 | // MetadataFromContext retrieve any custom metadata available on the provided 32 | // context. This is particularly useful when processing incoming requests on 33 | // the server side. 34 | func MetadataFromContext(ctx context.Context) (map[string]string, bool) { 35 | return drpcmetadata.Get(ctx) 36 | } 37 | -------------------------------------------------------------------------------- /net/rpc/client_tls.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | 7 | "go.bryk.io/pkg/errors" 8 | ) 9 | 10 | // ClientTLSConfig defines the configuration options available when establishing 11 | // a secure communication channel with a server. 12 | type ClientTLSConfig struct { 13 | // Whether to include system CAs. 14 | IncludeSystemCAs bool 15 | 16 | // Custom certificate authorities to include when accepting TLS connections. 17 | CustomCAs [][]byte 18 | } 19 | 20 | // Generate a proper TLS configuration to use on the client side. 21 | func clientTLSConf(opts ClientTLSConfig) (*tls.Config, error) { 22 | conf := &tls.Config{ 23 | MinVersion: tls.VersionTLS12, 24 | NextProtos: []string{alpnProtocolIdentifier}, 25 | } 26 | 27 | // Prepare cert pool 28 | var err error 29 | var cp *x509.CertPool 30 | if opts.IncludeSystemCAs { 31 | cp, err = x509.SystemCertPool() 32 | if err != nil { 33 | return nil, errors.Wrap(err, "failed to load system CAs") 34 | } 35 | } else { 36 | cp = x509.NewCertPool() 37 | } 38 | 39 | // Append custom CA certs 40 | if len(opts.CustomCAs) > 0 { 41 | for _, c := range opts.CustomCAs { 42 | if !cp.AppendCertsFromPEM(c) { 43 | return nil, errors.New("failed to append provided CA certificates") 44 | } 45 | } 46 | } 47 | 48 | conf.RootCAs = cp 49 | return conf, nil 50 | } 51 | -------------------------------------------------------------------------------- /crypto/x25519/keypair_js.go: -------------------------------------------------------------------------------- 1 | //go:build js 2 | 3 | package x25519 4 | 5 | import ( 6 | c "golang.org/x/crypto/curve25519" 7 | ) 8 | 9 | // KeyPair represents a X25519 (Diffie-Hellman) public/private key. 10 | type KeyPair struct { 11 | public [32]byte 12 | private []byte 13 | } 14 | 15 | // PrivateKey returns the private key bytes of the key pair instance. Using 16 | // this method may unintentionally expose secret material outside the security 17 | // memory segment managed by the instance. Don't use it unless you really know 18 | // what you are doing. 19 | func (k *KeyPair) PrivateKey() []byte { 20 | return k.private 21 | } 22 | 23 | // Destroy will safely release the allocated mlock/VirtualLock memory 24 | func (k *KeyPair) Destroy() { 25 | k.private = nil 26 | } 27 | 28 | // Setup a key pair instance from the provided private key bytes 29 | func fromPrivateKey(priv []byte, adjust bool) (*KeyPair, error) { 30 | // Adjust private key value 31 | // https://cr.yp.to/ecdh.html 32 | if adjust { 33 | priv[0] &= 248 34 | priv[31] &= 127 35 | priv[31] |= 64 36 | } 37 | 38 | // Get public key 39 | privateKey := [32]byte{} 40 | publicKey := [32]byte{} 41 | copy(privateKey[:], priv) 42 | c.ScalarBaseMult(&publicKey, &privateKey) 43 | 44 | // Clean and return key pair instance 45 | return &KeyPair{ 46 | public: publicKey, 47 | private: priv, 48 | }, nil 49 | } 50 | -------------------------------------------------------------------------------- /cli/spinner.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "time" 5 | 6 | sp "github.com/briandowns/spinner" 7 | ) 8 | 9 | // Spinner indicator. 10 | type Spinner struct { 11 | el *sp.Spinner 12 | } 13 | 14 | // NewSpinner creates a new spinner indicator instance. 15 | func NewSpinner(opts ...SpinnerOption) *Spinner { 16 | s := new(Spinner) 17 | s.el = sp.New(sp.CharSets[11], 100*time.Millisecond) 18 | s.el.HideCursor = true 19 | _ = s.el.Color("fgHiBlack") 20 | for _, opt := range opts { 21 | opt(s) 22 | } 23 | return s 24 | } 25 | 26 | // Start the spinner indicator. 27 | func (s *Spinner) Start() { 28 | s.el.Start() 29 | } 30 | 31 | // Stop the spinner indicator. 32 | func (s *Spinner) Stop() { 33 | s.el.Stop() 34 | } 35 | 36 | // SpinnerOption provide a functional style mechanism to adjust the settings 37 | // when creating a new spinner instance. 38 | type SpinnerOption = func(s *Spinner) 39 | 40 | // WithSpinnerColor adjust the color used for the spinner indicator. 41 | // Supported values are: "green", "blue", "yellow" and "red". 42 | func WithSpinnerColor(color string) SpinnerOption { 43 | return func(s *Spinner) { 44 | if c, ok := supportedSpinnerColors[color]; ok { 45 | _ = s.el.Color(c) 46 | } 47 | } 48 | } 49 | 50 | var supportedSpinnerColors = map[string]string{ 51 | "blue": "blue", 52 | "red": "red", 53 | "yellow": "yellow", 54 | "green": "green", 55 | } 56 | -------------------------------------------------------------------------------- /jose/jwt/validator_test.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "testing" 5 | 6 | tdd "github.com/stretchr/testify/assert" 7 | "go.bryk.io/pkg/jose/jwa" 8 | "go.bryk.io/pkg/jose/jwk" 9 | ) 10 | 11 | func TestValidator(t *testing.T) { 12 | assert := tdd.New(t) 13 | 14 | // Create (or import) a single master key 15 | mk, _ := jwk.New(jwa.ES256) 16 | mk.SetID("master-key") 17 | 18 | // Create a new generator instance 19 | tg, err := NewGenerator("acme.com") 20 | assert.Nil(err, "new generator") 21 | assert.Nil(tg.AddKey(mk), "add key") 22 | 23 | // Generator issue a token 24 | params := TokenParameters{ 25 | Method: string(jwa.ES256), 26 | Subject: "Rick Sanchez", 27 | Audience: []string{"https://bryk.io"}, 28 | NotBefore: "0ms", 29 | ContentType: "sample/token", 30 | } 31 | token, err := tg.Issue("master-key", ¶ms) 32 | assert.Nil(err, "new token") 33 | t.Log(token) 34 | 35 | // Generate publishes its JWK set 36 | tgSet := tg.ExportKeys(true) // no private keys 37 | 38 | // Validator is an external process with access only to public keys 39 | val, err := NewValidator(WithValidationKeys(tgSet)) 40 | assert.Nil(err, "new validator") 41 | 42 | // Use the validator to validate a token 43 | valChecks := params.GetChecks() 44 | valChecks = append(valChecks, IssuerCheck("acme.com")) 45 | assert.Nil(val.Validate(token.String(), valChecks...), "validate failed") 46 | } 47 | -------------------------------------------------------------------------------- /net/http/sample-openapi/petstore/oas_labeler_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by ogen, DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "context" 7 | 8 | "go.opentelemetry.io/otel/attribute" 9 | ) 10 | 11 | // Labeler is used to allow adding custom attributes to the server request metrics. 12 | type Labeler struct { 13 | attrs []attribute.KeyValue 14 | } 15 | 16 | // Add attributes to the Labeler. 17 | func (l *Labeler) Add(attrs ...attribute.KeyValue) { 18 | l.attrs = append(l.attrs, attrs...) 19 | } 20 | 21 | // AttributeSet returns the attributes added to the Labeler as an attribute.Set. 22 | func (l *Labeler) AttributeSet() attribute.Set { 23 | return attribute.NewSet(l.attrs...) 24 | } 25 | 26 | type labelerContextKey struct{} 27 | 28 | // LabelerFromContext retrieves the Labeler from the provided context, if present. 29 | // 30 | // If no Labeler was found in the provided context a new, empty Labeler is returned and the second 31 | // return value is false. In this case it is safe to use the Labeler but any attributes added to 32 | // it will not be used. 33 | func LabelerFromContext(ctx context.Context) (*Labeler, bool) { 34 | if l, ok := ctx.Value(labelerContextKey{}).(*Labeler); ok { 35 | return l, true 36 | } 37 | return &Labeler{}, false 38 | } 39 | 40 | func contextWithLabeler(ctx context.Context, l *Labeler) context.Context { 41 | return context.WithValue(ctx, labelerContextKey{}, l) 42 | } 43 | -------------------------------------------------------------------------------- /otel/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package otel provides OpenTelemetry instrumentation utilities for Go applications and libraries. 3 | 4 | OpenTelemetry is an Observability framework and toolkit designed to create and 5 | manage telemetry data such as traces, metrics, and logs. Crucially, OpenTelemetry 6 | is vendor and tool-agnostic, meaning that it can be used with a broad variety 7 | of Observability backends, including open source tools like Jaeger and Prometheus, 8 | as well as commercial offerings. 9 | 10 | For an application or component to emit useful telemetry data it needs to be 11 | “instrumented”. In order to instrument your code in a way that is idiomatic for 12 | OpenTelemetry you need to follow some conventions. 13 | 14 | - OpenTelemetry is split into two parts: an API to instrument code with, and SDKs 15 | that implement the API. 16 | 17 | - If you’re instrumenting an app, you need to use the OpenTelemetry SDK for your 18 | language. You’ll then use the SDK to initialize OpenTelemetry and the API to 19 | instrument your code. This will emit telemetry from your app, and any library 20 | you installed that also comes with instrumentation. 21 | 22 | - If you’re instrumenting a library, only install the OpenTelemetry API package 23 | for your language. Your library will not emit telemetry on its own. It will only 24 | emit telemetry when it is part of an app that uses the OpenTelemetry SDK. 25 | */ 26 | package otel 27 | -------------------------------------------------------------------------------- /cli/konf/config_test.go: -------------------------------------------------------------------------------- 1 | package konf 2 | 3 | import ( 4 | "flag" 5 | "os" 6 | "testing" 7 | 8 | tdd "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestKonf(t *testing.T) { 12 | assert := tdd.New(t) 13 | 14 | // ENV override 15 | os.Setenv("MYAPP_HTTP_PORT", "9092") 16 | 17 | // flag override 18 | flags := flag.NewFlagSet("start", flag.ContinueOnError) 19 | flags.Int("http.middleware.compression", 0, "gzip compression value") 20 | flags.Parse([]string{"--http.middleware.compression=7"}) 21 | 22 | locations := []string{"testdata/config.yaml"} 23 | locations = append(locations, DefaultLocations("sample-app", "config.yaml")...) 24 | opts := []Option{ 25 | WithFileLocations(locations), 26 | WithEnv("myapp"), 27 | WithFlags(flags), 28 | } 29 | config, err := Setup(opts...) 30 | assert.Nil(err, "load config") 31 | 32 | type sampleConf struct { 33 | Port int `yaml:"port"` 34 | Timeout int `yaml:"idle_timeout"` 35 | Middleware struct { 36 | Gzip int `yaml:"compression"` 37 | } 38 | } 39 | 40 | // default values 41 | appConf := sampleConf{ 42 | Port: 7070, 43 | Timeout: 5, 44 | } 45 | assert.Nil(config.Unmarshal("http", &appConf), "unmarshal") 46 | assert.Equal(9092, appConf.Port, "ENV override") 47 | assert.Equal(10, appConf.Timeout, "file override") 48 | assert.Equal(7, appConf.Middleware.Gzip, "flag override") 49 | t.Logf("\n%s\n", config.Explain("http")) 50 | } 51 | -------------------------------------------------------------------------------- /net/http/sample-openapi/petstore/oas_unimplemented_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by ogen, DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "context" 7 | 8 | ht "github.com/ogen-go/ogen/http" 9 | ) 10 | 11 | // UnimplementedHandler is no-op Handler which returns http.ErrNotImplemented. 12 | type UnimplementedHandler struct{} 13 | 14 | var _ Handler = UnimplementedHandler{} 15 | 16 | // AddPet implements addPet operation. 17 | // 18 | // Add a new pet to the store. 19 | // 20 | // POST /pet 21 | func (UnimplementedHandler) AddPet(ctx context.Context, req *Pet) (r *Pet, _ error) { 22 | return r, ht.ErrNotImplemented 23 | } 24 | 25 | // DeletePet implements deletePet operation. 26 | // 27 | // Deletes a pet. 28 | // 29 | // DELETE /pet/{petId} 30 | func (UnimplementedHandler) DeletePet(ctx context.Context, params DeletePetParams) error { 31 | return ht.ErrNotImplemented 32 | } 33 | 34 | // GetPetById implements getPetById operation. 35 | // 36 | // Returns a single pet. 37 | // 38 | // GET /pet/{petId} 39 | func (UnimplementedHandler) GetPetById(ctx context.Context, params GetPetByIdParams) (r GetPetByIdRes, _ error) { 40 | return r, ht.ErrNotImplemented 41 | } 42 | 43 | // UpdatePet implements updatePet operation. 44 | // 45 | // Updates a pet in the store. 46 | // 47 | // POST /pet/{petId} 48 | func (UnimplementedHandler) UpdatePet(ctx context.Context, params UpdatePetParams) error { 49 | return ht.ErrNotImplemented 50 | } 51 | -------------------------------------------------------------------------------- /storage/orm/transaction.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "go.mongodb.org/mongo-driver/bson" 5 | "go.mongodb.org/mongo-driver/mongo" 6 | ) 7 | 8 | // TransactionBody serves as a wrapper to group all operations 9 | // confirming a specific transaction. 10 | type TransactionBody func(tx *Transaction) error 11 | 12 | // Transaction instances allow to atomically run several operations. 13 | // If an operation fails, the whole transaction is reverted. 14 | type Transaction struct { 15 | ctx mongo.SessionContext 16 | done chan struct{} 17 | } 18 | 19 | // Commit the transaction. This method will return an error if the 20 | // transaction is no longer active or has been aborted. 21 | func (tx *Transaction) Commit() error { 22 | defer close(tx.done) 23 | return tx.ctx.CommitTransaction(tx.ctx) 24 | } 25 | 26 | // Abort the transaction and rollback all changes. This method will 27 | // return an error if transaction is no longer active, has been 28 | // committed or aborted. 29 | func (tx *Transaction) Abort() error { 30 | defer close(tx.done) 31 | return tx.ctx.AbortTransaction(tx.ctx) 32 | } 33 | 34 | // Done triggers a notification when the transaction is completed. 35 | // Either by abort or commit. 36 | func (tx *Transaction) Done() <-chan struct{} { 37 | return tx.done 38 | } 39 | 40 | // ID returns the session identifier for the transaction. 41 | func (tx *Transaction) ID() bson.Raw { 42 | return tx.ctx.ID() 43 | } 44 | -------------------------------------------------------------------------------- /amqp/options_test.go: -------------------------------------------------------------------------------- 1 | package amqp 2 | 3 | import ( 4 | xlog "go.bryk.io/pkg/log" 5 | "gopkg.in/yaml.v3" 6 | ) 7 | 8 | func ExampleWithLogger() { 9 | // Set the logger instance to use 10 | WithLogger(xlog.WithZero(xlog.ZeroOptions{ 11 | PrettyPrint: true, 12 | ErrorField: "error", 13 | })) 14 | } 15 | 16 | func ExampleWithPrefetch() { 17 | // Allow 5 in-flight message and a maximum of 512 bytes 18 | // in server-client buffers. 19 | WithPrefetch(5, 512) 20 | } 21 | 22 | func ExampleWithName() { 23 | // If not set, publishers are automatically named as "publisher-*" 24 | // and consumers as "consumer-*" 25 | WithName("custom-application-name") 26 | } 27 | 28 | func ExampleWithTopology() { 29 | // Allows to load an existing topology declaration, for example 30 | // from YAML or JSON file, or received from a remote location 31 | var sampleTopology = ` 32 | exchanges: 33 | - name: sample.tasks 34 | kind: direct 35 | durable: true 36 | - name: sample.notifications 37 | kind: fanout 38 | durable: true 39 | queues: 40 | - name: tasks 41 | durable: true 42 | arguments: 43 | - x-message-ttl: 10000 44 | - name: notifications 45 | durable: true 46 | bindings: 47 | - exchange: sample.notifications 48 | queue: notifications 49 | - exchange: sample.tasks 50 | queue: tasks 51 | routing_key: 52 | - foo 53 | - bar 54 | ` 55 | tp := Topology{} 56 | _ = yaml.Unmarshal([]byte(sampleTopology), &tp) 57 | WithTopology(tp) 58 | } 59 | -------------------------------------------------------------------------------- /crypto/x25519/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package x25519 provides a ECDH (Elliptic Curve Diffie-Hellman) wrapper for curve X25519. 3 | 4 | The main component in the package is the 'KeyPair' instance. Each key pair needs to be 5 | securely removed from memory by calling the "Destroy" method. 6 | 7 | # Key Creation 8 | 9 | There are 3 mechanisms to create a new key pair. 10 | 11 | // 1. Create a completely random new key 12 | rk, _ := New() 13 | 14 | // 2. Key using a given seed material 15 | sk, _ := FromSeed([]byte("material")) 16 | 17 | // 3. Load from PEM-encoded content 18 | pk, _ := Unmarshal(pemBinData) 19 | 20 | However created, the key pair instance always use a locked memory buffer to securely 21 | hold private information. Is mandatory to properly release the memory buffer after 22 | using the key by calling the 'Destroy' method. 23 | 24 | // Securely release in-memory secrets 25 | kp.Destroy() 26 | 27 | # Key Usage 28 | 29 | Diffie-Hellman is a shared key creation mechanism. The main use of a key pair is to 30 | generate a shared secret with a provided public key. 31 | 32 | // Generate peers 33 | alice, _ := New() 34 | bob, _ := New() 35 | defer alice.Destroy() 36 | defer bob.Destroy() 37 | 38 | // Generate shared secret on both sides 39 | s1 := alice.DH(bob.PublicKey()) 40 | s2 := bob.DH(alice.PublicKey()) 41 | 42 | // Test secrets 43 | if !bytes.Equal(s1, s2) { 44 | panic("failed to generate valid secret") 45 | } 46 | */ 47 | package x25519 48 | -------------------------------------------------------------------------------- /net/rpc/mw_protovalidate.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "context" 5 | 6 | "buf.build/go/protovalidate" 7 | "google.golang.org/grpc" 8 | "google.golang.org/grpc/codes" 9 | "google.golang.org/grpc/status" 10 | "google.golang.org/protobuf/reflect/protoreflect" 11 | ) 12 | 13 | func pvUnaryServerInterceptor() grpc.UnaryServerInterceptor { 14 | // nolint: lll 15 | return func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { 16 | msg, ok := req.(protoreflect.ProtoMessage) 17 | if !ok { 18 | return nil, status.Error(codes.InvalidArgument, "invalid message type") 19 | } 20 | if err := protovalidate.Validate(msg); err != nil { 21 | return nil, status.Error(codes.InvalidArgument, err.Error()) 22 | } 23 | return handler(ctx, req) 24 | } 25 | } 26 | 27 | func pvStreamServerInterceptor() grpc.StreamServerInterceptor { 28 | // nolint: lll 29 | return func(srv any, stream grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error { 30 | return handler(srv, &recvWrapper{ServerStream: stream}) 31 | } 32 | } 33 | 34 | type recvWrapper struct { 35 | grpc.ServerStream 36 | } 37 | 38 | func (s *recvWrapper) RecvMsg(m any) error { 39 | if err := s.ServerStream.RecvMsg(m); err != nil { 40 | return err 41 | } 42 | if msg, ok := m.(protoreflect.ProtoMessage); ok { 43 | if err := protovalidate.Validate(msg); err != nil { 44 | return err 45 | } 46 | } 47 | return nil 48 | } 49 | -------------------------------------------------------------------------------- /crypto/tred/config.go: -------------------------------------------------------------------------------- 1 | package tred 2 | 3 | import ( 4 | "crypto/rand" 5 | "io" 6 | 7 | "go.bryk.io/pkg/errors" 8 | ) 9 | 10 | // Config provides all configuration parameters available when creating a new 11 | // TRED worker agent. 12 | type Config struct { 13 | // Protocol version 14 | Version byte 15 | 16 | // Cipher code 17 | Cipher byte 18 | 19 | // Secure cryptographic key to use 20 | Key []byte 21 | 22 | // Internals 23 | rng io.Reader 24 | nonce [8]byte 25 | } 26 | 27 | // DefaultConfig generates sane default configuration parameters using the provided key value. 28 | func DefaultConfig(k []byte) (*Config, error) { 29 | c := &Config{ 30 | Version: Version10, 31 | Cipher: AES, 32 | Key: k, 33 | } 34 | return c, c.init() 35 | } 36 | 37 | // Validate the configuration instance against common setup errors. 38 | func (c *Config) Validate() error { 39 | // Cipher 40 | if _, ok := supportedCiphers[c.Cipher]; !ok { 41 | return errors.New(ErrUnsupportedCipher) 42 | } 43 | 44 | // Version 45 | if c.Version != Version10 { 46 | return errors.New(ErrUnsupportedVersion) 47 | } 48 | 49 | // No key if provided 50 | if len(c.Key) == 0 { 51 | return errors.New(ErrNoKey) 52 | } 53 | return nil 54 | } 55 | 56 | // Initialize internal configuration elements. 57 | func (c *Config) init() error { 58 | c.rng = rand.Reader 59 | if _, err := c.rng.Read(c.nonce[:]); err != nil { 60 | return errors.New(ErrRandomNonce) 61 | } 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /net/http/sample-openapi/README.md: -------------------------------------------------------------------------------- 1 | # OpenAPI Application 2 | 3 | Sample application that uses the [OpenAPI]() specification 4 | to define the interface of a web service. With the schema, you can then generate 5 | a client and server implementation using ogen. 6 | 7 | ## Usage 8 | 9 | * Install `ogen` 10 | 11 | ```bash 12 | go install -v github.com/ogen-go/ogen/cmd/ogen@latest 13 | ``` 14 | 15 | * Generate the client and server implementation from your schema file 16 | 17 | ```bash 18 | ogen -target petstore -clean petstore.yml 19 | ``` 20 | 21 | * Write a service implementation that conforms to the generated interface 22 | 23 | ```go 24 | type ServiceOperator struct {} 25 | 26 | func (svc *ServiceOperator) AddPet(ctx context.Context, req *api.Pet) (*api.Pet, error) { 27 | return nil, errors.New("not implemented") 28 | } 29 | 30 | // ...other methods... 31 | ``` 32 | 33 | * Run a server using your service implementation 34 | 35 | ```go 36 | // prepare service operator 37 | operator := newOperator() 38 | svc, _ := api.NewServer(operator) 39 | 40 | // prepare server instance 41 | srv, _ := http.NewServer( 42 | http.WithHandler(svc), // use service operator as handler 43 | http.WithPort(8080), 44 | http.WithMiddleware(mwRecovery.Handler()), 45 | http.WithMiddleware(mwGzip.Handler(5)), 46 | http.WithMiddleware(mwLog.Handler(log, nil)), 47 | ) 48 | 49 | // start server and listen for connections 50 | log.Info("server ready") 51 | return srv.Start() 52 | ``` 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without modification, are permitted 2 | provided that the following conditions are met: 3 | 4 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions 5 | and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of 8 | conditions and the following disclaimer in the documentation and/or other materials provided 9 | with the distribution. 10 | 11 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to 12 | endorse or promote products derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 16 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 18 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 21 | POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /net/http/sample-openapi/petstore/oas_server_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by ogen, DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "context" 7 | ) 8 | 9 | // Handler handles operations described by OpenAPI v3 specification. 10 | type Handler interface { 11 | // AddPet implements addPet operation. 12 | // 13 | // Add a new pet to the store. 14 | // 15 | // POST /pet 16 | AddPet(ctx context.Context, req *Pet) (*Pet, error) 17 | // DeletePet implements deletePet operation. 18 | // 19 | // Deletes a pet. 20 | // 21 | // DELETE /pet/{petId} 22 | DeletePet(ctx context.Context, params DeletePetParams) error 23 | // GetPetById implements getPetById operation. 24 | // 25 | // Returns a single pet. 26 | // 27 | // GET /pet/{petId} 28 | GetPetById(ctx context.Context, params GetPetByIdParams) (GetPetByIdRes, error) 29 | // UpdatePet implements updatePet operation. 30 | // 31 | // Updates a pet in the store. 32 | // 33 | // POST /pet/{petId} 34 | UpdatePet(ctx context.Context, params UpdatePetParams) error 35 | } 36 | 37 | // Server implements http server based on OpenAPI v3 specification and 38 | // calls Handler to handle requests. 39 | type Server struct { 40 | h Handler 41 | baseServer 42 | } 43 | 44 | // NewServer creates new Server. 45 | func NewServer(h Handler, opts ...ServerOption) (*Server, error) { 46 | s, err := newServerConfig(opts...).baseServer() 47 | if err != nil { 48 | return nil, err 49 | } 50 | return &Server{ 51 | h: h, 52 | baseServer: s, 53 | }, nil 54 | } 55 | -------------------------------------------------------------------------------- /net/drpc/client_tls.go: -------------------------------------------------------------------------------- 1 | package drpc 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | ) 7 | 8 | // ClientTLS defines the configuration options available when establishing 9 | // a secure communication channel with a server. 10 | type ClientTLS struct { 11 | // Whether to include system CAs. 12 | IncludeSystemCAs bool 13 | 14 | // Custom certificate authorities to include when accepting TLS connections. 15 | CustomCAs [][]byte 16 | 17 | // Name used to verify the hostname on the returned certificates. 18 | ServerName string 19 | 20 | // Don't verify the server name on the certificate when establishing a secure 21 | // TLS channel. THIS IS HIGHLY DANGEROUS, INTENDED FOR TESTING/DEV ONLY. 22 | SkipVerify bool 23 | } 24 | 25 | // Generate a proper TLS configuration to use on the client side. 26 | func (opts ClientTLS) conf() (*tls.Config, error) { 27 | conf := &tls.Config{ 28 | MinVersion: tls.VersionTLS12, 29 | } 30 | 31 | // Prepare cert pool 32 | var err error 33 | var cp *x509.CertPool 34 | if opts.IncludeSystemCAs { 35 | cp, err = x509.SystemCertPool() 36 | if err != nil { 37 | return nil, err 38 | } 39 | } else { 40 | cp = x509.NewCertPool() 41 | } 42 | 43 | // Append custom CA certs 44 | if len(opts.CustomCAs) > 0 { 45 | for _, c := range opts.CustomCAs { 46 | if !cp.AppendCertsFromPEM(c) { 47 | return nil, err 48 | } 49 | } 50 | } 51 | 52 | conf.RootCAs = cp 53 | conf.ServerName = opts.ServerName 54 | conf.InsecureSkipVerify = opts.SkipVerify 55 | return conf, nil 56 | } 57 | -------------------------------------------------------------------------------- /otel/sentry/span_map.go: -------------------------------------------------------------------------------- 1 | package sentry 2 | 3 | // Based on the original: github.com/getsentry/sentry-go/otel 4 | 5 | import ( 6 | "sync" 7 | 8 | sdk "github.com/getsentry/sentry-go" 9 | apiTrace "go.opentelemetry.io/otel/trace" 10 | ) 11 | 12 | // Map of Sentry spans to OpenTelemetry spans. 13 | // Singleton instance. 14 | var sentrySpanMap spanMap 15 | 16 | func init() { 17 | sentrySpanMap = spanMap{} 18 | sentrySpanMap.Clear() 19 | } 20 | 21 | // spanMap is a mapping between OpenTelemetry spans and Sentry spans. 22 | // It helps Sentry span processor and propagator to keep track of 23 | // unfinished Sentry spans and to establish parent-child links between 24 | // spans. 25 | type spanMap struct { 26 | db map[apiTrace.SpanID]*sdk.Span 27 | mu sync.RWMutex 28 | } 29 | 30 | func (sm *spanMap) Get(otelSpandID apiTrace.SpanID) (*sdk.Span, bool) { 31 | sm.mu.RLock() 32 | defer sm.mu.RUnlock() 33 | sp, ok := sm.db[otelSpandID] 34 | return sp, ok 35 | } 36 | 37 | func (sm *spanMap) Set(otelSpandID apiTrace.SpanID, sentrySpan *sdk.Span) { 38 | sm.mu.Lock() 39 | defer sm.mu.Unlock() 40 | sm.db[otelSpandID] = sentrySpan 41 | } 42 | 43 | func (sm *spanMap) Delete(otelSpandID apiTrace.SpanID) { 44 | sm.mu.Lock() 45 | defer sm.mu.Unlock() 46 | delete(sm.db, otelSpandID) 47 | } 48 | 49 | func (sm *spanMap) Clear() { 50 | sm.mu.Lock() 51 | defer sm.mu.Unlock() 52 | sm.db = make(map[apiTrace.SpanID]*sdk.Span) 53 | } 54 | 55 | func (sm *spanMap) Len() int { 56 | sm.mu.RLock() 57 | defer sm.mu.RUnlock() 58 | return len(sm.db) 59 | } 60 | -------------------------------------------------------------------------------- /crypto/tred/manifest.go: -------------------------------------------------------------------------------- 1 | package tred 2 | 3 | import ( 4 | "encoding/binary" 5 | ) 6 | 7 | type manifestBlock []byte 8 | 9 | // Length in bytes for the output manifestBlock. 10 | // 11 | // version | cipher | length | checksum 12 | const manifestSize = 38 13 | 14 | // Retrieve the manifest section from a byte array. 15 | // 16 | // version (1) | cipher (1) | length (4) | checksum (32) 17 | func manifest(b []byte) manifestBlock { 18 | return b[:manifestSize] 19 | } 20 | 21 | // Version return package's version byte. 22 | func (m manifestBlock) Version() byte { 23 | return m[0] 24 | } 25 | 26 | // Cipher return package's used AEAD cipher. 27 | func (m manifestBlock) Cipher() byte { 28 | return m[1] 29 | } 30 | 31 | // Len return manifest's packets count. 32 | func (m manifestBlock) Len() int { 33 | return int(binary.LittleEndian.Uint16(m[2:6])) + 1 34 | } 35 | 36 | // Checksum return manifest's checksum value. 37 | func (m manifestBlock) Checksum() []byte { 38 | return m[6:] 39 | } 40 | 41 | // SetVersion adjust manifest's version byte. 42 | func (m manifestBlock) SetVersion(version byte) { 43 | m[0] = version 44 | } 45 | 46 | // SetCipher adjust manifest's AEAD cipher byte. 47 | func (m manifestBlock) SetCipher(suite byte) { 48 | m[1] = suite 49 | } 50 | 51 | // SetLen adjust manifest's packets count. 52 | func (m manifestBlock) SetLen(length int) { 53 | binary.LittleEndian.PutUint16(m[2:6], uint16(length-1)) 54 | } 55 | 56 | // SetChecksum adjust manifest's checksum value. 57 | func (m manifestBlock) SetChecksum(val []byte) { 58 | copy(m[6:], val[:]) 59 | } 60 | -------------------------------------------------------------------------------- /cli/read.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "os" 8 | "os/signal" 9 | 10 | "go.bryk.io/pkg/errors" 11 | "golang.org/x/term" 12 | ) 13 | 14 | // ReadSecure will interactively prompt the user to enter a value. The value 15 | // provided won't be displayed on the screen. 16 | func ReadSecure(prompt string) ([]byte, error) { 17 | fmt.Print(prompt) 18 | defer fmt.Println() 19 | return term.ReadPassword(0) 20 | } 21 | 22 | // ReadPipedInput retrieves contents passed-in from standard input up to the 23 | // provided maximum number of bytes. 24 | func ReadPipedInput(maxLength int) ([]byte, error) { 25 | var input []byte 26 | 27 | // Fail to read stdin 28 | info, err := os.Stdin.Stat() 29 | if err != nil { 30 | return input, errors.Wrap(err, "failed to read stdin") 31 | } 32 | 33 | // No input passed in 34 | if info.Mode()&os.ModeCharDevice != 0 { 35 | return input, errors.New("no piped input") 36 | } 37 | 38 | // Read input 39 | reader := bufio.NewReader(os.Stdin) 40 | for { 41 | b, err := reader.ReadByte() 42 | if err != nil && errors.Is(err, io.EOF) { 43 | break 44 | } 45 | input = append(input, b) 46 | if len(input) == maxLength { 47 | break 48 | } 49 | } 50 | 51 | // Return provided input 52 | return input, nil 53 | } 54 | 55 | // SignalsHandler returns a properly configured OS signals handler channel. 56 | func SignalsHandler(list []os.Signal) chan os.Signal { 57 | signalsCh := make(chan os.Signal, 1) 58 | signal.Reset(list...) 59 | signal.Notify(signalsCh, list...) 60 | return signalsCh 61 | } 62 | -------------------------------------------------------------------------------- /net/rpc/ws/utils.go: -------------------------------------------------------------------------------- 1 | package ws 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "strings" 8 | 9 | "github.com/gorilla/websocket" 10 | ) 11 | 12 | type chuckWrapper struct { 13 | Result interface{} `json:"result"` 14 | Error string `json:"error"` 15 | } 16 | 17 | // Remove the result wrapper added by the gateway to stream chunks. 18 | // https://github.com/grpc-ecosystem/grpc-gateway/blob/master/runtime/handler.go#L189 19 | func removeResultWrapper(chunk []byte) []byte { 20 | wp := &chuckWrapper{} 21 | if err := json.Unmarshal(chunk, wp); err != nil { 22 | return chunk 23 | } 24 | if wp.Result != nil { 25 | data, err := json.Marshal(wp.Result) 26 | if err == nil && data != nil { 27 | return data 28 | } 29 | } 30 | return chunk 31 | } 32 | 33 | // IE and Edge do not delimit Sec-WebSocket-Protocol strings with spaces; 34 | // `Sec-Websocket-Protocol: Bearer, foo` is converted to `Authorization: Bearer foo`. 35 | func fixProtocolHeader(header string) string { 36 | tokens := strings.SplitN(header, "Bearer,", 2) 37 | if len(tokens) < 2 { 38 | return "" 39 | } 40 | return fmt.Sprintf("Bearer %v", strings.Trim(tokens[1], " ")) 41 | } 42 | 43 | // nolint: unused 44 | func isClosedConnError(err error) bool { 45 | if str := err.Error(); strings.Contains(str, "use of closed network connection") { 46 | return true 47 | } 48 | return websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) 49 | } 50 | 51 | func closeConnectionEarly(r *http.Request, param string) bool { 52 | return r.URL.Query().Get(param) != "" 53 | } 54 | -------------------------------------------------------------------------------- /net/sse/README.md: -------------------------------------------------------------------------------- 1 | # Server-Send Events 2 | 3 | Traditionally, a web page has to send a request to the server to receive new 4 | data; that is, the page requests data from the server. With server-sent events, 5 | it's possible for a server to send new data to a web page at any time, by 6 | pushing messages to the web page. 7 | 8 | More information: 9 | 10 | ## Server 11 | 12 | On the server side, you can use the `Handler` function to automatically 13 | create and handle SSE subscriptions based on incoming client HTTP requests. 14 | 15 | ```go 16 | // Handler 17 | router := lib.NewServeMux() 18 | router.HandleFunc("/sse", Handler(yourStreamSetupFunction)) 19 | 20 | // Server options 21 | opts := []http.Option{ 22 | // SSE requires no timeout on "keep-alive" connections 23 | http.WithIdleTimeout(0), 24 | http.WithHandler(router), 25 | http.WithPort(8080), 26 | } 27 | 28 | // Start server 29 | srv, _ := http.NewServer(opts...) 30 | go func() { 31 | _ = srv.Start() 32 | }() 33 | ``` 34 | 35 | ## Client 36 | 37 | A client instance can be used to subscribe to a SSE stream on the server. 38 | 39 | ```go 40 | // Create client instance 41 | cl, _ := NewClient(nil) 42 | 43 | // Prepare a request and submit it to the server to obtain 44 | // a subscription instance in return. 45 | req, _ := PrepareRequest(context.Background(), "http://localhost:8080/sse", nil) 46 | sub, err := cl.Subscribe(req) 47 | 48 | // Handle incoming events 49 | for ev := range sub.Receive() { 50 | fmt.Printf("server event: %+v", ev) 51 | } 52 | ``` 53 | -------------------------------------------------------------------------------- /net/drpc/middleware/server/auth_token.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "go.bryk.io/pkg/errors" 5 | "storj.io/drpc" 6 | "storj.io/drpc/drpcmetadata" 7 | ) 8 | 9 | // TokenValidator represents an external authentication mechanism used to validate 10 | // bearer credentials. In case of any error the validation function must return 11 | // 'false' and the server will return an 'invalid credentials' error message. 12 | type TokenValidator func(token string) bool 13 | 14 | // AuthByToken allows to use an external authentication mechanism using bearer 15 | // tokens as credentials. The token must be present in the request's metadata 16 | // under `key` and be valid according to the provided `validator`. 17 | func AuthByToken(key string, validator TokenValidator) Middleware { 18 | return func(next drpc.Handler) drpc.Handler { 19 | return authToken{ 20 | mKey: key, 21 | tVal: validator, 22 | next: next, 23 | } 24 | } 25 | } 26 | 27 | type authToken struct { 28 | mKey string 29 | tVal TokenValidator 30 | next drpc.Handler 31 | } 32 | 33 | func (md authToken) HandleRPC(stream drpc.Stream, rpc string) (err error) { 34 | data, ok := drpcmetadata.Get(stream.Context()) 35 | if !ok { 36 | return errors.New("authentication: missing credentials") // no metadata available 37 | } 38 | token, ok := data[md.mKey] 39 | if !ok { 40 | return errors.New("authentication: missing credentials") // no token set 41 | } 42 | if !md.tVal(token) { 43 | return errors.New("authentication: invalid credentials") // invalid token 44 | } 45 | return md.next.HandleRPC(stream, rpc) // continue 46 | } 47 | -------------------------------------------------------------------------------- /net/http/client_options.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | lib "net/http" 5 | "time" 6 | ) 7 | 8 | // ClientOption allows adjusting client settings following a functional pattern. 9 | type ClientOption func(srv *Client) error 10 | 11 | // WithRoundTripper adjust the transport used by the client instance. 12 | func WithRoundTripper(rt lib.RoundTripper) ClientOption { 13 | return func(c *Client) error { 14 | c.hc.Transport = rt 15 | return nil 16 | } 17 | } 18 | 19 | // WithTimeout specifies a time limit for requests made by this 20 | // Client. The timeout includes connection time, any redirects, 21 | // and reading the response body. The timer remains running after 22 | // Get, Head, Post, or Do return and will interrupt reading of the 23 | // Response.Body. 24 | func WithTimeout(timeout time.Duration) ClientOption { 25 | return func(c *Client) error { 26 | c.hc.Timeout = timeout 27 | return nil 28 | } 29 | } 30 | 31 | // WithCookieJar is used to insert relevant cookies into every outbound 32 | // Request and is updated with the cookie values of every inbound Response. 33 | // The Jar is consulted for every redirect that the Client follows. 34 | func WithCookieJar(jar lib.CookieJar) ClientOption { 35 | return func(c *Client) error { 36 | c.hc.Jar = jar 37 | return nil 38 | } 39 | } 40 | 41 | // WithInterceptors allows to transform/adjust every outbound Request 42 | // before being executed by the client. 43 | func WithInterceptors(ci ...func(req *lib.Request)) ClientOption { 44 | return func(c *Client) error { 45 | c.mw = append(c.mw, ci...) 46 | return nil 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /crypto/tred/header.go: -------------------------------------------------------------------------------- 1 | package tred 2 | 3 | import ( 4 | "encoding/binary" 5 | ) 6 | 7 | type headerBlock []byte 8 | 9 | // Retrieve the header section from a byte array. 10 | // 11 | // version (1) | cipher (1) | payload length (2) | seq (4) | nonce (8) 12 | func header(b []byte) headerBlock { 13 | return b[:headerSize] 14 | } 15 | 16 | // Version return package's version byte. 17 | func (h headerBlock) Version() byte { 18 | return h[0] 19 | } 20 | 21 | // Cipher return package's used AEAD cipher. 22 | func (h headerBlock) Cipher() byte { 23 | return h[1] 24 | } 25 | 26 | // Len return package's payload length. 27 | func (h headerBlock) Len() int { 28 | return int(binary.LittleEndian.Uint16(h[2:])) + 1 29 | } 30 | 31 | // SequenceNumber return package's seq number. 32 | func (h headerBlock) SequenceNumber() uint32 { 33 | return binary.LittleEndian.Uint32(h[4:]) 34 | } 35 | 36 | // SetVersion adjust the package's version byte. 37 | func (h headerBlock) SetVersion(version byte) { 38 | h[0] = version 39 | } 40 | 41 | // SetCipher adjust the package's AEAD cipher used. 42 | func (h headerBlock) SetCipher(suite byte) { 43 | h[1] = suite 44 | } 45 | 46 | // SetLen adjust the package's payload length. 47 | func (h headerBlock) SetLen(length int) { 48 | binary.LittleEndian.PutUint16(h[2:], uint16(length-1)) 49 | } 50 | 51 | // SetSequenceNumber adjust the package's seq number. 52 | func (h headerBlock) SetSequenceNumber(num uint32) { 53 | binary.LittleEndian.PutUint32(h[4:], num) 54 | } 55 | 56 | // SetNonce adjust the package's nonce value. 57 | func (h headerBlock) SetNonce(nonce [8]byte) { 58 | copy(h[8:], nonce[:]) 59 | } 60 | -------------------------------------------------------------------------------- /otel/gorm/logger.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | 8 | xlog "go.bryk.io/pkg/log" 9 | glog "gorm.io/gorm/logger" 10 | ) 11 | 12 | type logger struct { 13 | ll xlog.Logger 14 | slow time.Duration 15 | } 16 | 17 | func (gl *logger) LogMode(glog.LogLevel) glog.Interface { 18 | return gl 19 | } 20 | 21 | func (gl *logger) Info(_ context.Context, msg string, data ...interface{}) { 22 | gl.ll.Infof("%s: %+v", msg, data) 23 | } 24 | 25 | func (gl *logger) Warn(_ context.Context, msg string, data ...interface{}) { 26 | gl.ll.Warningf("%s: %+v", msg, data) 27 | } 28 | 29 | func (gl *logger) Error(_ context.Context, msg string, data ...interface{}) { 30 | gl.ll.Errorf("%s: %+v", msg, data) 31 | } 32 | 33 | func (gl *logger) Trace(_ context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) { 34 | elapsed := time.Since(begin) 35 | switch { 36 | case err != nil: 37 | sql, rows := fc() 38 | gl.ll.WithFields(xlog.Fields{ 39 | "gorm.sql": sql, 40 | "gorm.rows": rows, 41 | "gorm.elapsed_ms": elapsed.Milliseconds(), 42 | }).Error(err.Error()) 43 | case elapsed > gl.slow: 44 | sql, rows := fc() 45 | slowLog := fmt.Sprintf("SLOW SQL >= %v", gl.slow) 46 | gl.ll.WithFields(xlog.Fields{ 47 | "gorm.sql": sql, 48 | "gorm.rows": rows, 49 | "gorm.elapsed_ms": elapsed.Milliseconds(), 50 | }).Warning(slowLog) 51 | default: 52 | sql, rows := fc() 53 | gl.ll.WithFields(xlog.Fields{ 54 | "gorm.sql": sql, 55 | "gorm.rows": rows, 56 | "gorm.elapsed_ms": elapsed.Milliseconds(), 57 | }).Debug("SQL operation") 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | Please report to us any security issues you find. 4 | 5 | All security bugs in this repository should be reported by email to [info@bryk.io](mailto:info@bryk.io?subject=[GitHub]%20Security%20Report). This mail is delivered to a small security team. Your email will be acknowledged within 24 hours, and you'll receive a more detailed response to your email within 72 hours indicating the next steps in handling your report. 6 | 7 | After the initial reply to your report, the security team will endeavor to keep you informed of the progress being made towards a fix and full announcement. These updates will be sent at least every five days. In reality, this is more likely to be every 24-48 hours. 8 | 9 | ## Disclosure Process 10 | 11 | This project uses the following disclosure process: 12 | 13 | 1. Once the security report is received it is assigned a primary handler. This person coordinates the fix and release process. 14 | 15 | 2. The issue is confirmed and a list of affected software is determined. 16 | 17 | 3. Code is audited to find any potential similar problems. 18 | 19 | 4. If it is determined, in consultation with the submitter, that a CVE-ID is required, the primary handler will obtain one. 20 | 21 | 5. Fixes are prepared for, at least, the two most recent major releases and the head/master revision. 22 | 23 | This process can take some time, especially when coordination is required with maintainers of other projects. Every effort will be made to handle the bug in as timely a manner as possible, however it's important that we follow the process described above to ensure that disclosures are handled consistently. 24 | -------------------------------------------------------------------------------- /errors/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package errors provides an enhanced error management library. 3 | 4 | When dealing with unexpected or undesired behavior on any system (like issues and 5 | exceptions) the more information available, structured and otherwise, the better. 6 | Preserving error structure and context is particularly important since, in general, 7 | string comparisons on error messages are vulnerable to injection and can even cause 8 | security problems. On distributed systems is very useful, and often required, to 9 | preserve these details across service boundaries as well. 10 | 11 | The main goals of this package are: 12 | 13 | - Provide a simple, extensible and "familiar" implementation that can be easily 14 | used as a drop-in replacement for the standard "errors" package and popular 3rd 15 | party libraries. 16 | - Preserve the entire structure of errors across the wire using pluggable codecs. 17 | - Produce portable and PII-safe error reports. These reports can then be sent to 18 | any 3rd party service or webhook. 19 | - Enable fast, reliable and secure determination of whether a particular cause 20 | is present (not relying on the presence of a substring in the error message). 21 | - Being easily composable; by making it extensible with additional error annotations 22 | and supporting special behavior on custom error types. 23 | 24 | This library is mainly inspired on the original https://github.com/cockroachdb/errors 25 | package, while adding some specific adjustments. For additional information about the 26 | original package refer to [PR-36987](https://github.com/cockroachdb/cockroach/pull/36987) 27 | */ 28 | package errors 29 | -------------------------------------------------------------------------------- /errors/panic_test.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "testing" 5 | 6 | tdd "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | var samplePanic = `panic: sample error with '‹×›' [recovered] 10 | panic: sample error with '‹×›' 11 | 12 | goroutine 19 [running]: 13 | testing.tRunner.func1.1(0x1229020, 0xc00010e190) 14 | /usr/local/Cellar/go/1.15.3/libexec/src/testing/testing.go:1072 +0x46a 15 | testing.tRunner.func1(0xc000102900) 16 | /usr/local/Cellar/go/1.15.3/libexec/src/testing/testing.go:1075 +0x636 17 | panic(0x1229020, 0xc00010e190) 18 | /usr/local/Cellar/go/1.15.3/libexec/src/runtime/panic.go:975 +0x47a 19 | go.bryk.io/pkg/errors.TestRedactable(0xc000102900) 20 | /Users/ben/Documents/go/src/go.bryk.io/pkg/errors/api_test.go:22 +0x1af 21 | testing.tRunner(0xc000102900, 0x1250740) 22 | /usr/local/Cellar/go/1.15.3/libexec/src/testing/testing.go:1123 +0x203 23 | created by testing.(*T).Run 24 | /usr/local/Cellar/go/1.15.3/libexec/src/testing/testing.go:1168 +0x5bc` 25 | 26 | func TestParsePanic(t *testing.T) { 27 | assert := tdd.New(t) 28 | src, err := ParsePanic(samplePanic) 29 | assert.Nil(err, "parse failed") 30 | assert.Equal(6, len(src.StackTrace()), "incomplete stack trace") 31 | } 32 | 33 | func TestFromRecover(t *testing.T) { 34 | assert := tdd.New(t) 35 | defer func() { 36 | recovered := FromRecover(recover()) 37 | assert.NotNil(recovered, "parse failed") 38 | assert.True(len(recovered.StackTrace()) > 5, "invalid stack trace") 39 | t.Logf("%+v", recovered) 40 | }() 41 | _ = a() 42 | } 43 | 44 | func a() error { return b() } 45 | 46 | func b() error { return c() } 47 | 48 | func c() error { panic("cool programs never panic!!!") } 49 | -------------------------------------------------------------------------------- /net/csp/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package csp provides an easy-to-use "Content Security Policy" implementation. 3 | 4 | Content Security Policy (CSP) is an added layer of security that helps to detect 5 | and mitigate certain types of attacks, including Cross-Site Scripting (XSS) and 6 | data injection attacks. These attacks are used for everything from data theft, to 7 | site defacement, to malware distribution. 8 | 9 | As a general rule, a majority of complex web applications are susceptible to XSS, 10 | and would benefit from adopting CSP. In particular, CSP is recommended for applications 11 | which manage sensitive data such as administrative UIs and device management consoles, 12 | or products hosting user-generated documents, messages or media files. Especially 13 | in products using modern frameworks (Closure Templates) adopting CSP can be 14 | relatively straightforward and provide a large security improvement in exchange 15 | for a small-time investment. 16 | 17 | To enable a strict CSP policy (preventing the execution of untrusted scripts), 18 | most applications will need to make the following changes: 19 | - Add a nonce attribute to all 29 | 30 | More information: 31 | https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP 32 | */ 33 | package csp 34 | -------------------------------------------------------------------------------- /amqp/state_test.go: -------------------------------------------------------------------------------- 1 | package amqp 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "gopkg.in/yaml.v3" 8 | ) 9 | 10 | func ExampleTopology() { 11 | // To simplify storage and sharing. The topology for an application 12 | // can be easily managed either in YAML or JSON format. 13 | var inYAML = ` 14 | exchanges: 15 | - name: sample.tasks 16 | kind: direct 17 | durable: true 18 | - name: sample.notifications 19 | kind: fanout 20 | durable: true 21 | - name: sample.topic 22 | kind: topic 23 | queues: 24 | - name: hello 25 | durable: true 26 | auto_delete: false 27 | exclusive: false 28 | - name: tasks 29 | durable: true 30 | auto_delete: false 31 | exclusive: false 32 | - name: notifications 33 | durable: true 34 | auto_delete: false 35 | exclusive: false 36 | - name: by_topic 37 | bindings: 38 | - exchange: sample.notifications 39 | queue: notifications 40 | - exchange: sample.tasks 41 | queue: tasks 42 | routing_key: 43 | - foo 44 | - bar 45 | - exchange: sample.topic 46 | queue: by_topic 47 | routing_key: 48 | - stock.nyc.# 49 | ` 50 | tp := Topology{} 51 | err := yaml.Unmarshal([]byte(inYAML), &tp) 52 | if err != nil { 53 | panic(err) 54 | } 55 | } 56 | 57 | func ExampleQueueOptions_AsArguments() { 58 | ttl, _ := time.ParseDuration("15s") 59 | exp, _ := time.ParseDuration("1h") 60 | opts := QueueOptions{ 61 | MessageTTL: &ttl, 62 | Expiration: &exp, 63 | MaxLength: 500, 64 | MaxLengthBytes: 1024 * 100, // 100MB 65 | DLExchange: "sample.dead", 66 | SingleActiveConsumer: true, 67 | MaxPriority: 4, 68 | LazyMode: true, 69 | Overflow: OverflowRejectDL, 70 | } 71 | fmt.Printf("%+v", opts.AsArguments()) 72 | } 73 | -------------------------------------------------------------------------------- /crypto/x25519/keypair.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | // +build !js 3 | 4 | package x25519 5 | 6 | import ( 7 | "github.com/awnumar/memguard" 8 | c "golang.org/x/crypto/curve25519" 9 | ) 10 | 11 | // KeyPair represents a X25519 (Diffie-Hellman) public/private key. 12 | type KeyPair struct { 13 | public [32]byte 14 | lb *memguard.LockedBuffer 15 | } 16 | 17 | // PrivateKey returns the private key bytes of the key pair instance. Using 18 | // this method may unintentionally expose secret material outside the security 19 | // memory segment managed by the instance. Don't use it unless you really know 20 | // what you are doing. 21 | func (k *KeyPair) PrivateKey() []byte { 22 | if k.lb == nil { 23 | return nil 24 | } 25 | return k.lb.Bytes() 26 | } 27 | 28 | // Destroy will safely release the allocated mlock/VirtualLock memory. 29 | func (k *KeyPair) Destroy() { 30 | if k.lb != nil { 31 | k.lb.Destroy() 32 | } 33 | memguard.WipeBytes(k.public[:]) 34 | k.lb = nil 35 | } 36 | 37 | // Setup a key pair instance from the provided private key bytes. 38 | func fromPrivateKey(priv []byte, adjust bool) (*KeyPair, error) { 39 | // Adjust private key value 40 | // https://cr.yp.to/ecdh.html 41 | if adjust { 42 | priv[0] &= 248 43 | priv[31] &= 127 44 | priv[31] |= 64 45 | } 46 | 47 | // Get public key 48 | privateKey := [32]byte{} 49 | publicKey := [32]byte{} 50 | copy(privateKey[:], priv) 51 | if pb, err := c.X25519(privateKey[:], c.Basepoint); err == nil { 52 | copy(publicKey[:], pb) 53 | } 54 | 55 | // Clean and return key pair instance 56 | memguard.ScrambleBytes(privateKey[:]) 57 | memguard.WipeBytes(privateKey[:]) 58 | return &KeyPair{ 59 | public: publicKey, 60 | lb: memguard.NewBufferFromBytes(priv), 61 | }, nil 62 | } 63 | -------------------------------------------------------------------------------- /log/utils.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "strings" 5 | 6 | "go.bryk.io/pkg/metadata" 7 | ) 8 | 9 | func lPrint(ll SimpleLogger, lv Level, args ...any) { 10 | switch lv { 11 | case Debug: 12 | ll.Debug(args...) 13 | case Info: 14 | ll.Info(args...) 15 | case Warning: 16 | ll.Warning(args...) 17 | case Error: 18 | ll.Error(args...) 19 | case Panic: 20 | ll.Panic(args...) 21 | case Fatal: 22 | ll.Fatal(args...) 23 | } 24 | } 25 | 26 | func lPrintf(ll SimpleLogger, lv Level, format string, args ...any) { 27 | switch lv { 28 | case Debug: 29 | ll.Debugf(format, args...) 30 | case Info: 31 | ll.Infof(format, args...) 32 | case Warning: 33 | ll.Warningf(format, args...) 34 | case Error: 35 | ll.Errorf(format, args...) 36 | case Panic: 37 | ll.Panicf(format, args...) 38 | case Fatal: 39 | ll.Fatalf(format, args...) 40 | } 41 | } 42 | 43 | func sanitize(args ...any) []any { 44 | var ( 45 | vs string 46 | ok bool 47 | sv = make([]any, len(args)) 48 | ) 49 | for i, v := range args { 50 | // remove all newlines and carriage returns 51 | if vs, ok = v.(string); ok { 52 | v = strings.ReplaceAll(strings.ReplaceAll(vs, "\n", ""), "\r", "") 53 | } 54 | sv[i] = v 55 | } 56 | return sv 57 | } 58 | 59 | func fields(md ...metadata.MD) []any { 60 | // get all fields from the metadata 61 | fields := metadata.New() 62 | fields.Join(md...) 63 | values := fields.Values() 64 | 65 | // ensure max number of fields is not exceeded 66 | size := len(values) * 2 67 | if size > maxFields { 68 | size = maxFields 69 | } 70 | 71 | // build the list of fields 72 | i := 0 73 | list := make([]any, size) 74 | for k, v := range values { 75 | list[i] = k 76 | list[i+1] = v 77 | i += 2 78 | } 79 | return list 80 | } 81 | -------------------------------------------------------------------------------- /otel/gorm/options.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "go.bryk.io/pkg/otel" 5 | semConv "go.opentelemetry.io/otel/semconv/v1.30.0" 6 | ) 7 | 8 | // Option defines a function that configures the plugin behavior. 9 | type Option func(p *plugin) 10 | 11 | // WithAttributes register additional attributes that will be used 12 | // when creating spans. 13 | func WithAttributes(attrs map[string]interface{}) Option { 14 | return func(p *plugin) { 15 | kv := otel.Attributes(attrs) 16 | p.attrs = append(p.attrs, kv.Expand()...) 17 | } 18 | } 19 | 20 | // WithDBName configures a db.namespace attribute. 21 | func WithDBName(name string) Option { 22 | return func(p *plugin) { 23 | p.attrs = append(p.attrs, semConv.DBNamespaceKey.String(name)) 24 | } 25 | } 26 | 27 | // WithoutQueryVariables configures the db.statement attribute to exclude 28 | // query variables. 29 | func WithoutQueryVariables() Option { 30 | return func(p *plugin) { 31 | p.excludeQueryVars = true 32 | } 33 | } 34 | 35 | // WithQueryFormatter configures a query formatter. 36 | func WithQueryFormatter(queryFormatter func(query string) string) Option { 37 | return func(p *plugin) { 38 | p.queryFormatter = queryFormatter 39 | } 40 | } 41 | 42 | // WithoutMetrics prevents DBStats metrics from being reported. 43 | func WithoutMetrics() Option { 44 | return func(p *plugin) { 45 | p.excludeMetrics = true 46 | } 47 | } 48 | 49 | // WithIgnoredError registered errors that should be ignored by 50 | // the plugin when reporting spans. This is useful to avoid unnecessary 51 | // reports for common errors like "record not found" or "no rows". 52 | func WithIgnoredError(errors ...error) Option { 53 | return func(p *plugin) { 54 | p.ignoredErrors = append(p.ignoredErrors, errors...) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /otel/api/span_options.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "go.bryk.io/pkg/otel" 5 | apiTrace "go.opentelemetry.io/otel/trace" 6 | ) 7 | 8 | // SpanOption allow adjusting span settings at the moment of creation. 9 | type SpanOption func(conf *spanConfig) 10 | 11 | // Internal representation of a span configuration. 12 | type spanConfig struct { 13 | kind SpanKind 14 | opts []apiTrace.SpanStartOption 15 | attrs otel.Attributes 16 | } 17 | 18 | // WithSpanKind adjust the `span.kind` value for the created span. 19 | // When no value is provided, `unspecified` is used by default. 20 | func WithSpanKind(kind SpanKind) SpanOption { 21 | return func(sc *spanConfig) { 22 | sc.kind = kind 23 | } 24 | } 25 | 26 | // WithAttributes adds additional metadata related to a specific 27 | // task. These attributes are used to describe the work a Span represents. 28 | // If multiple of these options are passed the attributes of each 29 | // successive option will extend/override any previously set value. 30 | func WithAttributes(attrs map[string]any) SpanOption { 31 | return func(sc *spanConfig) { 32 | sc.attrs = otel.Attributes(attrs) 33 | } 34 | } 35 | 36 | // WithStartOptions allows passing additional options to the span 37 | // creation process. 38 | func WithStartOptions(opts ...apiTrace.SpanStartOption) SpanOption { 39 | return func(sc *spanConfig) { 40 | sc.opts = append(sc.opts, opts...) 41 | } 42 | } 43 | 44 | func defaultSpanConf() *spanConfig { 45 | return &spanConfig{kind: SpanKindUnspecified} 46 | } 47 | 48 | func (sc *spanConfig) startOpts() (opts []apiTrace.SpanStartOption) { 49 | opts = append(sc.opts, sc.kind.option()) 50 | if sc.attrs != nil { 51 | opts = append(opts, apiTrace.WithAttributes(sc.attrs.Expand()...)) 52 | } 53 | return opts 54 | } 55 | -------------------------------------------------------------------------------- /jose/jwt/README.md: -------------------------------------------------------------------------------- 1 | # Package `jwt` 2 | 3 | JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be 4 | transferred between two parties. The claims in a JWT are encoded as a JSON 5 | object that is used as the payload of a JSON Web Signature (JWS) structure or 6 | as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims 7 | to be digitally signed or integrity protected with a Message Authentication Code 8 | (MAC) and/or encrypted. JWTs are always represented using the JWS Compact 9 | Serialization or the JWE Compact Serialization. 10 | 11 | In its compact form, a JSON Web Token consist of three parts separated by dots. 12 | 13 | `Header.Payload.Signature` 14 | 15 | The signature is used to verify the message wasn't changed along the way 16 | (i.e., integrity), and in the case of tokens signed with a private key, it can 17 | also verify that the sender of the JWT is who it says it is (i.e., provenance). 18 | 19 | ## Claims 20 | 21 | The second part of the token is the payload, which contains the claims. Claims 22 | are statements about an entity (typically, the JWT holder) and additional data. 23 | There are three types of claims: registered, public, and private. 24 | 25 | Registered claims are a set of predefined claims which are not mandatory but 26 | recommended, to provide a set of useful, interoperable claims. 27 | 28 | Public claims can be defined at will by those using JWTs. But to avoid 29 | collisions they should be defined in the IANA JSON Web Token Registry or be 30 | defined as a URI that contains a collision resistant namespace. 31 | 32 | Private claims are the custom claims created to share information between 33 | parties that agree on using them and are neither registered nor public claims. 34 | 35 | More information: 36 | -------------------------------------------------------------------------------- /otel/gorm/main.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "database/sql" 5 | "time" 6 | 7 | "github.com/google/sqlcommenter/go/core" 8 | sqlC "github.com/google/sqlcommenter/go/database/sql" 9 | xlog "go.bryk.io/pkg/log" 10 | "gorm.io/gorm" 11 | glog "gorm.io/gorm/logger" 12 | ) 13 | 14 | // Plugin can be used to instrument any application using GORM. 15 | // To register the plugin symply call `db.Use`. 16 | // 17 | // plg := otelGorm.Plugin(otelGorm.WithIgnoredError(context.Canceled)) 18 | // db.Use(plg) 19 | func Plugin(opts ...Option) gorm.Plugin { 20 | return newPlugin(opts...) 21 | } 22 | 23 | // Logger returns a GORM log handler that uses the provided base logger 24 | // to report operations. The `slow` parameter can be used to define the 25 | // threshold to tag slow operations in ms; if not provided a default value 26 | // of 200 will be used. 27 | func Logger(log xlog.Logger, slow uint) glog.Interface { 28 | if slow == 0 { 29 | slow = 200 30 | } 31 | return &logger{ 32 | ll: log, 33 | slow: time.Duration(slow) * time.Millisecond, 34 | } 35 | } 36 | 37 | // Open provides a wrapper around the standard sql.Open function to 38 | // enable SQL commenter instrumentation. When used with GORM the returned 39 | // `*sql.DB` instance can be used as `gorm.ConnPool` 40 | // 41 | // More information: https://google.github.io/sqlcommenter/go/database_sql/ 42 | func Open(driver, conn string) (*sql.DB, error) { 43 | return sqlC.Open(driver, conn, core.CommenterOptions{ 44 | Config: core.CommenterConfig{ 45 | // base sql driver 46 | EnableDBDriver: true, 47 | // OTEL support 48 | EnableTraceparent: true, 49 | // web framework 50 | EnableRoute: true, 51 | EnableFramework: true, 52 | EnableController: true, 53 | EnableAction: true, 54 | EnableApplication: true, 55 | }, 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /jose/jwt/validator.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "go.bryk.io/pkg/errors" 5 | "go.bryk.io/pkg/jose/jwa" 6 | "go.bryk.io/pkg/jose/jwk" 7 | ) 8 | 9 | // Validator instances can be used when tokens need to be validated but 10 | // issuing is not possible or desired. For example when retrieving the 11 | // server's JWK key set including only public keys. 12 | type Validator struct { 13 | keys []jwk.Key 14 | } 15 | 16 | // NewValidator returns a new token validator instance ready to be used. 17 | func NewValidator(opts ...ValidatorOption) (*Validator, error) { 18 | v := &Validator{keys: []jwk.Key{}} 19 | for _, opt := range opts { 20 | if err := opt(v); err != nil { 21 | return nil, err 22 | } 23 | } 24 | return v, nil 25 | } 26 | 27 | // Validate a previously generated token instance. 28 | // 1. Is the string a valid JWT? 29 | // 2. Is 'alg' supported by the generator? 30 | // 3. Is the digital signature valid? 31 | // 4. Run all provided checks 32 | func (v *Validator) Validate(token string, checks ...Check) error { 33 | t, err := Parse(token) 34 | if err != nil { 35 | return err 36 | } 37 | 38 | // 'NONE' tokens require only payload validations 39 | alg := jwa.Alg(t.Header().Algorithm) 40 | if alg == jwa.NONE { 41 | return t.Validate(checks...) 42 | } 43 | 44 | // Verify 'alg' is supported 45 | if !isSupported(jwa.Alg(t.Header().Algorithm), v.keys) { 46 | return errors.New("unsupported 'alg' header") 47 | } 48 | 49 | // Verify signature for secure tokens 50 | if t.Header().Algorithm != string(jwa.NONE) { 51 | key := getKey(t.Header().KeyID, v.keys) 52 | if key == nil { 53 | return errors.New("invalid key identifier") 54 | } 55 | if err = verify(token, key); err != nil { 56 | return err 57 | } 58 | } 59 | 60 | // Basic payload validations 61 | return t.Validate(checks...) 62 | } 63 | -------------------------------------------------------------------------------- /crypto/shamir/polynomial_test.go: -------------------------------------------------------------------------------- 1 | package shamir 2 | 3 | import ( 4 | "testing" 5 | 6 | tdd "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestField(t *testing.T) { 10 | assert := tdd.New(t) 11 | 12 | t.Run("Add", func(t *testing.T) { 13 | assert.Equal(uint8(0), add(16, 16), "invalid result") 14 | assert.Equal(uint8(7), add(3, 4), "invalid result") 15 | }) 16 | 17 | t.Run("Multiply", func(t *testing.T) { 18 | assert.Equal(uint8(9), multiply(3, 7), "invalid result") 19 | assert.Equal(uint8(0), multiply(3, 0), "invalid result") 20 | assert.Equal(uint8(0), multiply(0, 3), "invalid result") 21 | }) 22 | 23 | t.Run("Divide", func(t *testing.T) { 24 | assert.Equal(uint8(0), div(0, 7), "invalid result") 25 | assert.Equal(uint8(1), div(3, 3), "invalid result") 26 | assert.Equal(uint8(2), div(6, 3), "invalid result") 27 | }) 28 | } 29 | 30 | func TestPolynomial_Random(t *testing.T) { 31 | assert := tdd.New(t) 32 | p, err := makePolynomial(42, 2) 33 | assert.Nil(err, "failed to make polynomial") 34 | assert.Equal(uint8(42), p.coefficients[0], "bad result") 35 | } 36 | 37 | func TestPolynomial_Eval(t *testing.T) { 38 | assert := tdd.New(t) 39 | p, err := makePolynomial(42, 1) 40 | assert.Nil(err, "failed to make polynomial") 41 | assert.Equal(uint8(42), p.evaluate(0), "evaluate error") 42 | out := p.evaluate(1) 43 | assert.Equal(out, add(42, multiply(1, p.coefficients[1])), "bad result") 44 | } 45 | 46 | func TestInterpolate_Rand(t *testing.T) { 47 | assert := tdd.New(t) 48 | for i := 0; i < 256; i++ { 49 | p, err := makePolynomial(uint8(i), 2) 50 | assert.Nil(err, "failed to make polynomial") 51 | 52 | xVals := []uint8{1, 2, 3} 53 | yVals := []uint8{p.evaluate(1), p.evaluate(2), p.evaluate(3)} 54 | out := interpolatePolynomial(xVals, yVals, 0) 55 | assert.Equal(out, uint8(i), "bad result") 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /net/http/server.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "context" 5 | "crypto/tls" 6 | lib "net/http" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | // Server provides the main HTTP(S) service provider. 12 | type Server struct { 13 | nh *lib.Server 14 | sh lib.Handler 15 | mw []func(lib.Handler) lib.Handler 16 | mu sync.Mutex 17 | tls *tls.Config 18 | port int 19 | } 20 | 21 | // NewServer returns a new ready-to-use server instance adjusted with the 22 | // provided configuration options. 23 | func NewServer(options ...Option) (*Server, error) { 24 | srv := &Server{ 25 | nh: &lib.Server{ 26 | MaxHeaderBytes: 1024, 27 | ReadHeaderTimeout: 2 * time.Second, 28 | ReadTimeout: 5 * time.Second, 29 | IdleTimeout: 5 * time.Second, 30 | WriteTimeout: 5 * time.Second, 31 | }, 32 | mw: []func(lib.Handler) lib.Handler{}, 33 | } 34 | 35 | // Apply user settings 36 | for _, opt := range options { 37 | if err := opt(srv); err != nil { 38 | return nil, err 39 | } 40 | } 41 | 42 | // Apply middleware 43 | for _, mw := range srv.mw { 44 | srv.sh = mw(srv.sh) 45 | } 46 | return srv, nil 47 | } 48 | 49 | // Start the server instance and start receiving and handling requests. 50 | func (srv *Server) Start() error { 51 | srv.nh.Handler = srv.sh 52 | if srv.tls != nil { 53 | return srv.nh.ListenAndServeTLS("", "") 54 | } 55 | return srv.nh.ListenAndServe() 56 | } 57 | 58 | // Stop the server instance. If graceful is set, the server closes without 59 | // interrupting any active connections by first closing all open listeners, 60 | // then closing all idle connections, and then waiting indefinitely for 61 | // connections to return to idle. 62 | func (srv *Server) Stop(graceful bool) error { 63 | if !graceful { 64 | return srv.nh.Close() 65 | } 66 | return srv.nh.Shutdown(context.Background()) 67 | } 68 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: "\U0001F4A1 Feature Request" 2 | description: Suggest an idea for this project 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | Thanks for taking the time to request this feature! If your feature request is complex or substantial enough to warrant in-depth discussion, maintainers may close the issue and ask you to open an RFC. 8 | - type: textarea 9 | id: problem 10 | attributes: 11 | label: Describe the problem 12 | description: Please provide a clear and concise description the problem this feature would solve. The more information you can provide here, the better. 13 | placeholder: I'm always frustrated when... 14 | validations: 15 | required: true 16 | - type: textarea 17 | id: solution 18 | attributes: 19 | label: Describe the proposed solution 20 | description: Please provide a clear and concise description of what you would like to happen. 21 | placeholder: I would like to see... 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: alternatives 26 | attributes: 27 | label: Alternatives considered 28 | description: "Please provide a clear and concise description of any alternative solutions or features you've considered." 29 | - type: dropdown 30 | id: importance 31 | attributes: 32 | label: Importance 33 | description: How important is this feature to you? 34 | options: 35 | - Nice to have 36 | - Would make my life easier 37 | - Cannot use this project without it 38 | validations: 39 | required: true 40 | - type: textarea 41 | id: additional-context 42 | attributes: 43 | label: Additional information 44 | description: Add any other context or screenshots about the feature request here. 45 | -------------------------------------------------------------------------------- /net/csp/policy_test.go: -------------------------------------------------------------------------------- 1 | package csp 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | tdd "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestNew(t *testing.T) { 11 | assert := tdd.New(t) 12 | 13 | options := []Option{ 14 | // disables URIs, preventing attackers from changing the locations of scripts 15 | // loaded from relative URLs 16 | WithBaseURI("'none'"), 17 | // report policy violations 18 | WithReportTo("/reports", "/another-endpoint"), 19 | // disable loading all external content 20 | WithDefaultSrc("'self'"), 21 | // don't enforce policy; use only for testing 22 | WithReportOnly(), 23 | // loose JS execution restrictions; use only for testing 24 | UnsafeEval(), 25 | } 26 | p, err := New(options...) 27 | assert.Nil(err) 28 | t.Logf("nonce: %s", p.Refresh()) 29 | t.Logf("report-to: %s", sink(p.reportTo)) 30 | t.Logf("policy: \n%s\n", p.Compile()) 31 | 32 | // Use for validation 33 | // https://csp-evaluator.withgoogle.com/ 34 | } 35 | 36 | func ExampleNew() { 37 | options := []Option{ 38 | // disables URIs, preventing attackers from changing the locations of scripts 39 | // loaded from relative URLs 40 | WithBaseURI("'none'"), 41 | // report policy violations 42 | WithReportTo("/reports", "/another-endpoint"), 43 | // disable loading all external content 44 | WithDefaultSrc("'self'"), 45 | // don't enforce policy; use only for testing 46 | WithReportOnly(), 47 | // loose JS execution restrictions; use only for testing 48 | UnsafeEval(), 49 | } 50 | 51 | // Create your policy object 52 | policy, err := New(options...) 53 | if err != nil { 54 | panic(err) 55 | } 56 | 57 | // For every page load create a new nonce value 58 | nonce := policy.Refresh() 59 | fmt.Printf("1. pass the nonce to any templates: %s", nonce) 60 | fmt.Printf("2. use `policy.Handler` as server middleware") 61 | } 62 | -------------------------------------------------------------------------------- /net/http/sample-openapi/petstore/oas_response_encoders_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by ogen, DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "net/http" 7 | 8 | "github.com/go-faster/errors" 9 | "github.com/go-faster/jx" 10 | "go.opentelemetry.io/otel/codes" 11 | "go.opentelemetry.io/otel/trace" 12 | ) 13 | 14 | func encodeAddPetResponse(response *Pet, w http.ResponseWriter, span trace.Span) error { 15 | w.Header().Set("Content-Type", "application/json; charset=utf-8") 16 | w.WriteHeader(200) 17 | span.SetStatus(codes.Ok, http.StatusText(200)) 18 | 19 | e := new(jx.Encoder) 20 | response.Encode(e) 21 | if _, err := e.WriteTo(w); err != nil { 22 | return errors.Wrap(err, "write") 23 | } 24 | 25 | return nil 26 | } 27 | 28 | func encodeDeletePetResponse(response *DeletePetOK, w http.ResponseWriter, span trace.Span) error { 29 | w.WriteHeader(200) 30 | span.SetStatus(codes.Ok, http.StatusText(200)) 31 | 32 | return nil 33 | } 34 | 35 | func encodeGetPetByIdResponse(response GetPetByIdRes, w http.ResponseWriter, span trace.Span) error { 36 | switch response := response.(type) { 37 | case *Pet: 38 | w.Header().Set("Content-Type", "application/json; charset=utf-8") 39 | w.WriteHeader(200) 40 | span.SetStatus(codes.Ok, http.StatusText(200)) 41 | 42 | e := new(jx.Encoder) 43 | response.Encode(e) 44 | if _, err := e.WriteTo(w); err != nil { 45 | return errors.Wrap(err, "write") 46 | } 47 | 48 | return nil 49 | 50 | case *GetPetByIdNotFound: 51 | w.WriteHeader(404) 52 | span.SetStatus(codes.Error, http.StatusText(404)) 53 | 54 | return nil 55 | 56 | default: 57 | return errors.Errorf("unexpected response type: %T", response) 58 | } 59 | } 60 | 61 | func encodeUpdatePetResponse(response *UpdatePetOK, w http.ResponseWriter, span trace.Span) error { 62 | w.WriteHeader(200) 63 | span.SetStatus(codes.Ok, http.StatusText(200)) 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /ulid/README.md: -------------------------------------------------------------------------------- 1 | # Package `ulid` 2 | 3 | Universally Unique Lexicographically Sortable Identifier implementation. 4 | 5 | A GUID/UUID can be suboptimal for many use-cases because: 6 | 7 | - It isn't the most character efficient way of encoding 128 bits 8 | - UUID v1/v2 is impractical in many environments, as it requires access 9 | to a unique, stable MAC address 10 | - UUID v3/v5 requires a unique seed and produces randomly distributed IDs, 11 | which can cause fragmentation in many data structures 12 | - UUID v4 provides no other information than randomness which can cause 13 | fragmentation in many data structures 14 | 15 | A ULID however: 16 | 17 | - Case insensitive 18 | - No special characters (URL safe) 19 | - Monotonic sort order (correctly detects and handles the same millisecond) 20 | - Is compatible with UUID/GUID's 21 | - Lexicographically sortable 22 | - Canonically encoded as a 26 character string, as opposed to the 36 character UUID 23 | - 1.21e+24 unique ULIDs per millisecond (1,208,925,819,614,629,174,706,176 24 | to be exact) 25 | - Uses Crockford's base32 for better efficiency and readability (5 bits per 26 | character) 27 | 28 | ## Disclaimer 29 | 30 | This package is a simplified version of the original implementation 31 | at: 32 | 33 | Copyright 2016 The Oklog Authors 34 | Licensed under the Apache License, Version 2.0 (the "License"); 35 | you may not use this file except in compliance with the License. 36 | You may obtain a copy of the License at 37 | 38 | 39 | 40 | Unless required by applicable law or agreed to in writing, software 41 | distributed under the License is distributed on an "AS IS" BASIS, 42 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 43 | See the License for the specific language governing permissions and 44 | limitations under the License. 45 | -------------------------------------------------------------------------------- /jose/jwt/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package jwt provides a JSON Web Token (JWT) implementation as specified by RFC-7519. 3 | 4 | JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be 5 | transferred between two parties. The claims in a JWT are encoded as a JSON 6 | object that is used as the payload of a JSON Web Signature (JWS) structure or 7 | as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims 8 | to be digitally signed or integrity protected with a Message Authentication Code 9 | (MAC) and/or encrypted. JWTs are always represented using the JWS Compact 10 | Serialization or the JWE Compact Serialization. 11 | 12 | In its compact form, a JSON Web Token consist of three parts separated by dots. 13 | 14 | Header.Payload.Signature 15 | 16 | The signature is used to verify the message wasn't changed along the way (i.e., integrity), 17 | and in the case of tokens signed with a private key, it can also verify that the sender 18 | of the JWT is who it says it is (i.e., provenance). 19 | 20 | # Claims 21 | 22 | The second part of the token is the payload, which contains the claims. Claims are 23 | statements about an entity (typically, the JWT holder) and additional data. There 24 | are three types of claims: registered, public, and private. 25 | 26 | Registered claims are a set of predefined claims which are not mandatory but recommended, 27 | to provide a set of useful, interoperable claims. 28 | 29 | Public claims can be defined at will by those using JWTs. But to avoid collisions they 30 | should be defined in the IANA JSON Web Token Registry or be defined as a URI that 31 | contains a collision resistant namespace. 32 | 33 | Private claims are the custom claims created to share information between parties that 34 | agree on using them and are neither registered nor public claims. 35 | 36 | More information: 37 | https://tools.ietf.org/html/rfc7519 38 | */ 39 | package jwt 40 | -------------------------------------------------------------------------------- /otel/http/options.go: -------------------------------------------------------------------------------- 1 | package otelhttp 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | // Option elements provide a functional-style mechanism to adjust the HTTP 8 | // monitor behavior. 9 | type Option func(mon *httpMonitor) 10 | 11 | // Filter is a predicate used to determine whether a given http.request 12 | // should be traced. A Filter must return true if the request should be 13 | // traced. 14 | type Filter func(*http.Request) bool 15 | 16 | // SpanNameFormatter allows to adjust how a given transaction is reported 17 | // when handling an HTTP request on the client or server side. 18 | type SpanNameFormatter func(r *http.Request) string 19 | 20 | // WithSpanNameFormatter allows to adjust how spans are reported. 21 | func WithSpanNameFormatter(nf SpanNameFormatter) Option { 22 | return func(mon *httpMonitor) { 23 | mon.nf = nf 24 | } 25 | } 26 | 27 | // WithNetworkEvents instructs the monitor to collect read and 28 | // write network events. These events are discarded by default. 29 | func WithNetworkEvents() Option { 30 | return func(mon *httpMonitor) { 31 | mon.ev = true 32 | } 33 | } 34 | 35 | // WithTraceInHeader allows to set a custom header to report the 36 | // transaction ID. The server will use this header to report the trace 37 | // ID to the client. 38 | func WithTraceInHeader(h string) Option { 39 | return func(mon *httpMonitor) { 40 | mon.rt = h 41 | } 42 | } 43 | 44 | // WithFilter adds a filter function to the monitor. If any filter 45 | // indicates to exclude a request then the request will not be traced. 46 | // All filters must allow a request to be traced for a Span to be created. 47 | // If no filters are provided then all requests are traced. Filters will 48 | // be invoked for each processed request, it is advised to make them 49 | // simple and fast. 50 | func WithFilter(f Filter) Option { 51 | return func(mon *httpMonitor) { 52 | mon.ft = append(mon.ft, f) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /errors/codec_json.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | // CodecJSON encodes error data as JSON documents. If `pretty` 10 | // is set to `true` the output will be indented for readability. 11 | func CodecJSON(pretty bool) Codec { 12 | return &jsonCodec{pretty: pretty} 13 | } 14 | 15 | type errReport struct { 16 | Msg string `json:"error,omitempty"` 17 | Stamp int64 `json:"stamp,omitempty"` 18 | Frames []StackFrame `json:"frames,omitempty"` 19 | Hints []string `json:"hints,omitempty"` 20 | Tags map[string]interface{} `json:"tags,omitempty"` 21 | Events []Event `json:"events,omitempty"` 22 | } 23 | 24 | type jsonCodec struct { 25 | pretty bool 26 | } 27 | 28 | func (c *jsonCodec) Marshal(err error) ([]byte, error) { 29 | rec := new(errReport) 30 | rec.Msg = err.Error() 31 | var oe *Error 32 | if As(err, &oe) { 33 | rec.Stamp = oe.Stamp() 34 | rec.Frames = oe.PortableTrace() // oe.StackTrace() 35 | rec.Hints = oe.Hints() 36 | rec.Tags = oe.Tags() 37 | rec.Events = oe.Events() 38 | } 39 | if c.pretty { 40 | return json.MarshalIndent(rec, "", " ") 41 | } 42 | return json.Marshal(rec) 43 | } 44 | 45 | func (c *jsonCodec) Unmarshal(src []byte) (bool, error) { 46 | // validate error report 47 | rep := new(errReport) 48 | if err := json.Unmarshal(src, rep); err != nil { 49 | return false, nil 50 | } 51 | 52 | // restore recovered error details 53 | rec := new(Error) 54 | rec.ts = rep.Stamp 55 | rec.frames = rep.Frames 56 | rec.hints = rep.Hints 57 | rec.tags = rep.Tags 58 | rec.events = rep.Events 59 | 60 | // parse error message 61 | msg := strings.Split(rep.Msg, ":") 62 | if len(msg) > 1 { 63 | rec.prefix = msg[0] 64 | rec.err = fmt.Errorf("%s", strings.Join(msg[1:], ": ")) 65 | } else { 66 | rec.err = fmt.Errorf("%s", rep.Msg) 67 | } 68 | return true, rec 69 | } 70 | -------------------------------------------------------------------------------- /ulid/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package ulid provides a Universally Unique Lexicographically Sortable Identifier implementation. 3 | 4 | A GUID/UUID can be suboptimal for many use-cases because: 5 | 6 | - It isn't the most character efficient way of encoding 128 bits 7 | - UUID v1/v2 is impractical in many environments, as it requires access 8 | to a unique, stable MAC address 9 | - UUID v3/v5 requires a unique seed and produces randomly distributed IDs, 10 | which can cause fragmentation in many data structures 11 | - UUID v4 provides no other information than randomness which can cause 12 | fragmentation in many data structures 13 | 14 | A ULID however: 15 | 16 | - Case insensitive 17 | - No special characters (URL safe) 18 | - Monotonic sort order (correctly detects and handles the same millisecond) 19 | - Is compatible with UUID/GUID's 20 | - Lexicographically sortable 21 | - Canonically encoded as a 26 character string, as opposed to the 36 character UUID 22 | - 1.21e+24 unique ULIDs per millisecond (1,208,925,819,614,629,174,706,176 23 | to be exact) 24 | - Uses Crockford's base32 for better efficiency and readability (5 bits per 25 | character) 26 | 27 | # Disclaimer 28 | 29 | This package is a simplified version of the original implementation 30 | at: https://github.com/oklog/ulid 31 | 32 | Copyright 2016 The Oklog Authors 33 | Licensed under the Apache License, Version 2.0 (the "License"); 34 | you may not use this file except in compliance with the License. 35 | You may obtain a copy of the License at 36 | 37 | http://www.apache.org/licenses/LICENSE-2.0 38 | 39 | Unless required by applicable law or agreed to in writing, software 40 | distributed under the License is distributed on an "AS IS" BASIS, 41 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 42 | See the License for the specific language governing permissions and 43 | limitations under the License. 44 | */ 45 | package ulid 46 | -------------------------------------------------------------------------------- /errors/redactable_test.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | 8 | tdd "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestSensitiveMessage(t *testing.T) { 12 | assert := tdd.New(t) 13 | var msg string 14 | secret := SensitiveMessage("my name is %s (or %03d)", "bond", 7) 15 | 16 | // Format with '%s' (redacted) 17 | msg = fmt.Sprintf("%s", secret) 18 | assert.Equal(0, strings.Count(msg, "bond")) 19 | assert.Equal(0, strings.Count(msg, "007")) 20 | assert.Equal(2, strings.Count(msg, piiMarker)) 21 | 22 | // Format with '%v' (redacted) 23 | msg = fmt.Sprintf("%v", secret) 24 | assert.Equal(0, strings.Count(msg, "bond")) 25 | assert.Equal(0, strings.Count(msg, "007")) 26 | assert.Equal(2, strings.Count(msg, piiMarker)) 27 | 28 | // Format with '%+v' (disclosed) 29 | msg = fmt.Sprintf("%+v", secret) 30 | assert.Equal(1, strings.Count(msg, "bond")) 31 | assert.Equal(1, strings.Count(msg, "007")) 32 | assert.Equal(0, strings.Count(msg, piiMarker)) 33 | 34 | // Use a redactable message to create an error instance 35 | t.Run("AsError", func(t *testing.T) { 36 | e1 := New(secret) 37 | 38 | // Obtaining the textual representation of the error won't leak 39 | // any secret details. 40 | msg = e1.Error() 41 | assert.Equal(0, strings.Count(msg, "bond")) 42 | assert.Equal(0, strings.Count(msg, "007")) 43 | assert.Equal(2, strings.Count(msg, piiMarker)) 44 | 45 | // Printing the error stacktrace won't leak any secret details 46 | msg = fmt.Sprintf("%v", e1) 47 | assert.Equal(0, strings.Count(msg, "bond")) 48 | assert.Equal(0, strings.Count(msg, "007")) 49 | assert.Equal(2, strings.Count(msg, piiMarker)) 50 | 51 | // Printing the portable version of error stacktrace won't leak 52 | // any secret details 53 | msg = fmt.Sprintf("%+v", e1) 54 | assert.Equal(0, strings.Count(msg, "bond")) 55 | assert.Equal(0, strings.Count(msg, "007")) 56 | assert.Equal(2, strings.Count(msg, piiMarker)) 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /net/drpc/ws/options.go: -------------------------------------------------------------------------------- 1 | package ws 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | ) 7 | 8 | // ProxyOption provides functional-style configuration settings for a proxy instance. 9 | type ProxyOption func(p *Proxy) error 10 | 11 | // EnableCompression specify if the server should attempt to negotiate per 12 | // message compression (RFC 7692). Setting this value to true does not guarantee 13 | // that compression will be supported. Currently, only "no context takeover" 14 | // modes are supported. 15 | func EnableCompression() ProxyOption { 16 | return func(p *Proxy) error { 17 | p.wsConf.EnableCompression = true 18 | return nil 19 | } 20 | } 21 | 22 | // CheckOrigin should return true if the request Origin header is acceptable. 23 | // If no setting is provided a safe default is used: return false if the Origin 24 | // request header is present and the origin host is not equal to request Host 25 | // header. A CheckOrigin function should carefully validate the request origin 26 | // to prevent cross-site request forgery. 27 | func CheckOrigin(f func(*http.Request) bool) ProxyOption { 28 | return func(p *Proxy) error { 29 | p.wsConf.CheckOrigin = f 30 | return nil 31 | } 32 | } 33 | 34 | // SubProtocols specifies the server's supported protocols in order of preference. 35 | // If no value is provided, the server negotiates a sub-protocol by selecting 36 | // the first match in this list with a protocol requested by the client. If there's 37 | // no match, then no protocol is negotiated (the Sec-Websocket-Protocol header 38 | // is not included in the handshake response). 39 | func SubProtocols(list []string) ProxyOption { 40 | return func(p *Proxy) error { 41 | p.wsConf.Subprotocols = list 42 | return nil 43 | } 44 | } 45 | 46 | // HandshakeTimeout specifies the duration for the handshake to complete. 47 | func HandshakeTimeout(timeout time.Duration) ProxyOption { 48 | return func(p *Proxy) error { 49 | p.wsConf.HandshakeTimeout = timeout 50 | return nil 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /otel/testdata/otel-collector-config.yaml: -------------------------------------------------------------------------------- 1 | # https://opentelemetry.io/docs/collector/configuration/ 2 | # https://github.com/open-telemetry/opentelemetry-collector/blob/main/extension/README.md 3 | extensions: 4 | health_check: 5 | endpoint: 0.0.0.0:13133 6 | # https://github.com/open-telemetry/opentelemetry-collector/blob/main/receiver/README.md 7 | receivers: 8 | otlp: 9 | protocols: 10 | grpc: 11 | endpoint: "0.0.0.0:4317" 12 | http: 13 | endpoint: "0.0.0.0:4318" 14 | cors: 15 | allowed_origins: ["*"] 16 | allowed_headers: ["*"] 17 | # https://github.com/open-telemetry/opentelemetry-collector/blob/main/processor/README.md 18 | processors: 19 | memory_limiter: 20 | check_interval: 1s 21 | limit_mib: 500 22 | spike_limit_mib: 100 23 | batch: 24 | send_batch_size: 100 25 | timeout: 2s 26 | resource: 27 | attributes: 28 | - key: collector.level.field 29 | value: "zone-1" 30 | action: upsert 31 | # https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/README.md 32 | exporters: 33 | debug: 34 | verbosity: basic 35 | sampling_initial: 5 36 | sampling_thereafter: 10 37 | # Jaeger now supports OTLP directly. 38 | # https://opentelemetry.io/blog/2023/jaeger-exporter-collector-migration/ 39 | otlp/jaeger: 40 | endpoint: "jaeger:4317" 41 | tls: 42 | insecure: true 43 | zipkin: 44 | endpoint: "http://zipkin:9411/api/v2/spans" 45 | tls: 46 | insecure: true 47 | service: 48 | extensions: [health_check] 49 | pipelines: 50 | traces: 51 | receivers: [otlp] 52 | processors: [memory_limiter, batch, resource] 53 | exporters: [debug, otlp/jaeger, zipkin] 54 | metrics: 55 | receivers: [otlp] 56 | processors: [memory_limiter, batch, resource] 57 | exporters: [debug] 58 | logs: 59 | receivers: [otlp] 60 | processors: [memory_limiter, batch, resource] 61 | exporters: [debug] 62 | -------------------------------------------------------------------------------- /proto/sample/v1/bar_api.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sample.v1; 4 | 5 | import "google/api/annotations.proto"; 6 | import "google/protobuf/empty.proto"; 7 | import "protoc-gen-openapiv2/options/annotations.proto"; 8 | // imports are relative to the module root; in this case our module 9 | // root is set to the `proto` directory. 10 | import "sample/v1/model.proto"; 11 | 12 | // OpenAPI settings. 13 | // https://buf.build/grpc-ecosystem/grpc-gateway/file/main:protoc-gen-openapiv2/options/annotations.proto 14 | // https://buf.build/grpc-ecosystem/grpc-gateway/docs/main:grpc.gateway.protoc_gen_openapiv2.options 15 | option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { 16 | swagger: "2.0" 17 | schemes: HTTP 18 | schemes: HTTPS 19 | schemes: WSS 20 | consumes: "application/json" 21 | consumes: "application/protobuf" 22 | produces: "application/json" 23 | produces: "application/protobuf" 24 | info: { 25 | title: "Bar API" 26 | version: "0.1.0" 27 | contact: { 28 | name: "John Doe" 29 | email: "john.dow@example.com" 30 | } 31 | } 32 | security_definitions: { 33 | security: { 34 | key: "bearer" 35 | value: { 36 | type: TYPE_API_KEY 37 | in: IN_HEADER 38 | name: "Authorization" 39 | description: "Authentication token provided as: 'Bearer {token}'" 40 | } 41 | } 42 | } 43 | security: { 44 | security_requirement: {key: "bearer"} 45 | } 46 | }; 47 | 48 | // Sample "bar" service server. 49 | service BarAPI { 50 | // Reachability test. 51 | rpc Ping(google.protobuf.Empty) returns (Pong) { 52 | option (google.api.http) = {post: "/bar/ping"}; 53 | } 54 | // Health test. 55 | rpc Health(google.protobuf.Empty) returns (HealthResponse) { 56 | option (google.api.http) = {post: "/bar/health"}; 57 | } 58 | // Sample request. 59 | rpc Request(google.protobuf.Empty) returns (Response) { 60 | option (google.api.http) = {post: "/bar/request"}; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /net/http/sample-openapi/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bryk-io/sample-openapi 2 | 3 | go 1.23.4 4 | 5 | toolchain go1.24.2 6 | 7 | require ( 8 | github.com/go-faster/errors v0.7.1 9 | github.com/go-faster/jx v1.1.0 10 | github.com/ogen-go/ogen v1.12.0 11 | go.bryk.io/pkg v0.0.0-20250411182835-130bbccf42ad 12 | go.opentelemetry.io/otel v1.35.0 13 | go.opentelemetry.io/otel/metric v1.35.0 14 | go.opentelemetry.io/otel/trace v1.35.0 15 | ) 16 | 17 | require ( 18 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 19 | github.com/charmbracelet/lipgloss v1.0.0 // indirect 20 | github.com/charmbracelet/log v0.4.1 // indirect 21 | github.com/charmbracelet/x/ansi v0.4.2 // indirect 22 | github.com/dlclark/regexp2 v1.11.5 // indirect 23 | github.com/fatih/color v1.18.0 // indirect 24 | github.com/felixge/httpsnoop v1.0.4 // indirect 25 | github.com/ghodss/yaml v1.0.0 // indirect 26 | github.com/go-faster/yaml v0.4.6 // indirect 27 | github.com/go-logfmt/logfmt v0.6.0 // indirect 28 | github.com/go-logr/logr v1.4.2 // indirect 29 | github.com/go-logr/stdr v1.2.2 // indirect 30 | github.com/google/uuid v1.6.0 // indirect 31 | github.com/gorilla/handlers v1.5.2 // indirect 32 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 33 | github.com/mattn/go-colorable v0.1.13 // indirect 34 | github.com/mattn/go-isatty v0.0.20 // indirect 35 | github.com/muesli/termenv v0.16.0 // indirect 36 | github.com/rivo/uniseg v0.4.7 // indirect 37 | github.com/rs/zerolog v1.34.0 // indirect 38 | github.com/segmentio/asm v1.2.0 // indirect 39 | github.com/sirupsen/logrus v1.9.3 // indirect 40 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect 41 | go.uber.org/multierr v1.11.0 // indirect 42 | go.uber.org/zap v1.27.0 // indirect 43 | golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect 44 | golang.org/x/net v0.39.0 // indirect 45 | golang.org/x/sync v0.13.0 // indirect 46 | golang.org/x/sys v0.32.0 // indirect 47 | golang.org/x/text v0.24.0 // indirect 48 | gopkg.in/yaml.v2 v2.4.0 // indirect 49 | ) 50 | -------------------------------------------------------------------------------- /net/sse/client.go: -------------------------------------------------------------------------------- 1 | package sse 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "fmt" 7 | "net/http" 8 | "sync" 9 | 10 | "go.bryk.io/pkg/errors" 11 | ) 12 | 13 | // Client instances can be used to receive events published by a server 14 | // via subscriptions. A single client can be used to open any number of 15 | // subscriptions. 16 | type Client struct { 17 | hc *http.Client 18 | } 19 | 20 | // NewClient returns a ready-to-use new client instance. If `hc` is nil 21 | // `http.DefaultClient` will be used by default. 22 | func NewClient(hc *http.Client) (*Client, error) { 23 | if hc == nil { 24 | hc = http.DefaultClient 25 | } 26 | return &Client{hc}, nil 27 | } 28 | 29 | // Subscribe opens a new subscription instance for the provided HTTP request. 30 | // The subscription can be closed by the client using the `context` in the 31 | // provided HTTP request. 32 | func (cl *Client) Subscribe(req *http.Request) (*Subscription, error) { 33 | res, err := cl.hc.Do(req) 34 | if err != nil { 35 | return nil, err 36 | } 37 | if res.StatusCode != http.StatusOK { 38 | _ = res.Body.Close() 39 | return nil, errors.Errorf("invalid status received: %s", res.Status) 40 | } 41 | scanner := bufio.NewScanner(res.Body) 42 | scanner.Buffer(make([]byte, 1024), 4096) 43 | scanner.Split(scanForEvents) 44 | ctx, halt := context.WithCancel(req.Context()) 45 | sub := &Subscription{ 46 | ctx: ctx, 47 | halt: halt, 48 | sink: make(chan Event), 49 | wg: new(sync.WaitGroup), 50 | } 51 | go func() { 52 | defer sub.close() 53 | for { 54 | select { 55 | // subscription is closed 56 | case <-sub.Done(): 57 | return 58 | // scan for incoming events 59 | default: 60 | if scanner.Scan() { 61 | sub.wg.Add(1) 62 | sub.sink <- parseEvent(scanner.Bytes()) 63 | sub.wg.Done() 64 | continue 65 | } 66 | if err := scanner.Err(); err != nil { 67 | fmt.Printf("error: %s\b", err) 68 | return 69 | } 70 | return // io.EOF 71 | } 72 | } 73 | }() 74 | return sub, nil 75 | } 76 | -------------------------------------------------------------------------------- /net/http/options.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "fmt" 5 | lib "net/http" 6 | "time" 7 | ) 8 | 9 | // Option allows adjusting server settings following a functional pattern. 10 | type Option func(srv *Server) error 11 | 12 | // WithPort sets the TCP port to handle requests. 13 | func WithPort(port int) Option { 14 | return func(srv *Server) error { 15 | srv.nh.Addr = fmt.Sprintf(":%d", port) 16 | srv.port = port 17 | return nil 18 | } 19 | } 20 | 21 | // WithIdleTimeout sets the maximum amount of time to wait for the 22 | // next request when "keep-alive" is enabled. You can use `0` to 23 | // disable all the server's timeouts. 24 | func WithIdleTimeout(timeout time.Duration) Option { 25 | return func(srv *Server) error { 26 | srv.nh.IdleTimeout = timeout 27 | srv.nh.WriteTimeout = timeout 28 | srv.nh.ReadTimeout = timeout 29 | srv.nh.ReadHeaderTimeout = timeout 30 | return nil 31 | } 32 | } 33 | 34 | // WithHandler sets the HTTP handler used by the server. 35 | func WithHandler(handler lib.Handler) Option { 36 | return func(srv *Server) error { 37 | srv.sh = handler 38 | return nil 39 | } 40 | } 41 | 42 | // WithTLS enable secure communications with server using 43 | // HTTPS connections. 44 | func WithTLS(settings TLS) Option { 45 | return func(srv *Server) error { 46 | var err error 47 | srv.tls, err = settings.Expand() 48 | if err == nil { 49 | srv.nh.TLSConfig = srv.tls 50 | } 51 | return err 52 | } 53 | } 54 | 55 | // WithMiddleware register the provided middleware to customize/extend the 56 | // processing of HTTP requests. When applying middleware the ordering is very 57 | // important, in this case it will be applied in the same order provided. 58 | // For example: 59 | // 60 | // Use(foo bar baz) 61 | // 62 | // Will be applied as: 63 | // 64 | // baz( bar( foo(handler) ) ) 65 | func WithMiddleware(md ...func(lib.Handler) lib.Handler) Option { 66 | return func(srv *Server) error { 67 | srv.mu.Lock() 68 | defer srv.mu.Unlock() 69 | srv.mw = append(srv.mw, md...) 70 | return nil 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /net/csp/options.go: -------------------------------------------------------------------------------- 1 | package csp 2 | 3 | // Option elements provide a functional-style configuration system for 4 | // CSP policies. 5 | type Option func(p *Policy) error 6 | 7 | // WithReportTo provides an endpoint where policy violations will be reported. 8 | // Reports are submitted as JSON objects via POST requests to the provided URI. 9 | // Multiple endpoints can be provided. 10 | func WithReportTo(endpoint ...string) Option { 11 | return func(p *Policy) error { 12 | p.reportTo = append(p.reportTo, endpoint...) 13 | return nil 14 | } 15 | } 16 | 17 | // WithReportOnly will not affect the behavior of existing applications, but 18 | // will still generate violation reports when patterns incompatible with CSP 19 | // are detected, and send them to a reporting endpoint defined in your policy. 20 | func WithReportOnly() Option { 21 | return func(p *Policy) error { 22 | p.reportOnly = true 23 | return nil 24 | } 25 | } 26 | 27 | // UnsafeEval allows the application to use the `eval()` JavaScript function. 28 | // This reduces the protection against certain types of DOM-based XSS bugs, 29 | // but makes it easier to adopt CSP. If your application doesn't use `eval()`, 30 | // you can omit this option and have a safer policy. 31 | func UnsafeEval() Option { 32 | return func(p *Policy) error { 33 | p.allowEval = true 34 | return nil 35 | } 36 | } 37 | 38 | // WithBaseURI restricts the URLs which can be used in a document's 39 | // element. If this value is absent, then any URI is allowed. If this directive 40 | // is absent, the user agent will use the value in the element. 41 | func WithBaseURI(v string) Option { 42 | return func(p *Policy) error { 43 | p.baseURI = v 44 | return nil 45 | } 46 | } 47 | 48 | // WithDefaultSrc serves as a fallback for the other CSP fetch directives. For 49 | // each fetch directive that is absent, the user agent looks for the `default-src` 50 | // directive and use this value for it. 51 | func WithDefaultSrc(v string) Option { 52 | return func(p *Policy) error { 53 | p.defaultSrc = v 54 | return nil 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Public Packages 2 | 3 | [![ci](https://github.com/bryk-io/pkg/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/bryk-io/pkg/actions/workflows/ci.yml) 4 | [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/11326/badge)](https://www.bestpractices.dev/projects/11326) 5 | [![Software License](https://img.shields.io/badge/license-BSD3-red.svg)](LICENSE) 6 | [![Go Report Card](https://goreportcard.com/badge/github.com/bryk-io/pkg?style=flat)](https://goreportcard.com/report/github.com/bryk-io/pkg) 7 | [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0-ff69b4.svg)](.github/CODE_OF_CONDUCT.md) 8 | [![Go Reference](https://pkg.go.dev/badge/go.bryk.io/pkg.svg)](https://pkg.go.dev/go.bryk.io/pkg) 9 | 10 | This repository provides a public collection of development resources and utilities. 11 | 12 | Contents on this package are to be considered under heavy development. This 13 | means interfaces (APIs) may change at any time, sometimes dramatically so. 14 | 15 | ## Cryptography Notice 16 | 17 | This distribution includes cryptographic software. The country in which you currently 18 | reside may have restrictions on the import, possession, use, and/or re-export to another 19 | country, of encryption software. BEFORE using any encryption software, please check your 20 | country's laws, regulations and policies concerning the import, possession, or use, and 21 | re-export of encryption software, to see if this is permitted. 22 | See for more information. 23 | 24 | The U.S. Government Department of Commerce, Bureau of Industry and Security (BIS), has 25 | classified this software as Export Commodity Control Number (ECCN) 5D002.C.1, which 26 | includes information security software using or performing cryptographic functions with 27 | asymmetric algorithms. The form and manner of this distribution makes it eligible for 28 | export under the License Exception ENC Technology Software Unrestricted (TSU) exception 29 | (see the BIS Export Administration Regulations, Section 740.13) for both object code and 30 | source code. 31 | -------------------------------------------------------------------------------- /otel/sdk/setup_test.go: -------------------------------------------------------------------------------- 1 | package sdk 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "testing" 7 | "time" 8 | 9 | tdd "github.com/stretchr/testify/assert" 10 | "go.bryk.io/pkg/log" 11 | "go.bryk.io/pkg/otel" 12 | sdkMetric "go.opentelemetry.io/otel/sdk/metric" 13 | sdkTrace "go.opentelemetry.io/otel/sdk/trace" 14 | ) 15 | 16 | func TestSetup(t *testing.T) { 17 | assert := tdd.New(t) 18 | 19 | // Exporters 20 | var ( 21 | traceExp sdkTrace.SpanExporter 22 | metricExp sdkMetric.Exporter 23 | err error 24 | ) 25 | if isCollectorAvailable() { 26 | traceExp, metricExp, err = ExporterOTLP("localhost:4317", true, nil, "grpc") 27 | } else { 28 | traceExp, metricExp, err = ExporterStdout(true) 29 | } 30 | assert.Nil(err, "failed to create exporter") 31 | 32 | // Application settings 33 | settings := []Option{ 34 | WithServiceName("my-service"), 35 | WithServiceVersion("0.1.0"), 36 | WithSpanLimits(sdkTrace.NewSpanLimits()), 37 | WithSampler(sdkTrace.ParentBased(sdkTrace.TraceIDRatioBased(0.9))), 38 | WithSpanExporter(traceExp), 39 | WithMetricExporter(metricExp), 40 | WithHostMetrics(), 41 | WithRuntimeMetrics(time.Duration(10) * time.Second), 42 | WithResourceAttributes(otel.Attributes{"resource.level.field": "bar"}), 43 | WithBaseLogger(log.WithZero(log.ZeroOptions{ 44 | PrettyPrint: true, 45 | ErrorField: "error.message", 46 | })), 47 | } 48 | 49 | // Setup instrumented application 50 | app, err := Setup(settings...) 51 | assert.Nil(err, "new operator") 52 | app.Flush(context.Background()) 53 | 54 | log := app.Logger() 55 | log.Info("application message") 56 | } 57 | 58 | // Verify a local collector instance is available using its `health check` 59 | // endpoint. 60 | func isCollectorAvailable() bool { 61 | ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 62 | defer cancel() 63 | req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost:13133/", nil) 64 | res, err := http.DefaultClient.Do(req) 65 | if res != nil { 66 | _ = res.Body.Close() 67 | } 68 | if err != nil { 69 | return false 70 | } 71 | return res.StatusCode == http.StatusOK 72 | } 73 | -------------------------------------------------------------------------------- /.github/workflows/maintenance.yml: -------------------------------------------------------------------------------- 1 | name: "maintenance" 2 | permissions: read-all 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" # daily at midnight 6 | jobs: 7 | stale: 8 | name: "close stale issues and pull requests" 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write # for actions/stale to close stale issues 12 | pull-requests: write # for actions/stale to close stale PRs 13 | steps: 14 | # Harden workflow runner 15 | - name: Harden workflow runner (audit all outbound calls) 16 | uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 17 | with: 18 | egress-policy: audit 19 | 20 | - name: Tag stale issues and PRs 21 | uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0 22 | with: 23 | # On the 'debug' mode the action will not perform any operation. 24 | # Add the secret ACTIONS_STEP_DEBUG with a value of 'true' in the repository. 25 | debug-only: false 26 | repo-token: ${{ secrets.GITHUB_TOKEN }} 27 | days-before-stale: 45 28 | days-before-close: 5 29 | stale-issue-label: "stale" 30 | stale-pr-label: "stale" 31 | exempt-issue-labels: "help wanted,awaiting approval,work in progress" 32 | exempt-pr-labels: "help wanted,awaiting approval,work in progress" 33 | stale-issue-message: "This issue has been marked as **stale** because it has not registered any activity during the last 45 days. If the **stale** label is not removed or no activity is registered, this will be automatically closed in 5 days." 34 | close-issue-message: "This issue has been closed automatically after not registering any activity for 50 consecutive days." 35 | stale-pr-message: "This pull request has been marked as **stale** because it has not registered any activity during the last 45 days. If the **stale** label is not removed or no activity is registered, this will be automatically closed in 5 days." 36 | close-pr-message: "This pull request has been closed automatically after not registering any activity for 50 consecutive days." 37 | -------------------------------------------------------------------------------- /net/http/sample-openapi/petstore/oas_request_decoders_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by ogen, DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "io" 7 | "mime" 8 | "net/http" 9 | 10 | "github.com/go-faster/errors" 11 | "github.com/go-faster/jx" 12 | 13 | "github.com/ogen-go/ogen/ogenerrors" 14 | "github.com/ogen-go/ogen/validate" 15 | ) 16 | 17 | func (s *Server) decodeAddPetRequest(r *http.Request) ( 18 | req *Pet, 19 | close func() error, 20 | rerr error, 21 | ) { 22 | var closers []func() error 23 | close = func() error { 24 | var merr error 25 | // Close in reverse order, to match defer behavior. 26 | for i := len(closers) - 1; i >= 0; i-- { 27 | c := closers[i] 28 | merr = errors.Join(merr, c()) 29 | } 30 | return merr 31 | } 32 | defer func() { 33 | if rerr != nil { 34 | rerr = errors.Join(rerr, close()) 35 | } 36 | }() 37 | ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) 38 | if err != nil { 39 | return req, close, errors.Wrap(err, "parse media type") 40 | } 41 | switch { 42 | case ct == "application/json": 43 | if r.ContentLength == 0 { 44 | return req, close, validate.ErrBodyRequired 45 | } 46 | buf, err := io.ReadAll(r.Body) 47 | if err != nil { 48 | return req, close, err 49 | } 50 | 51 | if len(buf) == 0 { 52 | return req, close, validate.ErrBodyRequired 53 | } 54 | 55 | d := jx.DecodeBytes(buf) 56 | 57 | var request Pet 58 | if err := func() error { 59 | if err := request.Decode(d); err != nil { 60 | return err 61 | } 62 | if err := d.Skip(); err != io.EOF { 63 | return errors.New("unexpected trailing data") 64 | } 65 | return nil 66 | }(); err != nil { 67 | err = &ogenerrors.DecodeBodyError{ 68 | ContentType: ct, 69 | Body: buf, 70 | Err: err, 71 | } 72 | return req, close, err 73 | } 74 | if err := func() error { 75 | if err := request.Validate(); err != nil { 76 | return err 77 | } 78 | return nil 79 | }(); err != nil { 80 | return req, close, errors.Wrap(err, "validate") 81 | } 82 | return &request, close, nil 83 | default: 84 | return req, close, validate.InvalidContentType(ct) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Go dependencies 4 | - package-ecosystem: "gomod" 5 | # Where to look for the go.mod file 6 | directory: "/" 7 | # Use '0' to disable the opening of pull requests 8 | open-pull-requests-limit: 5 9 | # Add labels to pull requests 10 | labels: 11 | - "dependencies" 12 | schedule: 13 | # how often to look for updates 14 | interval: "monthly" 15 | # what day to use for opening new requests 16 | day: "monday" 17 | # check for updates at 0hrs UTC 18 | time: "00:00" 19 | # Only manage direct dependencies 20 | allow: 21 | - dependency-type: "direct" 22 | # Ignore specific dependencies 23 | ignore: 24 | # Autogenerated proto files 25 | - dependency-name: "google.golang.org/genproto" 26 | - dependency-name: "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go" 27 | # Currently using our own fork at "github.com/bryk-io/cfssl" 28 | - dependency-name: "github.com/cloudflare/cfssl" 29 | # Avoid constant unstable releases 30 | - dependency-name: "github.com/cockroachdb/pebble" 31 | # Avoid breaking changes with gRPC gateway 32 | - dependency-name: "github.com/grpc-ecosystem/grpc-gateway/v2" 33 | # Avoid breaking changes with gRPC 34 | - dependency-name: "google.golang.org/grpc" 35 | versions: ["v1.x"] 36 | # Avoid breaking changes with unstable OTEL packages 37 | - dependency-name: "go.opentelemetry.io/*" 38 | # Utility only used for testing 39 | - dependency-name: "github.com/stretchr/testify" 40 | # Official Sentry library 41 | - dependency-name: "github.com/getsentry/sentry-go" 42 | # Configure commit messages 43 | commit-message: 44 | # Prefix all commit messages with "dependencies" 45 | prefix: "dependencies" 46 | # Github Actions 47 | - package-ecosystem: "github-actions" 48 | directory: "/" 49 | schedule: 50 | interval: "monthly" 51 | ignore: 52 | - dependency-name: "bufbuild/buf-action" 53 | - dependency-name: "github/codeql-action" 54 | - dependency-name: "trufflesecurity/trufflehog" 55 | -------------------------------------------------------------------------------- /otel/api/span_kind.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | apiTrace "go.opentelemetry.io/otel/trace" 5 | ) 6 | 7 | // SpanKind indicates the nature and/or owner of the traced operation. 8 | type SpanKind string 9 | 10 | const ( 11 | // SpanKindUnspecified is the default value used when no span kind 12 | // is explicitly set. 13 | SpanKindUnspecified SpanKind = "unspecified" 14 | 15 | // SpanKindInternal should be used for internal-only tasks. 16 | SpanKindInternal SpanKind = "internal" 17 | 18 | // SpanKindServer should be used for server-side operations. 19 | SpanKindServer SpanKind = "server" 20 | 21 | // SpanKindClient should be used for client-side operations. 22 | SpanKindClient SpanKind = "client" 23 | 24 | // SpanKindConsumer should be used when an operation starts 25 | // by receiving a message from an MQ broker. 26 | SpanKindConsumer SpanKind = "consumer" 27 | 28 | // SpanKindProducer should be used when an operation involves 29 | // the publishing of a message to an MQ broker. 30 | SpanKindProducer SpanKind = "producer" 31 | ) 32 | 33 | func (sk SpanKind) option() apiTrace.SpanStartOption { 34 | switch sk { 35 | case SpanKindInternal: 36 | return apiTrace.WithSpanKind(apiTrace.SpanKindInternal) 37 | case SpanKindServer: 38 | return apiTrace.WithSpanKind(apiTrace.SpanKindServer) 39 | case SpanKindClient: 40 | return apiTrace.WithSpanKind(apiTrace.SpanKindClient) 41 | case SpanKindConsumer: 42 | return apiTrace.WithSpanKind(apiTrace.SpanKindConsumer) 43 | case SpanKindProducer: 44 | return apiTrace.WithSpanKind(apiTrace.SpanKindProducer) 45 | case SpanKindUnspecified: 46 | return apiTrace.WithSpanKind(apiTrace.SpanKindUnspecified) 47 | default: 48 | return apiTrace.WithSpanKind(apiTrace.SpanKindUnspecified) 49 | } 50 | } 51 | 52 | func (sk SpanKind) String() string { 53 | switch sk { 54 | case SpanKindInternal: 55 | return "internal" 56 | case SpanKindServer: 57 | return "server" 58 | case SpanKindClient: 59 | return "client" 60 | case SpanKindConsumer: 61 | return "consumer" 62 | case SpanKindProducer: 63 | return "producer" 64 | case SpanKindUnspecified: 65 | return "unspecified" 66 | default: 67 | return "unspecified" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /crypto/tred/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package tred provides a reference implementation for the Tamper Resistant Encrypted Data protocol. 3 | 4 | Proper secure data management must support scenarios for in-transit and at-rest use cases. For 5 | network communications (i.e, in-transit) there are already well established and secure protocols 6 | available like TLS. The protocols available for secure data persistence (i.e., at-rest) on the 7 | other hand are not as reliable and/or robust for several reasons. 8 | 9 | TRED introduces a secure, fast and easy-to-use mechanism to handle secure data persistence. The 10 | protocol uses a simple data structure that introduces very small overhead, prevent cipher text 11 | manipulation and greatly simplifies data integrity validation. 12 | 13 | The original data is split into individual packets for optimum security and performance. Each 14 | packet is properly tagged and processed using an authentication encryption cipher. The final 15 | output prevent manipulation (tamper attempts) of the produced cipher text. 16 | 17 | // output: 18 | packet[...] 19 | 20 | // packet: 21 | // tag is calculated and validated by the AEAD cipher 22 | header (16) | payload (1 byte - 64 KB) | tag (16) 23 | 24 | // header: 25 | version (1) | cipher (1) | payload length (2) | seq (4) | nonce (8) 26 | 27 | # Usage 28 | 29 | To facilitate the integration of the protocol with higher level components and primitives this 30 | package introduces a 'Worker' component with a simple interface. 31 | 32 | content := make([]byte, 1024*256) 33 | rand.Read(content) 34 | 35 | // Create a worker instance using the ChaCha20 cipher 36 | conf, _ := DefaultConfig([]byte("super-secret-key")) 37 | conf.Cipher = CHACHA20 38 | w, _ := NewWorker(conf) 39 | 40 | // Encrypt data 41 | secure := bytes.NewBuffer([]byte{}) 42 | _, _ = w.Encrypt(bytes.NewReader(content), secure) 43 | if bytes.Equal(content, secure.Bytes()) { 44 | panic("failed to encrypt original content") 45 | } 46 | 47 | // Decrypt data 48 | verification := bytes.NewBuffer([]byte{}) 49 | _, _ = w.Decrypt(secure, verification) 50 | if !bytes.Equal(content, verification.Bytes()) { 51 | panic("failed to decrypt data") 52 | } 53 | */ 54 | package tred 55 | -------------------------------------------------------------------------------- /net/drpc/client_options.go: -------------------------------------------------------------------------------- 1 | package drpc 2 | 3 | import ( 4 | "go.bryk.io/pkg/errors" 5 | clmw "go.bryk.io/pkg/net/drpc/middleware/client" 6 | ) 7 | 8 | // ClientOption allows adjusting client settings following a functional pattern. 9 | type ClientOption func(cl *Client) error 10 | 11 | // WithClientTLS adjust the client to establish a secure communication channel 12 | // with the server. 13 | func WithClientTLS(opts ClientTLS) ClientOption { 14 | return func(cl *Client) error { 15 | tc, err := opts.conf() 16 | if err != nil { 17 | return err 18 | } 19 | cl.tls = tc 20 | return nil 21 | } 22 | } 23 | 24 | // WithAuthCertificate enabled certificate-based client authentication with the 25 | // provided credentials. This requires the client and the server to use a TLS 26 | // communication channel, otherwise this option will be ignored. 27 | func WithAuthCertificate(cert, key []byte) ClientOption { 28 | return func(c *Client) error { 29 | ct, err := LoadCertificate(cert, key) 30 | if err != nil { 31 | return errors.WithStack(err) 32 | } 33 | c.cert = &ct 34 | return nil 35 | } 36 | } 37 | 38 | // WithProtocolHeader ensure the client connections include the protocol selection 39 | // header. This is required when the server supports both DRPC and HTTP requests. 40 | func WithProtocolHeader() ClientOption { 41 | return func(cl *Client) error { 42 | cl.http = true 43 | return nil 44 | } 45 | } 46 | 47 | // WithPoolCapacity adjust the max limit of concurrent DRPC connections a single 48 | // client instance can support. 49 | func WithPoolCapacity(limit int) ClientOption { 50 | return func(cl *Client) error { 51 | cl.capacity = limit 52 | return nil 53 | } 54 | } 55 | 56 | // WithClientMiddleware register the provided middleware to customize/extend 57 | // the processing of RPC requests. When providing middleware the ordering is very 58 | // important; middleware will be applied in the same order provided. 59 | // 60 | // For example: 61 | // Use(foo bar baz) 62 | // Will be applied as: 63 | // baz( bar( foo(handler) ) ) 64 | func WithClientMiddleware(mw ...clmw.Middleware) ClientOption { 65 | return func(cl *Client) error { 66 | cl.Use(mw...) 67 | return nil 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /cli/shell/command.go: -------------------------------------------------------------------------------- 1 | package shell 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | "strings" 7 | 8 | "github.com/chzyer/readline" 9 | ) 10 | 11 | // Command provides a mechanism to add functionality to a shell instance. 12 | type Command struct { 13 | // Short name for the command. 14 | Name string 15 | 16 | // Brief but clear description about the command purpose. 17 | Description string 18 | 19 | // Information about how to use the command. 20 | Usage string 21 | 22 | // Method to execute when the command is invoked. 23 | Run func(arg string) string 24 | 25 | // Sub-commands available, if any. 26 | SubCommands []*Command 27 | } 28 | 29 | // Build the proper auto-completer entries. It will handle nested elements as needed. 30 | func (c *Command) getPCI() readline.PrefixCompleterInterface { 31 | var items []readline.PrefixCompleterInterface 32 | if c.SubCommands != nil { 33 | // Sort command entries by name 34 | sort.Slice(c.SubCommands, func(i, j int) bool { 35 | return c.SubCommands[i].Name < c.SubCommands[j].Name 36 | }) 37 | 38 | for _, cc := range c.SubCommands { 39 | items = append(items, cc.getPCI()) 40 | } 41 | } 42 | return readline.PcItem(c.Name, items...) 43 | } 44 | 45 | // Match an incoming user line with a command branch. 46 | func (c *Command) match(line string, sh *Instance) (bool, string) { 47 | // Not a match 48 | if strings.SplitN(line, " ", 2)[0] != c.Name { 49 | return false, "" 50 | } 51 | 52 | line = strings.TrimSpace(strings.Replace(line, c.Name, "", 1)) 53 | if c.SubCommands != nil { 54 | for _, cc := range c.SubCommands { 55 | if ok, res := cc.match(line, sh); ok { 56 | return true, res 57 | } 58 | } 59 | } 60 | 61 | // Display help if required 62 | if sh.shouldShowHelp(line) || c.Run == nil { 63 | if len(c.SubCommands) > 0 { 64 | sh.help(c.SubCommands) 65 | return true, "" 66 | } 67 | return true, c.help() 68 | } 69 | 70 | // Execute command function 71 | return true, c.Run(line) 72 | } 73 | 74 | // Return the help information for a command instance. 75 | func (c *Command) help() string { 76 | res := c.Description 77 | if c.Usage != "" { 78 | res += fmt.Sprintf("\nUsage: %s\n", c.Usage) 79 | } 80 | return res 81 | } 82 | -------------------------------------------------------------------------------- /crypto/pow/main_test.go: -------------------------------------------------------------------------------- 1 | package pow 2 | 3 | import ( 4 | "context" 5 | "crypto/sha256" 6 | "fmt" 7 | "log" 8 | "math/rand" 9 | "testing" 10 | "time" 11 | 12 | tdd "github.com/stretchr/testify/assert" 13 | "go.bryk.io/pkg/errors" 14 | "go.uber.org/goleak" 15 | ) 16 | 17 | type src struct { 18 | nonce int64 19 | value []byte 20 | } 21 | 22 | func (s *src) Nonce() int64 { 23 | return s.nonce 24 | } 25 | 26 | func (s *src) ResetNonce() { 27 | s.nonce = 0 28 | } 29 | 30 | func (s *src) IncrementNonce() { 31 | s.nonce++ 32 | } 33 | 34 | func (s *src) MarshalBinary() ([]byte, error) { 35 | if rand.Intn(1000) == 777 { 36 | return nil, errors.New("simulated random encoding error") // jackpot 37 | } 38 | return append(s.value, []byte(fmt.Sprintf("%d", s.nonce))...), nil 39 | } 40 | 41 | func TestSolve(t *testing.T) { 42 | assert := tdd.New(t) 43 | defer goleak.VerifyNone(t) 44 | rec := &src{value: []byte("this is the value")} 45 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 46 | defer cancel() 47 | 48 | r1 := Solve(ctx, rec, sha256.New(), 16) 49 | log.Printf("hash found: %s", <-r1) 50 | log.Printf("total attempts: %d", rec.Nonce()) 51 | assert.True(Verify(rec, sha256.New(), 12), "verification error") 52 | assert.True(Verify(rec, sha256.New(), 16), "verification error") 53 | 54 | r2 := Solve(ctx, rec, sha256.New(), 28) 55 | val, ok := <-r2 56 | if ok || val != "" { 57 | log.Printf("hash found: %s", val) 58 | } else { 59 | log.Printf("round 2 terminated via timeout =/") 60 | } 61 | } 62 | 63 | // Run a protocol round to find a solution to a PoW challenge. 64 | func ExampleSolve() { 65 | // Create a context with a maximum timeout of 10 seconds 66 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 67 | defer cancel() 68 | 69 | // Set the source for the round 70 | src := &src{} 71 | 72 | // Start the PoW round and wait for the result 73 | res := Solve(ctx, src, sha256.New(), 16) 74 | fmt.Printf("solution found: %x", <-res) 75 | } 76 | 77 | // Verify an already produced solution to a PoW challenge. 78 | func ExampleVerify() { 79 | // The source element to verify 80 | solved := &src{} 81 | fmt.Printf("source verification result: %v", Verify(solved, sha256.New(), 12)) 82 | } 83 | -------------------------------------------------------------------------------- /net/sse/http.go: -------------------------------------------------------------------------------- 1 | package sse 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | ) 7 | 8 | // Handler provides a basic "Server-Send Events" handler implementation. The 9 | // provided `setup` function allows to flexibly create streams and/or subscriptions 10 | // based on the HTTP request contents, e.g., credentials, headers, query, etc. 11 | // - SSE requires no timeouts on "keep-alive" connections on the server side. 12 | // - If the subscription is closed by the server, the client connection will be 13 | // closed as well. 14 | // - If the client connection drops, the subscription will be closed on the 15 | // server as well. 16 | func Handler(setup func(req *http.Request) *Subscription) http.HandlerFunc { 17 | return func(res http.ResponseWriter, req *http.Request) { 18 | rf, ok := res.(http.Flusher) 19 | if !ok { 20 | http.Error(res, "SSE is not supported", http.StatusInternalServerError) 21 | return 22 | } 23 | 24 | // Set required standard headers 25 | res.Header().Set("Content-Type", "text/event-stream") 26 | res.Header().Set("Cache-Control", "no-cache") 27 | res.Header().Set("Connection", "keep-alive") 28 | 29 | // Prepare subscription handler 30 | sub := setup(req) 31 | for { 32 | select { 33 | // send stream event(s) 34 | case ev := <-sub.Receive(): 35 | data, err := ev.Encode() 36 | if err == nil { 37 | _, _ = res.Write(data) 38 | rf.Flush() 39 | } 40 | // when subscription is 'done', close client connection 41 | case <-sub.Done(): 42 | return 43 | } 44 | } 45 | } 46 | } 47 | 48 | // PrepareRequest returns an HTTP request configured to receive an incoming 49 | // stream of SSE events from the provided `url` endpoint. 50 | func PrepareRequest(ctx context.Context, url string, headers map[string]string) (*http.Request, error) { 51 | req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | // Set required standard headers 57 | req.Header.Set("Content-Type", "text/event-stream") 58 | req.Header.Set("Cache-Control", "no-cache") 59 | req.Header.Set("Connection", "keep-alive") 60 | 61 | // Attach extra headers 62 | for k, v := range headers { 63 | req.Header.Set(k, v) 64 | } 65 | return req, nil 66 | } 67 | -------------------------------------------------------------------------------- /amqp/publisher_test.go: -------------------------------------------------------------------------------- 1 | package amqp 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "time" 7 | ) 8 | 9 | var publisher *Publisher 10 | 11 | func ExampleNewPublisher() { 12 | // Create a new publisher instance 13 | publisher, err := NewPublisher("amqp://guest:guest@localhost:5672") 14 | if err != nil { 15 | panic(err) 16 | } 17 | 18 | // Wait for the publisher to be ready 19 | <-publisher.Ready() 20 | 21 | // Send a sample message 22 | msg := Message{ 23 | Body: []byte("hello world"), 24 | ContentType: "text/plain", 25 | } 26 | err = publisher.UnsafePush(msg, MessageOptions{Exchange: "my-exchange"}) 27 | if err != nil { 28 | log.Printf("push error: %s", err) 29 | } 30 | 31 | // When no longer needed, close the publisher 32 | if err = publisher.Close(); err != nil { 33 | panic(err) 34 | } 35 | } 36 | 37 | func ExamplePublisher_AddExchange() { 38 | // Create and add definition for the new exchange 39 | newExchange := Exchange{ 40 | Name: "custom_notifications", 41 | Kind: "fanout", 42 | Durable: true, 43 | AutoDelete: false, 44 | } 45 | if err := publisher.AddExchange(newExchange); err != nil { 46 | panic(err) 47 | } 48 | } 49 | 50 | func ExamplePublisher_GetDispatcher() { 51 | // All messages send using the dispatcher instance will use 52 | // the options provided. 53 | opts := MessageOptions{ 54 | Exchange: "jobs", 55 | RoutingKey: "zone=us-west", 56 | Persistent: true, 57 | Immediate: true, 58 | Mandatory: true, 59 | } 60 | 61 | // A context instance allows to manually close the dispatcher 62 | // when no longer needed 63 | ctx, cancel := context.WithCancel(context.Background()) 64 | 65 | // Create new dispatcher 66 | importantJobs := publisher.GetDispatcher(ctx, true, opts) 67 | go func() { 68 | ticker := time.NewTicker(1 * time.Second) 69 | defer ticker.Stop() 70 | for { 71 | select { 72 | case <-ticker.C: 73 | importantJobs.Publish() <- Message{Body: []byte(time.Now().String())} 74 | case err := <-importantJobs.Errors(): 75 | log.Printf("error: %s", err) 76 | case <-importantJobs.Done(): 77 | log.Printf("dispatcher is closed") 78 | return 79 | } 80 | } 81 | }() 82 | 83 | // Wait for a bit 84 | <-time.After(10 * time.Second) 85 | cancel() 86 | } 87 | -------------------------------------------------------------------------------- /amqp/consumer_test.go: -------------------------------------------------------------------------------- 1 | package amqp 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | var consumer *Consumer 8 | 9 | func doStuff(_ Delivery) {} 10 | 11 | func ExampleNewConsumer() { 12 | // Create a new consumer instance 13 | consumer, err := NewConsumer("amqp://guest:guest@localhost:5672") 14 | if err != nil { 15 | panic(err) 16 | } 17 | 18 | // Wait for the consumer to be ready 19 | <-consumer.Ready() 20 | 21 | // Open a subscription and start working with events 22 | tasksToHandle, id, err := consumer.Subscribe(SubscribeOptions{Queue: "jobs"}) 23 | if err != nil { 24 | panic(err) 25 | } 26 | log.Printf("subscription open: %s", id) 27 | 28 | // Handle all events received, sending an ACK message back to the 29 | // broker once the task has been successfully completed to prevent 30 | // requeue and resending. 31 | for msg := range tasksToHandle { 32 | doStuff(msg) 33 | if err := msg.Ack(false); err != nil { 34 | log.Printf("failed to process message: %s", err) 35 | } 36 | } 37 | 38 | // When no longer needed, close the consumer instance 39 | if err = consumer.Close(); err != nil { 40 | panic(err) 41 | } 42 | } 43 | 44 | func ExampleConsumer_AddBinding() { 45 | err := consumer.AddBinding(Binding{ 46 | Exchange: "topic_exchange", 47 | Queue: "my_tasks", 48 | RoutingKey: []string{ 49 | "tasks.zone.us.#", 50 | "tasks.zone.eu.#", 51 | }, 52 | }) 53 | if err != nil { 54 | panic(err) 55 | } 56 | } 57 | 58 | func ExampleConsumer_AddQueue() { 59 | _, err := consumer.AddQueue(Queue{ 60 | Name: "my_temporal_and_exclusive_queue", 61 | AutoDelete: true, 62 | Exclusive: true, 63 | Durable: false, 64 | }) 65 | if err != nil { 66 | panic(err) 67 | } 68 | } 69 | 70 | func ExampleConsumer_Subscribe() { 71 | // Open subscription 72 | deliveries, id, err := consumer.Subscribe(SubscribeOptions{ 73 | Queue: "my_tasks", 74 | AutoAck: true, 75 | }) 76 | if err != nil { 77 | panic(err) 78 | } 79 | 80 | // Handle tasks, no need to manually send ACK because "AutoAck" 81 | // is set to "true" 82 | for task := range deliveries { 83 | doStuff(task) 84 | } 85 | 86 | // Close subscription when no longer need 87 | // but keep consumer connection 88 | err = consumer.CloseSubscription(id) 89 | if err != nil { 90 | panic(err) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /cli/konf/options.go: -------------------------------------------------------------------------------- 1 | package konf 2 | 3 | import ( 4 | "flag" 5 | "strings" 6 | 7 | "github.com/spf13/pflag" 8 | ) 9 | 10 | type settings struct { 11 | locations []string 12 | env bool 13 | envPrefix string 14 | tagName string 15 | flags *flag.FlagSet 16 | pflags *pflag.FlagSet 17 | } 18 | 19 | // Option instances adjust the behavior of a configuration provider. 20 | type Option func(*settings) error 21 | 22 | // WithFileLocations adjust the configuration provider to attempt to load a configuration 23 | // file form the local filesystem. The first valid configuration file found will be the one 24 | // used. 25 | func WithFileLocations(locations []string) Option { 26 | return func(s *settings) error { 27 | s.locations = locations 28 | return nil 29 | } 30 | } 31 | 32 | // WithFlags loads configuration values coming from "command-line" flags. 33 | func WithFlags(set *flag.FlagSet) Option { 34 | return func(s *settings) error { 35 | s.flags = set 36 | return nil 37 | } 38 | } 39 | 40 | // WithPflags loads configuration values coming from "command-line" flags using 41 | // the `github.com/spf13/pflag` package. 42 | func WithPflags(set *pflag.FlagSet) Option { 43 | return func(s *settings) error { 44 | s.pflags = set 45 | return nil 46 | } 47 | } 48 | 49 | // WithTagName adjust the tag identifier is used when decoding configuration into structs. 50 | // For example, with the tag name `konf`, it would look for `konf` tags on struct fields. 51 | // If no value is provided a sane default will be used depending on the configuration 52 | // file extension. 53 | func WithTagName(name string) Option { 54 | return func(s *settings) error { 55 | s.tagName = name 56 | return nil 57 | } 58 | } 59 | 60 | // WithEnv adjust the configuration provider to load values from 61 | // ENV variables. If a `prefix` is provided only ENV variables 62 | // with it will be evaluated. The provided `prefix` value will be 63 | // automatically formatted, for example: `myapp` will be evaluated 64 | // as `MYAPP_`. 65 | func WithEnv(prefix string) Option { 66 | return func(s *settings) error { 67 | prefix = strings.ToUpper(prefix) 68 | if !strings.HasSuffix(prefix, "_") { 69 | prefix = prefix + "_" 70 | } 71 | 72 | s.env = true 73 | s.envPrefix = prefix 74 | return nil 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /jose/jwk/key_test.go: -------------------------------------------------------------------------------- 1 | package jwk 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/json" 6 | "fmt" 7 | "strings" 8 | "testing" 9 | 10 | tdd "github.com/stretchr/testify/assert" 11 | "go.bryk.io/pkg/jose/jwa" 12 | ) 13 | 14 | func TestNewKey(t *testing.T) { 15 | assert := tdd.New(t) 16 | 17 | for _, alg := range standardMethods { 18 | if alg == string(jwa.NONE) { 19 | continue 20 | } 21 | k, err := New(jwa.Alg(alg)) 22 | assert.Nil(err, "failed to create key") 23 | k.SetID(sampleID()) 24 | assert.Equal(jwa.Alg(alg), k.Alg(), "wrong 'alg'") 25 | 26 | // Marshal 27 | _, err = k.MarshalBinary() 28 | assert.Nil(err, "marshal") 29 | 30 | // Print thumbprint 31 | tp, err := k.Thumbprint() 32 | assert.Nil(err) 33 | t.Logf("thumbprint: %s", tp) 34 | 35 | // Produce signature 36 | hm, _ := jwa.Alg(alg).HashFunction() 37 | msg := []byte("original message to sign") 38 | sig, err := k.Sign(rand.Reader, msg, hm) 39 | assert.Nil(err, "sign error") 40 | 41 | // Export and import full key 42 | rec := k.Export(false) 43 | js, _ := json.Marshal(rec) 44 | t.Logf("%s\n", js) 45 | k2, err := Import(rec) 46 | assert.Nil(err, "import") 47 | assert.True(k2.Verify(hm, msg, sig), "bad verify result") 48 | 49 | // HMAC keys are symmetric; there's no "pub-only" version available 50 | if strings.HasPrefix(alg, "HS") { 51 | continue 52 | } 53 | 54 | // Import only pub key 55 | onlyPub, err := Import(k.Export(true)) 56 | assert.Nil(err, "import") 57 | assert.NotNil(onlyPub.Public(), "retrieve public key") 58 | assert.True(onlyPub.Verify(hm, msg, sig), "bad verify result") 59 | _, err = onlyPub.Sign(rand.Reader, msg, hm) 60 | assert.NotNil(err, "sign should fail") 61 | } 62 | } 63 | 64 | func sampleID() string { 65 | seed := make([]byte, 4) 66 | _, _ = rand.Read(seed) 67 | return fmt.Sprintf("%X-%X", seed[:2], seed[2:]) 68 | } 69 | 70 | // https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1 71 | var standardMethods = []string{ 72 | string(jwa.NONE), 73 | string(jwa.HS256), 74 | string(jwa.HS384), 75 | string(jwa.HS512), 76 | string(jwa.RS256), 77 | string(jwa.RS384), 78 | string(jwa.RS512), 79 | string(jwa.ES256), 80 | string(jwa.ES384), 81 | string(jwa.ES512), 82 | string(jwa.PS256), 83 | string(jwa.PS384), 84 | string(jwa.PS512), 85 | } 86 | -------------------------------------------------------------------------------- /net/middleware/metadata/handler.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "strings" 7 | 8 | "google.golang.org/grpc/metadata" 9 | ) 10 | 11 | // Options available to adjust the behavior of the metadata middleware. 12 | type Options struct { 13 | // The headers must be specified in its lowercase (non-canonical) form. 14 | // If no specific headers are provided, all headers in the request are 15 | // registered as metadata by default. 16 | Headers []string `json:"headers" yaml:"headers" mapstructure:"headers"` 17 | 18 | // Provides complete flexibility to adjust the metadata produced for a 19 | // received request. 20 | Hook func(md *MD, r http.Request) `json:"-" yaml:"-" mapstructure:"-"` 21 | } 22 | 23 | // Handler allows keeping HTTP headers or other request details as 24 | // metadata in the context used when processing incoming requests. This 25 | // allows other extensions and resolvers to have access to required information. 26 | // 27 | // Upstream elements can retrieve available metadata with: 28 | // 29 | // md, ok := FromContext(ctx) 30 | func Handler(options Options) func(http.Handler) http.Handler { 31 | return func(h http.Handler) http.Handler { 32 | fn := func(w http.ResponseWriter, r *http.Request) { 33 | md := MD{} 34 | for hk, hv := range r.Header { 35 | if len(options.Headers) == 0 || contains(hk, options.Headers) { 36 | md.Set(hk, hv...) 37 | } 38 | } 39 | if options.Hook != nil { 40 | options.Hook(&md, *r) 41 | } 42 | ctx := metadata.NewIncomingContext(r.Context(), md) 43 | h.ServeHTTP(w, r.WithContext(ctx)) 44 | } 45 | return http.HandlerFunc(fn) 46 | } 47 | } 48 | 49 | // MD provides a simple mechanism to propagate custom values 50 | // through the context instance used while processing operations. 51 | // Based on the gRPC implementation. 52 | type MD = metadata.MD 53 | 54 | // FromContext retrieves metadata information from the provided 55 | // context if available. 56 | func FromContext(ctx context.Context) (MD, bool) { 57 | return metadata.FromIncomingContext(ctx) 58 | } 59 | 60 | // Helper method to look for specific key in the provided list. 61 | func contains(needle string, haystack []string) bool { 62 | for _, k := range haystack { 63 | if strings.EqualFold(k, needle) { 64 | return true 65 | } 66 | } 67 | return false 68 | } 69 | -------------------------------------------------------------------------------- /amqp/dispatcher.go: -------------------------------------------------------------------------------- 1 | package amqp 2 | 3 | import ( 4 | "context" 5 | "time" 6 | ) 7 | 8 | // Dispatcher instances simplify the process of sending messages to 9 | // a broker server through an underlying publisher instance. 10 | type Dispatcher struct { 11 | name string // dispatcher identifier 12 | safe bool // whether to use 'safe' message push or not 13 | opts MessageOptions // message delivery options 14 | done chan struct{} // signals when the dispatcher is closed 15 | msgCh chan Message // publish message sink 16 | errCh chan error // error notifications receiver 17 | parent *Publisher // publisher instance used to create the dispatcher 18 | ctx context.Context 19 | } 20 | 21 | // Errors returned by publish operations. 22 | func (dp *Dispatcher) Errors() <-chan error { 23 | return dp.errCh 24 | } 25 | 26 | // Publish a new message based on the dispatcher options. 27 | func (dp *Dispatcher) Publish() chan<- Message { 28 | return dp.msgCh 29 | } 30 | 31 | // Done notify users when the dispatcher instance is closing. 32 | func (dp *Dispatcher) Done() <-chan struct{} { 33 | return dp.done 34 | } 35 | 36 | // Internal event processing. 37 | func (dp *Dispatcher) eventLoop() { 38 | defer func() { 39 | dp.parent.log.WithField("id", dp.name).Debug("closing dispatcher") 40 | close(dp.done) 41 | }() 42 | dp.parent.log.WithField("id", dp.name).Debug("starting new dispatcher") 43 | for { 44 | select { 45 | // Publisher is closing. 46 | case <-dp.parent.ctx.Done(): 47 | return 48 | // User closed dispatcher manually. 49 | case <-dp.ctx.Done(): 50 | return 51 | // Handle message delivery. 52 | case msg, ok := <-dp.msgCh: 53 | // Drop channel was closed 54 | if !ok { 55 | return 56 | } 57 | 58 | // Publish message 59 | var err error 60 | if dp.safe { 61 | _, err = dp.parent.Push(msg, dp.opts) 62 | } else { 63 | err = dp.parent.UnsafePush(msg, dp.opts) 64 | } 65 | 66 | // Deliver error notification in the background 67 | if err != nil { 68 | go func() { 69 | select { 70 | case dp.errCh <- err: 71 | return 72 | case <-dp.parent.ctx.Done(): 73 | return 74 | case <-dp.ctx.Done(): 75 | return 76 | case <-time.After(ackDelay): 77 | return 78 | } 79 | }() 80 | } 81 | } 82 | } 83 | } 84 | --------------------------------------------------------------------------------