// Proves sign-in end to end against the deployed API. // // The password is read from the database and posted straight to the endpoint — // never printed, never passed on a command line where it would land in a shell // history. The token is truncated in the output for the same reason: it is a // bearer credential for a whole trading day. package main import ( "bytes" "encoding/json" "fmt" "io" "log" "net/http" "os" "strings" "github.com/joho/godotenv" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" ) const base = "https://fiesta.nearle.app/live/api/v1/pos" func main() { who := "rsselvapuram@gmail.com" if len(os.Args) > 1 { who = os.Args[1] } _ = godotenv.Load() dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_USER"), os.Getenv("DB_PASSWORD"), os.Getenv("DB_NAME")) db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)}) if err != nil { log.Fatal(err) } var pw string db.Raw(`SELECT COALESCE(password,'') FROM app_users WHERE LOWER(authname)=LOWER(?) LIMIT 1`, who).Scan(&pw) if pw == "" { log.Fatalf("%s has no password set", who) } body, _ := json.Marshal(map[string]any{ "authname": who, "password": pw, "terminal_id": "PROBE", "device_id": "probe-device", }) resp, err := http.Post(base+"/login", "application/json", bytes.NewReader(body)) if err != nil { log.Fatal(err) } defer resp.Body.Close() raw, _ := io.ReadAll(resp.Body) fmt.Printf("POST /login HTTP %d\n", resp.StatusCode) var out struct { Message string `json:"message"` Details struct { Token string `json:"token"` Expiresat string `json:"expires_at"` Tenantid int `json:"tenant_id"` Tenantname string `json:"tenant_name"` Storeid string `json:"store_id"` Locationname string `json:"location_name"` Gstin string `json:"gstin"` Locations []struct { Locationid int `json:"location_id"` Locationname string `json:"location_name"` } `json:"locations"` Staff []struct { Fullname string `json:"full_name"` Role string `json:"role"` } `json:"staff"` } `json:"details"` } if err := json.Unmarshal(raw, &out); err != nil { fmt.Println(string(raw)) return } if resp.StatusCode != 200 { fmt.Println(" ", out.Message) return } t := out.Details.Token fmt.Printf(" token %s… (%d chars, signature verified below)\n", t[:12], len(t)) fmt.Printf(" expires %s\n", out.Details.Expiresat) fmt.Printf(" tenant %d %s\n", out.Details.Tenantid, out.Details.Tenantname) fmt.Printf(" store_id %s (%s)\n", out.Details.Storeid, out.Details.Locationname) fmt.Printf(" gstin %s\n", out.Details.Gstin) fmt.Printf(" outlets %d\n", len(out.Details.Locations)) fmt.Printf(" staff %d\n", len(out.Details.Staff)) for _, s := range out.Details.Staff { fmt.Printf(" %s (%s)\n", s.Fullname, s.Role) } // The token has to actually open the doors it claims to. for _, path := range []string{"/session", "/staff", "/catalogue?store_id=" + out.Details.Storeid + "&page_size=1"} { req, _ := http.NewRequest("GET", base+path, nil) req.Header.Set("Authorization", "Bearer "+t) r, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } b, _ := io.ReadAll(r.Body) r.Body.Close() fmt.Printf("\nGET %-28s HTTP %d %s", strings.Split(path, "&")[0], r.StatusCode, truncate(string(b), 150)) } // And must NOT open somebody else's. req, _ := http.NewRequest("GET", base+"/catalogue?store_id=1185&page_size=1", nil) req.Header.Set("Authorization", "Bearer "+t) r, _ := http.DefaultClient.Do(req) b, _ := io.ReadAll(r.Body) r.Body.Close() fmt.Printf("\n\nGET /catalogue (ANOTHER TENANT'S OUTLET 1185) HTTP %d %s\n", r.StatusCode, truncate(string(b), 160)) } func truncate(s string, n int) string { s = strings.ReplaceAll(s, "\n", " ") if len(s) > n { return s[:n] + "…" } return s }