Checkpoint 3
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,2 +1,3 @@ | |||||||
| .idea | .idea | ||||||
| godoor | godoor | ||||||
|  | godoor_server/godoor_server | ||||||
|   | |||||||
							
								
								
									
										150
									
								
								godoor.go
									
									
									
									
									
								
							
							
						
						
									
										150
									
								
								godoor.go
									
									
									
									
									
								
							| @@ -2,11 +2,13 @@ package main | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"github.com/joho/godotenv" | 	"github.com/joho/godotenv" | ||||||
| 	"io" | 	"io" | ||||||
|  | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/signal" | 	"os/signal" | ||||||
| @@ -31,17 +33,14 @@ type cardList struct { | |||||||
| 	} `json:"allowed_uids"` | 	} `json:"allowed_uids"` | ||||||
| } | } | ||||||
|  |  | ||||||
| type simpleUids struct { |  | ||||||
| 	tokens []string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type ValidUids map[string]bool // bool has no meaning | type ValidUids map[string]bool // bool has no meaning | ||||||
|  |  | ||||||
| type Config struct { | type Config struct { | ||||||
| 	door     string | 	door         string | ||||||
| 	uid_salt string | 	uidSalt      string | ||||||
| 	mock     string | 	doorOpenTime string | ||||||
| 	api      struct { | 	mock         bool | ||||||
|  | 	api          struct { | ||||||
| 		allowed  string | 		allowed  string | ||||||
| 		longpoll string | 		longpoll string | ||||||
| 		swipe    string | 		swipe    string | ||||||
| @@ -66,26 +65,29 @@ func main() { | |||||||
| 	config.api.longpoll = os.Getenv("KDOORPI_API_LONGPOLL") | 	config.api.longpoll = os.Getenv("KDOORPI_API_LONGPOLL") | ||||||
| 	config.api.swipe = os.Getenv("KDOORPI_API_SWIPE") | 	config.api.swipe = os.Getenv("KDOORPI_API_SWIPE") | ||||||
| 	config.api.key = os.Getenv("KDOORPI_API_KEY") | 	config.api.key = os.Getenv("KDOORPI_API_KEY") | ||||||
| 	config.uid_salt = os.Getenv("KDOORPI_UID_SALT") | 	config.uidSalt = os.Getenv("KDOORPI_UID_SALT") | ||||||
| 	config.mock = os.Getenv("KDOORPI_MOCK_HW") | 	config.doorOpenTime = os.Getenv("KDOORPI_OPEN_TIME") | ||||||
|  | 	_, config.mock = os.LookupEnv("KDOORPI_MOCK_HW") | ||||||
|  |  | ||||||
| 	if config.mock == "true" { | 	go func() { | ||||||
|  | 		setup() | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	<-ctx.Done() | ||||||
|  | 	log.Printf("Cleanup\n") | ||||||
|  |  | ||||||
|  | 	// cleanup | ||||||
|  | } | ||||||
|  | func setup() { | ||||||
|  | 	log.Println("Started Setup") | ||||||
|  |  | ||||||
|  | 	if config.mock { | ||||||
|  | 		log.Println("MOCK mode enabled") | ||||||
| 		wiegand = &WiegandMock{} | 		wiegand = &WiegandMock{} | ||||||
| 	} else { | 	} else { | ||||||
| 		wiegand = WiegandSetup(wiegand_a, wiegand_b, wiegand_bit_timeout, solenoid) | 		wiegand = WiegandSetup(wiegand_a, wiegand_b, wiegand_bit_timeout, solenoid) | ||||||
| 	} | 	} | ||||||
|  | 	log.Println("HW Setup done") | ||||||
| 	http.DefaultClient.Timeout = 120 * time.Second |  | ||||||
|  |  | ||||||
| 	for { |  | ||||||
| 		err := reloadTokens() |  | ||||||
| 		if err == nil { |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 		time.Sleep(10 * time.Second) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	go cardRunner(wiegand) |  | ||||||
|  |  | ||||||
| 	go func() { | 	go func() { | ||||||
| 		for { | 		for { | ||||||
| @@ -93,12 +95,44 @@ func main() { | |||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	fmt.Printf("Sleeping\n") | 	log.Println("Initialized longpoll event loop") | ||||||
|  |  | ||||||
| 	<-ctx.Done() | 	http.DefaultClient.Timeout = 120 * time.Second | ||||||
| 	fmt.Printf("Cleanup\n") |  | ||||||
|  |  | ||||||
| 	// cleanup | 	for { | ||||||
|  | 		log.Println("Start initial token population") | ||||||
|  | 		err := reloadTokens() | ||||||
|  | 		if err == nil { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		log.Printf("Initial token population failed. err: %v", err) | ||||||
|  | 		log.Println("Retrying in 10 seconds...") | ||||||
|  | 		time.Sleep(10 * time.Second) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	log.Println("Initial token population success") | ||||||
|  |  | ||||||
|  | 	go cardRunner(wiegand) | ||||||
|  |  | ||||||
|  | 	log.Println("Setup completed") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func OpenAndCloseDoor(w Wiegand) error { | ||||||
|  | 	err := w.OpenDoor() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	fmt.Println("Door is now open") | ||||||
|  |  | ||||||
|  | 	time.Sleep(5 * time.Second) | ||||||
|  |  | ||||||
|  | 	err = w.CloseDoor() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	fmt.Println("Door is now closed") | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func cardRunner(w Wiegand) { | func cardRunner(w Wiegand) { | ||||||
| @@ -110,16 +144,26 @@ func cardRunner(w Wiegand) { | |||||||
|  |  | ||||||
| 		printCardId(card) | 		printCardId(card) | ||||||
| 		hashedHex := hashCardUid(card) | 		hashedHex := hashCardUid(card) | ||||||
| 		fmt.Println(hashedHex) | 		log.Println(hashedHex) | ||||||
|  |  | ||||||
|  | 		go func() { | ||||||
|  | 			err := sendSwipeEvent(hashedHex) | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Println("Failed to send swipe event: %v", err) | ||||||
|  | 			} | ||||||
|  | 		}() | ||||||
|  |  | ||||||
| 		globalLock.Lock() | 		globalLock.Lock() | ||||||
| 		ok := validUids[hashedHex] | 		ok := validUids[hashedHex] | ||||||
| 		globalLock.Unlock() | 		globalLock.Unlock() | ||||||
| 		if ok { | 		if ok { | ||||||
| 			fmt.Println("Opening door") | 			log.Println("Opening door") | ||||||
| 			w.OpenDoor() | 			err := OpenAndCloseDoor(w) | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Println("There was an error opening and closing the Door") | ||||||
|  | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			fmt.Println("Unknown card") | 			log.Println("Unknown card") | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
| @@ -159,7 +203,7 @@ func waitEvents() error { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	fmt.Printf("%v\n", resp) | 	log.Printf("%v\n", resp) | ||||||
|  |  | ||||||
| 	reader := bufio.NewReader(resp.Body) | 	reader := bufio.NewReader(resp.Body) | ||||||
| 	for { | 	for { | ||||||
| @@ -173,9 +217,12 @@ func waitEvents() error { | |||||||
| 			if !found_data { | 			if !found_data { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			fmt.Printf("got server data: %q\n", data) | 			log.Printf("got server data: %q\n", data) | ||||||
| 			if strings.TrimSpace(data) == config.door { | 			if strings.TrimSpace(data) == config.door { | ||||||
| 				wiegand.OpenDoor() | 				err := OpenAndCloseDoor(wiegand) | ||||||
|  | 				if err != nil { | ||||||
|  | 					log.Println("There was an error opening and closing the Door") | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			go reloadTokens() | 			go reloadTokens() | ||||||
| @@ -183,7 +230,7 @@ func waitEvents() error { | |||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	fmt.Printf("%v\n", resp) | 	log.Printf("%v\n", resp) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -197,7 +244,7 @@ func reloadTokens() error { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	fmt.Printf("%v\n", resp) | 	log.Printf("%v\n", resp) | ||||||
|  |  | ||||||
| 	var cl cardList | 	var cl cardList | ||||||
|  |  | ||||||
| @@ -215,9 +262,38 @@ func reloadTokens() error { | |||||||
| 	defer globalLock.Unlock() | 	defer globalLock.Unlock() | ||||||
| 	validUids = make(ValidUids) | 	validUids = make(ValidUids) | ||||||
| 	for i, val := range cl.AllowedUids { | 	for i, val := range cl.AllowedUids { | ||||||
| 		fmt.Printf("%d: %+v\n", i, val.Token.UidHash) | 		log.Printf("%d: %+v\n", i, val.Token.UidHash) | ||||||
| 		validUids[val.Token.UidHash] = true | 		validUids[val.Token.UidHash] = true | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func sendSwipeEvent(cardUidHash string) error { | ||||||
|  | 	swipeEvent := map[string]string{ | ||||||
|  | 		"uid_hash":  cardUidHash, | ||||||
|  | 		"door":      config.door, | ||||||
|  | 		"timestamp": time.Now().Format(time.DateTime), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	data, err := json.Marshal(swipeEvent) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	req, err := http.NewRequest(http.MethodPost, config.api.swipe, bytes.NewReader(data)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	req.Header.Add("KEY", config.api.key) | ||||||
|  | 	resp, err := http.DefaultClient.Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !(resp.StatusCode >= 200 && resp.StatusCode < 300) { | ||||||
|  | 		return fmt.Errorf("Server responded with %d", resp.StatusCode) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ func getAllowed(w http.ResponseWriter, r *http.Request) { | |||||||
| 	keys := cardList{ | 	keys := cardList{ | ||||||
| 		AllowedUids: []cardToken{ | 		AllowedUids: []cardToken{ | ||||||
| 			{card{UidHash: "d72c87d0f077c7766f2985dfab30e8955c373a13a1e93d315203939f542ff86e73ee37c31f4c4b571f4719fa8e3589f12db8dcb57ea9f56764bb7d58f64cf705"}}, | 			{card{UidHash: "d72c87d0f077c7766f2985dfab30e8955c373a13a1e93d315203939f542ff86e73ee37c31f4c4b571f4719fa8e3589f12db8dcb57ea9f56764bb7d58f64cf705"}}, | ||||||
| 			{card{UidHash: "112233445566"}}, | 			{card{UidHash: "873636abbcf597a4835afc1c9b16a72eb6175b7ab278a8f18ab13c50172c90ea97cc3e258efd9cc1d885d7ea32d87fd006907892793e7cd6c468417bd8b8421a"}}, | ||||||
| 			{card{UidHash: "aabbccddeeff"}}, | 			{card{UidHash: "aabbccddeeff"}}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| @@ -114,6 +114,10 @@ func (doobserver *DoorBoyServer) postOpenDoor(w http.ResponseWriter, r *http.Req | |||||||
| 	w.Write([]byte("OK")) | 	w.Write([]byte("OK")) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func postCardSwipe(w http.ResponseWriter, r *http.Request) { | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
| 	doorboyserver := DoorBoyServer{longPollers: map[string]chan string{}} | 	doorboyserver := DoorBoyServer{longPollers: map[string]chan string{}} | ||||||
| 	http.HandleFunc("/", getRoot) | 	http.HandleFunc("/", getRoot) | ||||||
| @@ -121,6 +125,7 @@ func main() { | |||||||
| 	http.HandleFunc("/longpoll", doorboyserver.getLongPoll) | 	http.HandleFunc("/longpoll", doorboyserver.getLongPoll) | ||||||
| 	http.HandleFunc("/jspoll", doorboyserver.getLongPollJson) | 	http.HandleFunc("/jspoll", doorboyserver.getLongPollJson) | ||||||
| 	http.HandleFunc("/open", doorboyserver.postOpenDoor) | 	http.HandleFunc("/open", doorboyserver.postOpenDoor) | ||||||
|  | 	http.HandleFunc("/cardswipe", postCardSwipe) | ||||||
|  |  | ||||||
| 	err := http.ListenAndServe(":3333", nil) | 	err := http.ListenAndServe(":3333", nil) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								wiegand.go
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								wiegand.go
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ import ( | |||||||
| 	"encoding/hex" | 	"encoding/hex" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"golang.org/x/crypto/scrypt" | 	"golang.org/x/crypto/scrypt" | ||||||
|  | 	"log" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -14,7 +15,9 @@ import ( | |||||||
|  |  | ||||||
| type Wiegand interface { | type Wiegand interface { | ||||||
| 	GetCardUid() (uint64, error) | 	GetCardUid() (uint64, error) | ||||||
| 	OpenDoor() | 	OpenDoor() error | ||||||
|  | 	CloseDoor() error | ||||||
|  | 	IsDoorOpen() (bool, error) | ||||||
| } | } | ||||||
|  |  | ||||||
| type WiegandHW struct { | type WiegandHW struct { | ||||||
| @@ -28,15 +31,21 @@ type WiegandHW struct { | |||||||
| 	solenoidLine *gpiod.Line | 	solenoidLine *gpiod.Line | ||||||
| } | } | ||||||
|  |  | ||||||
| func (w *WiegandHW) OpenDoor() { | func (w *WiegandHW) OpenDoor() error { | ||||||
| 	fmt.Println("Open") | 	return w.solenoidLine.SetValue(1) | ||||||
| 	w.solenoidLine.SetValue(1) |  | ||||||
| 	d, _ := time.ParseDuration("500ms") |  | ||||||
| 	time.Sleep(d) |  | ||||||
| 	w.solenoidLine.SetValue(0) |  | ||||||
| 	fmt.Println("Close") |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (w *WiegandHW) CloseDoor() error { | ||||||
|  | 	return w.solenoidLine.SetValue(0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *WiegandHW) IsDoorOpen() (bool, error) { | ||||||
|  | 	i, err := w.solenoidLine.Value() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	return i == 1, nil | ||||||
|  | } | ||||||
| func printCardId(card uint64) { | func printCardId(card uint64) { | ||||||
| 	for i := 0; i < 7; i++ { | 	for i := 0; i < 7; i++ { | ||||||
| 		fmt.Printf("%02x", (card>>(8*i))&0xff) | 		fmt.Printf("%02x", (card>>(8*i))&0xff) | ||||||
| @@ -47,7 +56,7 @@ func printCardId(card uint64) { | |||||||
| func hashCardUid(card uint64) string { | func hashCardUid(card uint64) string { | ||||||
| 	b := make([]byte, 8) | 	b := make([]byte, 8) | ||||||
| 	binary.LittleEndian.PutUint64(b, card) | 	binary.LittleEndian.PutUint64(b, card) | ||||||
| 	hashed, err := scrypt.Key(b, []byte(config.uid_salt), 16384, 8, 1, 64) | 	hashed, err := scrypt.Key(b, []byte(config.uidSalt), 16384, 8, 1, 64) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		panic(err) // can only happen when scrypt params are garbage | 		panic(err) // can only happen when scrypt params are garbage | ||||||
| 	} | 	} | ||||||
| @@ -58,10 +67,9 @@ func hashCardUid(card uint64) string { | |||||||
|  |  | ||||||
| func (w *WiegandHW) GetCardUid() (uint64, error) { | func (w *WiegandHW) GetCardUid() (uint64, error) { | ||||||
| 	// Wait for bit timeout | 	// Wait for bit timeout | ||||||
| 	fmt.Printf("Waiting for bit timeout\n") | 	log.Printf("Waiting for bit timeout\n") | ||||||
|  |  | ||||||
| 	<-w.bitTimeoutTimer.C | 	<-w.bitTimeoutTimer.C | ||||||
| 	fmt.Printf("\n") |  | ||||||
|  |  | ||||||
| 	defer func() { w.bitNr = 0 }() | 	defer func() { w.bitNr = 0 }() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,23 +1,32 @@ | |||||||
| package main | package main | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" |  | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type WiegandMock struct { | type WiegandMock struct { | ||||||
| 	mockUid uint64 | 	mockUid uint64 | ||||||
|  |  | ||||||
|  | 	openState bool | ||||||
| } | } | ||||||
|  |  | ||||||
| func (*WiegandMock) OpenDoor() { | func (w *WiegandMock) OpenDoor() error { | ||||||
| 	fmt.Println("Door is now open") | 	w.openState = true | ||||||
| 	time.Sleep(500 * time.Millisecond) | 	return nil | ||||||
| 	fmt.Println("Door is now closed") | } | ||||||
|  |  | ||||||
|  | func (w *WiegandMock) CloseDoor() error { | ||||||
|  | 	w.openState = false | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *WiegandMock) IsDoorOpen() (bool, error) { | ||||||
|  | 	return w.openState, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (w *WiegandMock) GetCardUid() (uint64, error) { | func (w *WiegandMock) GetCardUid() (uint64, error) { | ||||||
| 	time.Sleep(1 * time.Second) | 	time.Sleep(1 * time.Second) | ||||||
| 	return w.mockUid, fmt.Errorf("err") | 	return w.mockUid, nil //fmt.Errorf("err") | ||||||
| } | } | ||||||
|  |  | ||||||
| func (w *WiegandMock) SetMockUid(mockUid uint64) { | func (w *WiegandMock) SetMockUid(mockUid uint64) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user