1// Copyright 2015 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4package libkb 5 6import ( 7 "fmt" 8 "regexp" 9 "strings" 10 "unicode" 11 12 "github.com/keybase/client/go/kbun" 13) 14 15var emailRE = regexp.MustCompile(`^\S+@\S+\.\S+$`) 16 17// Also used in shared/signup/device-name/index.tsx 18var deviceRE = regexp.MustCompile(`^[a-zA-Z0-9][ _'a-zA-Z0-9+‘’—–-]*$`) 19var badDeviceRE = regexp.MustCompile(` |[ '_-]$|['_-][ ]?['_-]`) 20var normalizeDeviceRE = regexp.MustCompile(`[^a-zA-Z0-9]`) 21 22var CheckEmail = Checker{ 23 F: func(s string) bool { 24 return len(s) > 3 && emailRE.MatchString(s) 25 }, 26 Hint: "must be a valid email address", 27} 28 29var CheckUsername = Checker{ 30 F: kbun.CheckUsername, 31 Hint: "between 2 and 16 characters long", 32} 33 34var CheckEmailOrUsername = Checker{ 35 F: func(s string) bool { 36 return CheckEmail.F(s) || CheckUsername.F(s) 37 }, 38 Hint: "valid usernames are 2-16 letters long", 39} 40 41var CheckPassphraseSimple = Checker{ 42 F: func(s string) bool { 43 return len(s) > 0 44 }, 45 Hint: "passphrase cannot be empty", 46} 47 48var CheckPassphraseNew = Checker{ 49 F: func(s string) bool { 50 r := []rune(s) 51 if len(r) > 0 && unicode.IsSpace(r[0]) { 52 return false 53 } 54 return len(s) >= MinPassphraseLength 55 }, 56 Hint: fmt.Sprintf("passphrase must be %d or more characters", MinPassphraseLength), 57 PreserveSpace: true, 58} 59 60var CheckInviteCode = Checker{ 61 F: func(s string) bool { 62 return len(s) > 4 63 }, 64 Hint: "Invite codes are 4 or more characters", 65} 66 67func normalizeDeviceName(s string) string { 68 return strings.ToLower(normalizeDeviceRE.ReplaceAllString(s, "")) 69} 70 71var CheckDeviceName = Checker{ 72 F: func(s string) bool { 73 normalized := normalizeDeviceName(s) 74 75 return len(normalized) >= 3 && 76 len(normalized) <= 64 && 77 deviceRE.MatchString(s) && 78 !badDeviceRE.MatchString(s) 79 }, 80 Transform: func(s string) string { 81 s = strings.Replace(s, "—", "-", -1) // em dash 82 s = strings.Replace(s, "–", "-", -1) // en dash 83 s = strings.Replace(s, "‘", "'", -1) // curly quote #1 84 s = strings.Replace(s, "’", "'", -1) // curly quote #2 85 return s 86 }, 87 Normalize: normalizeDeviceName, 88 Hint: "between 3 and 64 characters long; use a-Z, 0-9, space, plus, underscore, dash and apostrophe", 89} 90 91func MakeCheckKex2SecretPhrase(g *GlobalContext) Checker { 92 return Checker{ 93 F: func(s string) bool { 94 if err := validPhrase(s, []int{Kex2PhraseEntropy, Kex2PhraseEntropy2}); err != nil { 95 g.Log.Debug("invalid kex2 phrase: %s", err) 96 return false 97 } 98 return true 99 }, 100 Hint: "Wrong secret phrase. Please try again.", 101 } 102} 103 104func IsYes(s string) bool { 105 s = strings.ToLower(strings.TrimSpace(s)) 106 return s == "y" || s == "yes" 107} 108 109func IsEmpty(s string) bool { 110 return len(strings.TrimSpace(s)) == 0 111} 112 113func IsNo(s string) bool { 114 s = strings.ToLower(strings.TrimSpace(s)) 115 return s == "n" || s == "no" 116} 117 118var CheckYesNo = Checker{ 119 F: func(s string) bool { 120 return IsYes(s) || IsNo(s) 121 }, 122 Hint: "'yes' or 'no'", 123} 124 125var CheckNotEmpty = Checker{ 126 F: func(s string) bool { 127 return len(s) > 0 128 }, 129 Hint: "cannot be empty", 130} 131 132type CheckMember struct { 133 Set []string 134} 135 136func (c CheckMember) Checker() Checker { 137 return Checker{ 138 F: func(s string) bool { 139 for _, v := range c.Set { 140 if Cicmp(v, s) { 141 return true 142 } 143 } 144 return false 145 }, 146 Hint: strings.Join(c.Set, ", "), 147 } 148} 149