From 395d932f93e77088cb08a5a9ac7491ee97ebfbee Mon Sep 17 00:00:00 2001 From: Justin Judd Date: Mon, 11 Jan 2016 09:56:15 +0900 Subject: [PATCH] Updating some of the examples. --- README.md | 23 +++++++---- hotp_client_example_test.go | 58 +++++++++++++++++++++++++++ hotp_example_test.go | 14 +++---- hotp_server_example_test.go | 78 +++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 14 deletions(-) create mode 100644 hotp_client_example_test.go create mode 100644 hotp_server_example_test.go diff --git a/README.md b/README.md index 44177aa..ad833a5 100644 --- a/README.md +++ b/README.md @@ -21,16 +21,25 @@ Go library for generating and using One Time Passwords. Supports both HOTP ([RFC opts.Label = user key := otp.NewHOTPKey(opts) - // Store this string variable in your database keyURL := key.URL() + Store(user, keyURL) // Provide the URL to the customer so they can include it in their 2FA client. // Can email URL, or present QR code encoding of the URL } + // Store this string variable in your database + func Store(user, url string) { + + } + + // Retrieve the url string variable from your database + func GetURL(user string) string { + return "" + } + func CheckUsersCode(user string, code string) (bool, error) { - // Retrieve this string variable from your database - var keyURL string + keyURL := GetURL(user) key, err := otp.FromURL(keyURL) if err != nil { @@ -38,7 +47,7 @@ Go library for generating and using One Time Passwords. Supports both HOTP ([RFC } // Ensure you are using the correct key - if key.Label != user { + if key.Label() != user { return false, nil } @@ -48,11 +57,11 @@ Go library for generating and using One Time Passwords. Supports both HOTP ([RFC // Don't need this step for TOTP keys as the counter is time-based keyURL = key.URL() - - return success + return success, nil } + ### OTP Client import ( @@ -85,7 +94,7 @@ Go library for generating and using One Time Passwords. Supports both HOTP ([RFC } // Verify Issuer and Label are correct - if key.Issuer != issuer || key.Label != username { + if key.Issuer() != issuer || key.Label() != username { return "", nil } diff --git a/hotp_client_example_test.go b/hotp_client_example_test.go new file mode 100644 index 0000000..fcc117b --- /dev/null +++ b/hotp_client_example_test.go @@ -0,0 +1,58 @@ +package otp_test + +import ( + "fmt" + + "dev.justinjudd.org/justin/otp" +) + +// Just an example for storing OTP keys on the client +var keys map[Key]string + +// Key is used as keys for the otp key storing map +type Key struct { + Issuer, Label string +} + +func GetCode(issuer, username string) (string, error) { + + mapKey := Key{issuer, username} + + // Get the stored Key URL + keyURL, ok := keys[mapKey] + if !ok { + return "", nil + } + + // Build the key from the URL + key, err := otp.FromURL(keyURL) + if err != nil { + return "", err + } + + // Verify Issuer and Label are correct + if key.Issuer() != issuer || key.Label() != username { + return "", nil + } + + code := key.OTP() + + // If using HOTP, than need to save the state + keyURL = key.URL() + keys[mapKey] = keyURL + + return code, nil +} + +func Example_hOTPClient() { + issuer := "example.com" + username := "username" + + code, err := GetCode(issuer, username) + if err != nil { + // Handle error + } + + // Present code to user, or send code to server + fmt.Println(code) +} diff --git a/hotp_example_test.go b/hotp_example_test.go index 7f04f91..635a284 100644 --- a/hotp_example_test.go +++ b/hotp_example_test.go @@ -6,15 +6,15 @@ import ( "dev.justinjudd.org/justin/otp" ) -type Key struct { +type MapKey struct { Issuer, Label string } -var keys map[Key]string +var keysMap map[MapKey]string func CreateKey(issuer, username string) error { - mapKey := Key{issuer, username} - _, ok := keys[mapKey] + mapKey := MapKey{issuer, username} + _, ok := keysMap[mapKey] if ok { return fmt.Errorf("Key already exists for Issuer:%s, Label:%s", issuer, username) } @@ -23,14 +23,14 @@ func CreateKey(issuer, username string) error { opts.Label = username k := otp.NewHOTPKey(opts) - keys[mapKey] = k.URL() + keysMap[mapKey] = k.URL() return nil } func CheckCode(issuer, username, code string) bool { - mapKey := Key{issuer, username} - keyURL, ok := keys[mapKey] + mapKey := MapKey{issuer, username} + keyURL, ok := keysMap[mapKey] if !ok { return false } diff --git a/hotp_server_example_test.go b/hotp_server_example_test.go new file mode 100644 index 0000000..0c6eae6 --- /dev/null +++ b/hotp_server_example_test.go @@ -0,0 +1,78 @@ +package otp_test + +import ( + "dev.justinjudd.org/justin/otp" +) + +var Issuer = "example.com" + +func CreateKeyForUser(user string) { + + opts := otp.NewHOTPKeyOptions() + opts.Issuer = Issuer + opts.Label = user + key := otp.NewHOTPKey(opts) + + keyURL := key.URL() + Store(user, keyURL) + + // Provide the URL to the customer so they can include it in their 2FA client. + // Can email URL, or present QR code encoding of the URL +} + +// Store this string variable in your database +func Store(user, url string) { + +} + +// Retrieve the url string variable from your database +func GetURL(user string) string { + return "" +} + +// get the OTP code from the user +func getCode() string { + return "" +} + +func CheckUsersCode(user string, code string) (bool, error) { + keyURL := GetURL(user) + + key, err := otp.FromURL(keyURL) + if err != nil { + return false, err + } + + // Ensure you are using the correct key + if key.Label() != user { + return false, nil + } + + success := key.Verify(code) + + // Counter has been updated, update this info in the database + // Don't need this step for TOTP keys as the counter is time-based + keyURL = key.URL() + + return success, nil +} + +func Example_hOTPServer() { + + // Create new user + user := "username" + CreateKeyForUser(user) + + // When user is authenticating + // Perform password based auth - if that is successful, then continue + code := getCode() + success, err := CheckUsersCode(user, code) + if err != nil { + // Handle error + } + + if success { + // User is authenticated + } + +}