From 56c57957c813eeb07396608dbf0299ae22882f07 Mon Sep 17 00:00:00 2001 From: Foudre Date: Tue, 29 Apr 2025 23:40:33 +0200 Subject: [PATCH] v1.0.1 probe --- probe/Makefile | 18 +++++++ probe/cmd/obsero-probe/main.go | 29 ++++++++-- probe/pkg/proof/format.go | 49 +++++++++++++++++ probe/readme.md | 98 +++++++++++++++++++++------------- 4 files changed, 152 insertions(+), 42 deletions(-) create mode 100644 probe/Makefile diff --git a/probe/Makefile b/probe/Makefile new file mode 100644 index 0000000..030606e --- /dev/null +++ b/probe/Makefile @@ -0,0 +1,18 @@ +BINARY_NAME=obsero-probe + +all: build + +build: + go build -o $(BINARY_NAME) ./cmd/obsero-probe + +build-linux: + GOOS=linux GOARCH=amd64 go build -o $(BINARY_NAME)-linux ./cmd/obsero-probe + +build-mac: + GOOS=darwin GOARCH=amd64 go build -o $(BINARY_NAME)-mac ./cmd/obsero-probe + +build-arm: + GOOS=linux GOARCH=arm64 go build -o $(BINARY_NAME)-arm64 ./cmd/obsero-probe + +clean: + rm -f $(BINARY_NAME)* diff --git a/probe/cmd/obsero-probe/main.go b/probe/cmd/obsero-probe/main.go index 6d37a8f..57f6eef 100644 --- a/probe/cmd/obsero-probe/main.go +++ b/probe/cmd/obsero-probe/main.go @@ -1,20 +1,41 @@ package main import ( + "flag" "fmt" "os" + "git.cryptolab.re/foudre/whitepaper_obsero/pkg/geo" "git.cryptolab.re/foudre/whitepaper_obsero/pkg/probe" "git.cryptolab.re/foudre/whitepaper_obsero/pkg/proof" ) func main() { - target := "https://example.com" + target := flag.String("target", "https://example.com", "Target URL to probe") + output := flag.String("output", "proof_http_signed.json", "Output file name for proof JSON") + useIPFS := flag.Bool("ipfs", false, "Upload to IPFS after proof generation") + + flag.Parse() location := geo.GetGeoLocation() - result := probe.HttpPing(target) + result := probe.HttpPing(*target) observation := proof.BuildProof(result, location) - proof.SaveProof(observation, "proof_http_result.json") - fmt.Println("✅ Proof generated and saved.") + err := proof.SignProof(&observation) + if err != nil { + fmt.Println("❌ Failed to sign proof:", err) + os.Exit(1) + } + + proof.SaveProof(observation, *output) + fmt.Println("✅ Signed proof saved to", *output) + + if *useIPFS { + cid, err := proof.UploadToIPFS(*output) + if err != nil { + fmt.Println("❌ Failed to upload to IPFS:", err) + } else { + fmt.Println("📡 Uploaded to IPFS with CID:", cid) + } + } } diff --git a/probe/pkg/proof/format.go b/probe/pkg/proof/format.go index 880d7da..13c18d4 100644 --- a/probe/pkg/proof/format.go +++ b/probe/pkg/proof/format.go @@ -1,13 +1,34 @@ package proof import ( + "crypto/ecdsa" + "crypto/sha256" + "encoding/hex" "encoding/json" + "fmt" "os" + "github.com/ethereum/go-ethereum/crypto" "git.cryptolab.re/foudre/whitepaper_obsero/pkg/geo" "git.cryptolab.re/foudre/whitepaper_obsero/pkg/probe" +import ( + ... + shell "github.com/ipfs/go-ipfs-api" + ... ) +... + +func UploadToIPFS(filepath string) (string, error) { + sh := shell.NewShell("localhost:5001") + cid, err := sh.AddNoPin(shell.NewShellFile(filepath)) + if err != nil { + return "", err + } + return cid, nil +} + + type Observation struct { Timestamp string `json:"timestamp"` Target string `json:"target"` @@ -17,6 +38,7 @@ type Observation struct { Error string `json:"error_message"` Observer ObserverInfo `json:"observer"` Version string `json:"version"` + Proof ProofMeta `json:"proof"` } type ObserverInfo struct { @@ -27,6 +49,11 @@ type ObserverInfo struct { ProbeVersion string `json:"probe_version"` } +type ProofMeta struct { + Hash string `json:"hash"` + Signature string `json:"signature"` +} + func BuildProof(result probe.PingResult, loc geo.GeoInfo) Observation { return Observation{ Timestamp: result.Timestamp, @@ -50,3 +77,25 @@ func SaveProof(obs Observation, filename string) { file, _ := json.MarshalIndent(obs, "", " ") _ = os.WriteFile(filename, file, 0644) } + +func SignProof(obs *Observation) error { + // Replace with your own private key (for demo only) + privKeyHex := "4f3edf983ac636a65a842ce7c78d9aa706d3b113bce03738e0f7b6267d5bdc25" + privKey, err := crypto.HexToECDSA(privKeyHex) + if err != nil { + return err + } + + // Hash relevant fields + data := fmt.Sprintf("%s|%s|%s|%d|%d", obs.Timestamp, obs.Target, obs.Status, obs.HTTPStatus, obs.LatencyMs) + hash := sha256.Sum256([]byte(data)) + obs.Proof.Hash = hex.EncodeToString(hash[:]) + + sigBytes, err := crypto.Sign(hash[:], privKey) + if err != nil { + return err + } + + obs.Proof.Signature = hex.EncodeToString(sigBytes) + return nil +} diff --git a/probe/readme.md b/probe/readme.md index 04ab4bc..fb7f7c0 100644 --- a/probe/readme.md +++ b/probe/readme.md @@ -1,48 +1,57 @@ -# 🛰️ Obsero Probe +# 🛰️ Obsero Probe (Full) -Lightweight monitoring agent for generating Proof-of-Observability JSON files. +Obsero Probe is a lightweight Go-based agent that generates cryptographically signed uptime proofs and can optionally upload them to IPFS. -This probe performs HTTP health checks, automatically geolocates itself, and exports signed observation files compliant with the Obsero specification. +--- + +## 🚀 Features + +- HTTP ping with latency measurement +- Automatic geolocation of probe (city, region, country) +- SHA256 hashing of observation data +- EVM-compatible signature using Ethereum private key +- IPFS upload support (`--ipfs`) +- CLI support for target, output, and IPFS toggle +- Cross-platform Makefile for easy builds --- ## ⚙️ Requirements - Go 1.21+ -- Internet access (for geo lookup and ping) +- Local IPFS node (optional, for `--ipfs`) +- Ethereum private key (test key included by default) --- -## 🚀 Quick Start +## 📦 Quick Start -### 1. Clone & Enter +### 1. Install dependencies ```bash cd probe -``` - -### 2. Install dependencies - -```bash go mod tidy ``` -### 3. Run the probe +### 2. Run a probe ```bash -go run ./cmd/obsero-probe +go run ./cmd/obsero-probe --target https://example.com --output proof_http_signed.json --ipfs ``` -This will: -- Ping `https://example.com` -- Auto-detect country, city and region -- Output a file named `proof_http_result.json` - --- -## 📄 Output Format +## 🛠️ CLI Options -The output file is a valid Obsero proof: +| Flag | Description | +|------------|------------------------------------| +| `--target` | URL to ping | +| `--output` | Output file name | +| `--ipfs` | Upload the proof to IPFS | + +--- + +## 📄 Proof Format (simplified) ```json { @@ -59,34 +68,47 @@ The output file is a valid Obsero proof: "city": "Paris", "probe_version": "0.1" }, - "version": "0.1" + "version": "0.1", + "proof": { + "hash": "ab13...cdef", + "signature": "0x..." + } } ``` --- -## 📦 Next steps - -- Add CLI support (`--target`, `--output`) -- Add cryptographic signature of the proof -- Upload to IPFS -- Submit hash + CID on Base chain - ---- - -## 📁 Structure +## 📁 Project Structure ``` probe/ ├── cmd/ -│ └── obsero-probe/ -│ └── main.go # CLI entrypoint +│ └── obsero-probe/main.go # CLI entrypoint ├── pkg/ -│ ├── geo/ # IP geolocation -│ ├── probe/ # HTTP ping logic -│ └── proof/ # Proof struct + output -├── go.mod -├── go.sum +│ ├── geo/geo.go # Geolocation +│ ├── probe/ping.go # HTTP ping +│ └── proof/format.go # Build, sign and upload proof +├── Makefile # Multi-platform build support +├── go.mod / go.sum +``` + +--- + +## 🧱 Next Steps + +- ✅ JSON signed and stored locally +- ✅ Upload to IPFS (`--ipfs`) +- 🔗 Submit `submitProof(hash, cid, timestamp)` to a smart contract on Base chain (coming soon) + +--- + +## 🛠️ Makefile Usage + +```bash +make build # Build for local platform +make build-linux # Build for Linux amd64 +make build-mac # Build for macOS +make build-arm # Build for ARM64 (Raspberry Pi, etc.) ``` ---