Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a9741cf
feat: add geo-resto package
recule556688 Oct 21, 2025
d6ea2b8
fix: add missing newline at end of files in geo-resto package
recule556688 Oct 21, 2025
4099c86
style: format geo-resto package with gno fmt
recule556688 Oct 21, 2025
96aa0ce
feat: add new event types and update event participation method names
recule556688 Oct 23, 2025
a286517
refactor: replace std.Address with address type across geo-resto package
recule556688 Oct 23, 2025
fc682d3
test: add unit tests for transaction link generation in geo-resto pac…
recule556688 Oct 29, 2025
0ef3949
feat: add string parsing helpers and transaction link generation for …
recule556688 Oct 29, 2025
e3df41a
feat: add quick action links for adding locations and checking in to …
recule556688 Oct 29, 2025
3297a28
refactor: remove obsolete transaction link tests from geo-resto package
recule556688 Nov 11, 2025
3004e91
refactor: streamline AuthManager by replacing maps with AVL trees for…
recule556688 Nov 11, 2025
7c7c006
refactor: replace maps with AVL trees in EventManager
recule556688 Nov 11, 2025
29a47eb
refactor: replace maps with AVL trees in LocationManager
recule556688 Nov 11, 2025
10e7201
refactor: replace maps with AVL trees in VisitManager
recule556688 Nov 11, 2025
50c4472
refactor: simplify event creation by removing redundant password para…
recule556688 Nov 11, 2025
d436ed4
refactor: remove password parameter from event-related functions for …
recule556688 Nov 11, 2025
44fa137
refactor: remove password check from event joining test for simplific…
recule556688 Nov 11, 2025
7f49c46
refactor: adjust formatting
recule556688 Nov 11, 2025
17e1263
refactor: enhance error handling in location and event functions; add…
recule556688 Nov 13, 2025
4b3368c
refactor: implement trusted verifier management; add functions to add…
recule556688 Nov 16, 2025
6350c6c
test: add unit tests for trusted verifier management functionality
recule556688 Nov 17, 2025
6cd9afc
refactor: enforce owner-only access checks in AddTrustedVerifier and …
recule556688 Nov 17, 2025
865cb24
refactor: add owner-only actions for managing trusted verifiers in re…
recule556688 Nov 17, 2025
7981ebd
fix: fixing the coding style
recule556688 Nov 19, 2025
0175a2d
refactor: remove obsolete 'zkproof is hard' documentation file
recule556688 Nov 19, 2025
92d9303
refactor: replace address truncation with name resolution for user vi…
recule556688 Nov 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions packages/r/karma1337/geo-resto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# 🌍 Geo-Resto

A Gno-based realm for creating a decentralized, on-chain record of real-world places and visits.

## Core Features

- **Location Management**: Add and verify geographic locations, creating a permanent, user-owned registry.
- **Proof of Presence**: Check-in at locations using a secure challenge-response mechanism to prove you were there.
- **Event System**: Organize location-based events like meetups, airdrops, or community gatherings.
- **QR Code Verification**: A robust system for event organizers to securely verify attendee presence in real-time.
- **On-Chain History**: All data is immutable, timestamped, and verifiable on the Gno blockchain.

## How It Works

The realm is organized into modules that handle specific tasks:

- `geo_resto.gno`: The main entry point and public API.
- `location.gno`: Manages location data.
- `visit.gno`: Handles check-ins and visit history.
- `event.gno`: Manages the event lifecycle.
- `auth.gno`: Secures the system with rate-limiting, access control, and verification logic.
- `renderer.gno`: Renders the web interface.

## Quick Start

### Add a Location
```gno
AddLocation("Eiffel Tower", "Iconic tower in Paris", 48.8584, 2.2945, "landmark")
```

### Check-In at a Location
1. **Get the challenge:**
```gno
GetLocationChallenge("loc_1")
```
2. **Submit the proof (challenge response):**
```gno
CheckIn("loc_1", "proof_from_challenge")
```

### Create an Event
```gno
CreateEvent("loc_1", "Tech Meetup", "Weekly discussion", "", 1, startTime, endTime)
```

## Event QR Code Verification

A secure system for proving event attendance.

- **Organizers**: Create an event to get a QR code. At the event, generate temporary verification codes for attendees using `GenerateAttendeeCode("event_1")`.
- **Attendees**: Get verified by the organizer.
- **Stats**: Organizers can track attendance with `GetVerifiedAttendees("event_1")` and `GetEventVerificationStats("event_1")`.

## Future Ideas

- **Zero-Knowledge Proofs**: For privacy-preserving check-ins.
- **Community Governance**: Location ratings, reviews, and decentralized moderation.
- **Enhanced Visuals**: Richer map interfaces and data visualizations.

## Testing

Run the full test suite with:
```bash
gno test
```

253 changes: 253 additions & 0 deletions packages/r/karma1337/geo-resto/auth.gno
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole file and functionality already exists in packages like p/nt/ownable & gno.land/p/nt/ownable/exts/authorizable. Please remove this code and use existing libraries. This will shorten your code, make it more readable, and increase the reusability value and trust of your code.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still unresolved

Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
package georesto

import (
"crypto/sha256"
"encoding/hex"
"math"
"strconv"
"time"

"gno.land/p/nt/avl"
"gno.land/p/nt/ownable/exts/authorizable"
)

// AuthManager handles access control and proof verification
type AuthManager struct {
*authorizable.Authorizable // Handles admin/verifier authorization
rateLimitTracker *avl.Tree // key (user:action) -> timestamp
accessTokens *avl.Tree // token -> expiration time
Authorized *avl.Tree // address -> bool (trusted verifiers)
}

// NewAuthManager creates a new authentication manager instance
func NewAuthManager() *AuthManager {
return &AuthManager{
Authorizable: authorizable.NewAuthorizable(),
rateLimitTracker: avl.NewTree(),
accessTokens: avl.NewTree(),
Authorized: avl.NewTree(),
}
}

// IsTrustedVerifier checks if an address is authorized (verifier)
func (am *AuthManager) IsTrustedVerifier(addr string) bool {
v, ok := am.Authorized.Get(addr)
if !ok {
return false
}
return v.(bool)
}

// AddTrustedVerifier allows the owner to add an address as a trusted verifier
func (am *AuthManager) AddTrustedVerifier(addr string, caller address) bool {
// Owner-only check
if am.Authorizable.Owner() != caller {
return false
}

// Add via the authorizable extension and mirror locally.
err := am.Authorizable.AddToAuthList(address(addr))
if err != nil {
return false
}
am.Authorized.Set(addr, true)
return true
}

// RemoveTrustedVerifier allows the owner to remove a trusted verifier
func (am *AuthManager) RemoveTrustedVerifier(addr string, caller address) bool {
// Owner-only check
if am.Authorizable.Owner() != caller {
return false
}

err := am.Authorizable.DeleteFromAuthList(address(addr))
if err != nil {
return false
}
am.Authorized.Remove(addr)
return true
}

// IsAdmin checks if an address is an admin (owner or authorized)
func (am *AuthManager) IsAdmin(addr string) bool {
addrType := address(addr)
return am.Authorizable.Owner() == addrType
}

// VerifyLocationProof verifies a cryptographic proof for location check-in
func (am *AuthManager) VerifyLocationProof(userAddress, locationID, proof string, timestamp int64) bool {
// In a real implementation, this would involve more complex verification.
// For now, we'll check if the proof is a valid challenge response.
return am.VerifyLocationChallenge(locationID, proof)
}

// GenerateLocationProof generates a proof for location check-in
func (am *AuthManager) GenerateLocationProof(userAddress, locationID string, timestamp int64) string {
return am.generateLocationProof(userAddress, locationID, timestamp)
}

// CanModifyLocation checks if a user can modify a location
func (am *AuthManager) CanModifyLocation(locationID string, user address) bool {
location := locationManager.GetLocation(locationID)
if location == nil {
return false
}

userAddr := user.String()

// Location creator can always modify
if location.Creator.String() == userAddr {
return true
}

// Admins can modify any location
if am.IsAdmin(userAddr) {
return true
}
// Trusted verifiers can modify for verification purposes
if am.IsTrustedVerifier(userAddr) {
return true
}
return false
}

// CanModifyEvent checks if a user can modify an event
func (am *AuthManager) CanModifyEvent(eventID string, user address) bool {
event := eventManager.GetEvent(eventID)
if event == nil {
return false
}

userAddr := user.String()

// Event creator can always modify
if event.Creator.String() == userAddr {
return true
}

// Admins can modify any event
if am.IsAdmin(userAddr) {
return true
}

return false
}

// ValidateCoordinates validates GPS coordinates
func (am *AuthManager) ValidateCoordinates(latitude, longitude float64) bool {
return latitude >= -90 && latitude <= 90 && longitude >= -180 && longitude <= 180
}

// ValidateProximity checks if user is within acceptable range of location
func (am *AuthManager) ValidateProximity(userLat, userLon, locationLat, locationLon, maxDistanceKm float64) bool {
distance := haversine(userLat, userLon, locationLat, locationLon)
return distance <= maxDistanceKm
}

// GenerateAccessToken generates a temporary access token for API access
func (am *AuthManager) GenerateAccessToken(userAddress string, expirationTime int64) string {
data := userAddress + ":" + strconv.FormatInt(expirationTime, 10)
hash := sha256.Sum256([]byte(data))
token := hex.EncodeToString(hash[:])
am.accessTokens.Set(token, expirationTime)
return token
}

// VerifyAccessToken verifies an access token
func (am *AuthManager) VerifyAccessToken(token, userAddress string, currentTime int64) bool {
expirationTimeValue, exists := am.accessTokens.Get(token)
if !exists {
return false // Token does not exist
}

expirationTime := expirationTimeValue.(int64)
if currentTime > expirationTime {
am.accessTokens.Remove(token) // Clean up expired token
return false // Token has expired
}

return true
}

// CheckRateLimit implements basic rate limiting for API calls
func (am *AuthManager) CheckRateLimit(userAddress string, action string, cooldownSeconds int64) bool {
key := userAddress + ":" + action
lastActionTimeValue, exists := am.rateLimitTracker.Get(key)

currentTime := time.Now().Unix()

if exists {
lastActionTime := lastActionTimeValue.(int64)
if (currentTime - lastActionTime) < cooldownSeconds {
return false // Rate limit exceeded
}
}

am.rateLimitTracker.Set(key, currentTime)
return true
}

// Helper methods

func (am *AuthManager) generateLocationProof(userAddress, locationID string, timestamp int64) string {
data := userAddress + ":" + locationID + ":" + strconv.FormatInt(timestamp, 10)
hash := sha256.Sum256([]byte(data))
return hex.EncodeToString(hash[:])
}

func (am *AuthManager) hashString(input string) string {
hash := sha256.Sum256([]byte(input))
return hex.EncodeToString(hash[:])
}

// VerifyZKProof verifies a zero-knowledge proof (placeholder for future implementation)
func (am *AuthManager) VerifyZKProof(proof string, publicInputs []string) bool {
// Placeholder for ZK proof verification
// In a real implementation, this would verify a zk-SNARK or zk-STARK proof
// allowing users to prove they were at a location without revealing exact coordinates
return len(proof) > 0 && len(publicInputs) > 0
}

// GenerateLocationChallenge generates a challenge for location verification
func (am *AuthManager) GenerateLocationChallenge(locationID string) string {
// Generate a time-based challenge that can be solved by someone physically present
timestamp := time.Now().Unix()
data := locationID + ":" + strconv.FormatInt(timestamp/300, 10) // 5-minute windows
hash := sha256.Sum256([]byte(data))
return hex.EncodeToString(hash[:8]) // Return first 8 bytes as challenge
}

// VerifyLocationChallenge verifies a location challenge response
func (am *AuthManager) VerifyLocationChallenge(locationID, response string) bool {
// Check if response matches any of the last few time windows (for clock drift tolerance)
currentTime := time.Now().Unix()
for i := 0; i < 3; i++ { // Check current and previous 2 windows
timeWindow := (currentTime / 300) - int64(i)
data := locationID + ":" + strconv.FormatInt(timeWindow, 10)
hash := sha256.Sum256([]byte(data))
expectedResponse := hex.EncodeToString(hash[:8])

if response == expectedResponse {
return true
}
}

return false
}

// haversine calculates the distance between two points on Earth.
func haversine(lat1, lon1, lat2, lon2 float64) float64 {
const R = 6371 // Earth radius in kilometers
dLat := (lat2 - lat1) * (math.Pi / 180.0)
dLon := (lon2 - lon1) * (math.Pi / 180.0)
lat1Rad := lat1 * (math.Pi / 180.0)
lat2Rad := lat2 * (math.Pi / 180.0)

a := math.Sin(dLat/2)*math.Sin(dLat/2) +
math.Cos(lat1Rad)*math.Cos(lat2Rad)*
math.Sin(dLon/2)*math.Sin(dLon/2)
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))

return R * c
}
Loading
Loading