From 2dd94507937276cae93ca17a8518c12b55e8ae6e Mon Sep 17 00:00:00 2001
From: Jakob Borg <jakob@kastelo.net>
Date: Wed, 20 Sep 2017 21:34:32 +0200
Subject: [PATCH] lib/protocol, vendor: Import luhn code directly
I've changed it incompatibly to fix a correctness bug. Nonetheless, we
should remain incorrect indefinitely.
---
lib/protocol/deviceid.go | 5 ++-
lib/protocol/luhn.go | 53 ++++++++++++++++++++++++++++
lib/protocol/luhn_test.go | 48 ++++++++++++++++++++++++++
vendor/github.com/calmh/luhn/LICENSE | 19 ----------
vendor/github.com/calmh/luhn/luhn.go | 67 ------------------------------------
vendor/manifest | 8 -----
6 files changed, 103 insertions(+), 97 deletions(-)
create mode 100644 lib/protocol/luhn.go
create mode 100644 lib/protocol/luhn_test.go
delete mode 100644 vendor/github.com/calmh/luhn/LICENSE
delete mode 100644 vendor/github.com/calmh/luhn/luhn.go
diff --git a/lib/protocol/deviceid.go b/lib/protocol/deviceid.go
index df1cbdece..c2a30b286 100644
--- a/lib/protocol/deviceid.go
+++ b/lib/protocol/deviceid.go
@@ -10,7 +10,6 @@ import (
"fmt"
"strings"
- "github.com/calmh/luhn"
"github.com/syncthing/syncthing/lib/sha256"
)
@@ -158,7 +157,7 @@ func luhnify(s string) (string, error) {
for i := 0; i < 4; i++ {
p := s[i*13 : (i+1)*13]
copy(res[i*(13+1):], p)
- l, err := luhn.Base32.Generate(p)
+ l, err := luhnBase32.generate(p)
if err != nil {
return "", err
}
@@ -176,7 +175,7 @@ func unluhnify(s string) (string, error) {
for i := 0; i < 4; i++ {
p := s[i*(13+1) : (i+1)*(13+1)-1]
copy(res[i*13:], p)
- l, err := luhn.Base32.Generate(p)
+ l, err := luhnBase32.generate(p)
if err != nil {
return "", err
}
diff --git a/lib/protocol/luhn.go b/lib/protocol/luhn.go
new file mode 100644
index 000000000..ee5155f09
--- /dev/null
+++ b/lib/protocol/luhn.go
@@ -0,0 +1,53 @@
+// Copyright (C) 2014 The Protocol Authors.
+
+package protocol
+
+import (
+ "fmt"
+ "strings"
+)
+
+// An alphabet is a string of N characters, representing the digits of a given
+// base N.
+type luhnAlphabet string
+
+var (
+ luhnBase32 luhnAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
+)
+
+// generate returns a check digit for the string s, which should be composed
+// of characters from the Alphabet a.
+func (a luhnAlphabet) generate(s string) (rune, error) {
+ factor := 1
+ sum := 0
+ n := len(a)
+
+ for i := range s {
+ codepoint := strings.IndexByte(string(a), s[i])
+ if codepoint == -1 {
+ return 0, fmt.Errorf("Digit %q not valid in alphabet %q", s[i], a)
+ }
+ addend := factor * codepoint
+ if factor == 2 {
+ factor = 1
+ } else {
+ factor = 2
+ }
+ addend = (addend / n) + (addend % n)
+ sum += addend
+ }
+ remainder := sum % n
+ checkCodepoint := (n - remainder) % n
+ return rune(a[checkCodepoint]), nil
+}
+
+// luhnValidate returns true if the last character of the string s is correct, for
+// a string s composed of characters in the alphabet a.
+func (a luhnAlphabet) luhnValidate(s string) bool {
+ t := s[:len(s)-1]
+ c, err := a.generate(t)
+ if err != nil {
+ return false
+ }
+ return rune(s[len(s)-1]) == c
+}
diff --git a/lib/protocol/luhn_test.go b/lib/protocol/luhn_test.go
new file mode 100644
index 000000000..fe7f80c11
--- /dev/null
+++ b/lib/protocol/luhn_test.go
@@ -0,0 +1,48 @@
+// Copyright (C) 2014 The Protocol Authors.
+
+package protocol
+
+import (
+ "testing"
+)
+
+func TestGenerate(t *testing.T) {
+ // Base 6 Luhn
+ a := luhnAlphabet("abcdef")
+ c, err := a.generate("abcdef")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if c != 'e' {
+ t.Errorf("Incorrect check digit %c != e", c)
+ }
+
+ // Base 10 Luhn
+ a = luhnAlphabet("0123456789")
+ c, err = a.generate("7992739871")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if c != '3' {
+ t.Errorf("Incorrect check digit %c != 3", c)
+ }
+}
+
+func TestInvalidString(t *testing.T) {
+ a := luhnAlphabet("ABC")
+ _, err := a.generate("7992739871")
+ t.Log(err)
+ if err == nil {
+ t.Error("Unexpected nil error")
+ }
+}
+
+func TestValidate(t *testing.T) {
+ a := luhnAlphabet("abcdef")
+ if !a.luhnValidate("abcdefe") {
+ t.Errorf("Incorrect validation response for abcdefe")
+ }
+ if a.luhnValidate("abcdefd") {
+ t.Errorf("Incorrect validation response for abcdefd")
+ }
+}
diff --git a/vendor/github.com/calmh/luhn/LICENSE b/vendor/github.com/calmh/luhn/LICENSE
deleted file mode 100644
index 0e07d0e10..000000000
--- a/vendor/github.com/calmh/luhn/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (C) 2014 Jakob Borg
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/vendor/github.com/calmh/luhn/luhn.go b/vendor/github.com/calmh/luhn/luhn.go
deleted file mode 100644
index f09f3f298..000000000
--- a/vendor/github.com/calmh/luhn/luhn.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (C) 2014 Jakob Borg
-
-// Package luhn generates and validates Luhn mod N check digits.
-package luhn
-
-import (
- "fmt"
- "strings"
-)
-
-// An alphabet is a string of N characters, representing the digits of a given
-// base N.
-type Alphabet string
-
-var (
- Base32 Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
-)
-
-// Generate returns a check digit for the string s, which should be composed
-// of characters from the Alphabet a.
-func (a Alphabet) Generate(s string) (rune, error) {
- factor := 1
- sum := 0
- n := len(a)
-
- for i := range s {
- codepoint := strings.IndexByte(string(a), s[i])
- if codepoint == -1 {
- return 0, fmt.Errorf("Digit %q not valid in alphabet %q", s[i], a)
- }
- addend := factor * codepoint
- if factor == 2 {
- factor = 1
- } else {
- factor = 2
- }
- addend = (addend / n) + (addend % n)
- sum += addend
- }
- remainder := sum % n
- checkCodepoint := (n - remainder) % n
- return rune(a[checkCodepoint]), nil
-}
-
-// Validate returns true if the last character of the string s is correct, for
-// a string s composed of characters in the alphabet a.
-func (a Alphabet) Validate(s string) bool {
- t := s[:len(s)-1]
- c, err := a.Generate(t)
- if err != nil {
- return false
- }
- return rune(s[len(s)-1]) == c
-}
-
-// NewAlphabet converts the given string an an Alphabet, verifying that it
-// is correct.
-func NewAlphabet(s string) (Alphabet, error) {
- cm := make(map[byte]bool, len(s))
- for i := range s {
- if cm[s[i]] {
- return "", fmt.Errorf("Digit %q non-unique in alphabet %q", s[i], s)
- }
- cm[s[i]] = true
- }
- return Alphabet(s), nil
-}
diff --git a/vendor/manifest b/vendor/manifest
index 72d9c1c01..801a83ccb 100644
--- a/vendor/manifest
+++ b/vendor/manifest
@@ -50,14 +50,6 @@
"notests": true
},
{
- "importpath": "github.com/calmh/luhn",
- "repository": "https://github.com/calmh/luhn",
- "vcs": "git",
- "revision": "c0f1d77264fb3d1bfc65b70eea6ee264058c57c0",
- "branch": "master",
- "notests": true
- },
- {
"importpath": "github.com/calmh/xdr",
"repository": "https://github.com/calmh/xdr",
"vcs": "git",