diff --git a/.dockerignore b/.dockerignore new file mode 120000 index 0000000..6200b3a --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +./.gitignore \ No newline at end of file diff --git a/.env b/.env deleted file mode 100644 index 0ab81c5..0000000 --- a/.env +++ /dev/null @@ -1,6 +0,0 @@ -KDOORPI_DOOR=workshop -KDOORPI_API_ALLOWED=http://127.0.0.1:3333/allowed -KDOORPI_API_LONGPOLL=http://127.0.0.1:3333/longpoll -KDOORPI_API_SWIPE=http://127.0.0.1:3333/cardswipe -KDOORPI_API_KEY=keykey -KDOORPI_MOCK_HW=true diff --git a/.gitignore b/.gitignore index 1074e4f..089d22c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ godoor godoor_server/godoor_server godoor_server/keys.json +__debug_bin* +.env +.vscode diff --git a/Dockerfile b/Dockerfile index 7a08e04..6948512 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM mirror.gcr.io/library/golang:1.21-alpine as build +FROM mirror.gcr.io/library/golang:1.25-alpine AS build RUN apk add ca-certificates WORKDIR /godoor diff --git a/go.mod b/go.mod index 5fc5e13..9a9c5b4 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,8 @@ module godoor -go 1.21 +go 1.25 require ( - github.com/joho/godotenv v1.5.1 github.com/prometheus/client_golang v1.16.0 github.com/warthog618/gpiod v0.8.2 golang.org/x/crypto v0.12.0 diff --git a/go.sum b/go.sum index 6f0c360..3f89ffa 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,6 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/godoor.go b/godoor.go index 639998a..642f624 100644 --- a/godoor.go +++ b/godoor.go @@ -18,7 +18,6 @@ import ( "syscall" "time" - "github.com/joho/godotenv" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -33,18 +32,12 @@ const ( solenoid_default = 21 ) -type card struct { - UidHash string `json:"uid_hash"` -} - -type cardList struct { - AllowedUids []struct { - Token card `json:"token"` - } `json:"allowed_uids"` +type upstreamUpdate struct { + AllowedHashes []string `json:"allowed_hashes"` KeepOpenUntil *time.Time `json:"keep_open_until,omitempty"` } -type ValidUids map[string]bool // bool has no meaning +type ValidHashesT map[string]bool // bool has no meaning type Config struct { door string @@ -90,11 +83,11 @@ var Commit = func() string { var Version string var ( - config Config - globalLock sync.Mutex - validUids ValidUids - wiegand Wiegand - keepDoorOpen KeepDoorOpen + config Config + VALID_HASHES_LOCK sync.Mutex + VALID_HASHES = make(ValidHashesT) + wiegand Wiegand + keepDoorOpen KeepDoorOpen ) var ( @@ -130,6 +123,7 @@ func main() { defer cancel() loadConfig() + log.Printf("Door name: %s\n", config.door) godoorBuildInfo.WithLabelValues(Version, Commit).Set(1) @@ -146,12 +140,6 @@ func main() { func loadConfig() { var err error - log.Println("Loading .env config") - err = godotenv.Load() - if err != nil { - log.Println("Failed to load .env config, using internal defaults") - } - config.door = os.Getenv("KDOORPI_DOOR") config.api.allowed = os.Getenv("KDOORPI_API_ALLOWED") config.api.longpoll = os.Getenv("KDOORPI_API_LONGPOLL") @@ -189,8 +177,6 @@ func loadConfig() { } func setup(ctx context.Context) { - log.Println("Started Setup") - if config.mock { log.Println("MOCK mode enabled") if config.door == "" { @@ -208,7 +194,7 @@ func setup(ctx context.Context) { for { log.Println("Start initial token population") - err := reloadTokens() + err := reloadInfo() if err == nil { break } @@ -230,9 +216,9 @@ func setup(ctx context.Context) { } time.Sleep(1 * time.Second) go func() { - err := reloadTokens() + err := reloadInfo() if err != nil { - log.Printf("ReloadTokens failed: %q", err) + log.Printf("reloadTokens failed: %q", err) apiFailuresCount.WithLabelValues("allowed", config.api.allowed).Inc() } }() @@ -325,9 +311,9 @@ func cardRunner(w Wiegand) { hashedHex := hash.HashCardUid(card) log.Println(hashedHex) - globalLock.Lock() - ok := validUids[hashedHex] - globalLock.Unlock() + VALID_HASHES_LOCK.Lock() + ok := VALID_HASHES[hashedHex] + VALID_HASHES_LOCK.Unlock() go func() { err := sendSwipeEvent(hashedHex, ok) @@ -416,12 +402,13 @@ func waitEvents() error { } } -func reloadTokens() error { +func reloadInfo() error { req, err := http.NewRequest(http.MethodGet, config.api.allowed, nil) if err != nil { return err } req.Header.Add("KEY", config.api.key) + req.Header.Add("DOOR_NAME", config.door) resp, err := http.DefaultClient.Do(req) if err != nil { return err @@ -430,32 +417,35 @@ func reloadTokens() error { log.Printf("%v\n", resp) } - var cl cardList + var info upstreamUpdate body, err := io.ReadAll(resp.Body) if err != nil { return err } - err = json.Unmarshal(body, &cl) + err = json.Unmarshal(body, &info) if err != nil { return err } - globalLock.Lock() - defer globalLock.Unlock() - validUids = make(ValidUids) - var totalCardCount int = 0 - for i, val := range cl.AllowedUids { - // log.Printf("%d: %+v\n", i, val.Token.UidHash) - validUids[val.Token.UidHash] = true - totalCardCount = i + // Update Allowed hashes + validHashesPre := make(ValidHashesT) + for _, hash := range info.AllowedHashes { + validHashesPre[hash] = true } - log.Printf("Got %d cards from server", totalCardCount) - nrCardsInAllowList.Set(float64(totalCardCount)) - if cl.KeepOpenUntil != nil { - updateKeepOpenDoor(*cl.KeepOpenUntil) + VALID_HASHES_LOCK.Lock() + VALID_HASHES = validHashesPre + VALID_HASHES_LOCK.Unlock() + + log.Printf("Got %d cards from server", len(info.AllowedHashes)) + nrCardsInAllowList.Set(float64(len(info.AllowedHashes))) + + // Update Keep open + + if info.KeepOpenUntil != nil { + updateKeepOpenDoor(*info.KeepOpenUntil) } lastSyncTimestamp.SetToCurrentTime() @@ -463,32 +453,6 @@ func reloadTokens() error { return nil } -func updateKeepOpenDoor(newKeepOpenTime time.Time) { - // is there one active? - if keepDoorOpen.timer != nil { - keepDoorOpen.timer.Stop() - keepDoorOpen = KeepDoorOpen{} - } - - if newKeepOpenTime.After(time.Now()) { - log.Printf("Keeping door open until %v", newKeepOpenTime) - OpenDoor(wiegand) - timer := time.AfterFunc(time.Until(newKeepOpenTime), handleKeepDoorOpenCloseCleanup) - keepDoorOpen = KeepDoorOpen{ - timer: timer, - until: newKeepOpenTime, - } - } else { - CloseDoor(wiegand) - } -} - -func handleKeepDoorOpenCloseCleanup() { - fmt.Println("Keep door open time is reached!") - CloseDoor(wiegand) - keepDoorOpen = KeepDoorOpen{} -} - func sendSwipeEvent(cardUidHash string, success bool) error { swipeEvent := map[string]any{ "uid_hash": cardUidHash, diff --git a/keepopen.go b/keepopen.go new file mode 100644 index 0000000..0d1f2f8 --- /dev/null +++ b/keepopen.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + "log" + "time" +) + +func updateKeepOpenDoor(newKeepOpenTime time.Time) { + // is there one active? + if keepDoorOpen.timer != nil { + keepDoorOpen.timer.Stop() + keepDoorOpen = KeepDoorOpen{} + } + + if newKeepOpenTime.After(time.Now()) { + log.Printf("Keeping door open until %v", newKeepOpenTime) + OpenDoor(wiegand) + timer := time.AfterFunc(time.Until(newKeepOpenTime), handleKeepDoorOpenCloseCleanup) + keepDoorOpen = KeepDoorOpen{ + timer: timer, + until: newKeepOpenTime, + } + } else { + CloseDoor(wiegand) + } +} + +func handleKeepDoorOpenCloseCleanup() { + fmt.Println("Keep door open time is reached!") + CloseDoor(wiegand) + keepDoorOpen = KeepDoorOpen{} +} diff --git a/wiegand.go b/wiegand.go index 255155e..ca4283c 100644 --- a/wiegand.go +++ b/wiegand.go @@ -57,6 +57,7 @@ func (w *WiegandHW) IsDoorOpen() (bool, error) { defer w.lock.RUnlock() return w.isDoorOpen() } + func (w *WiegandHW) isDoorOpen() (bool, error) { i, err := w.solenoidLine.Value() if err != nil { @@ -90,19 +91,18 @@ func (w *WiegandHW) GetCardUid() (uint64, error) { func (w *WiegandHW) wiegandAEvent(evt gpiod.LineEvent) { w.bitTimeoutTimer.Reset(w.bitTimeout) w.bits[w.bitNr] = true - //fmt.Printf("1") + // fmt.Printf("1") w.bitNr += 1 } func (w *WiegandHW) wiegandBEvent(evt gpiod.LineEvent) { w.bitTimeoutTimer.Reset(w.bitTimeout) w.bits[w.bitNr] = false - //fmt.Printf("0") + // fmt.Printf("0") w.bitNr += 1 } func WiegandSetup(a int, b int, bitTimeout time.Duration, solenoid int) *WiegandHW { - log.Printf("Wiegand GPIO-s: A:%d B:%d Solenoid:%d", a, b, solenoid) var wiegand WiegandHW wiegand.bitTimeout = bitTimeout @@ -141,9 +141,9 @@ func (w *WiegandHW) WiegandClose() { w.solenoidLine.Close() } -func printCardId(card uint64) { - for i := 0; i < 7; i++ { - fmt.Printf("%02x", (card>>(8*i))&0xff) - } - fmt.Printf("\n") -} +// func printCardId(card uint64) { +// for i := 0; i < 7; i++ { +// fmt.Printf("%02x", (card>>(8*i))&0xff) +// } +// fmt.Printf("\n") +// }