github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/assertion_test.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package libkb 5 6 import ( 7 "fmt" 8 "strings" 9 "testing" 10 11 "github.com/stretchr/testify/require" 12 "golang.org/x/net/context" 13 ) 14 15 type testAssertionContext struct{} 16 17 func (t testAssertionContext) Ctx() context.Context { return context.Background() } 18 19 func (t testAssertionContext) NormalizeSocialName(service string, username string) (string, error) { 20 return strings.ToLower(username), nil 21 } 22 23 type testAlwaysFailAssertionContext struct{} 24 25 const failAssertionContextErr = "Unknown social network BECAUSE IT'S A TEST" 26 27 func (t testAlwaysFailAssertionContext) Ctx() context.Context { return context.Background() } 28 29 func (t testAlwaysFailAssertionContext) NormalizeSocialName(service string, username string) (string, error) { 30 return "", fmt.Errorf("%s: %s", failAssertionContextErr, service) 31 } 32 33 func TestUsername(t *testing.T) { 34 a := "max" 35 expr, err := AssertionParse(testAssertionContext{}, a) 36 require.NoError(t, err) 37 require.IsType(t, AssertionKeybase{}, expr) 38 require.Equal(t, expr.String(), a) 39 proofset := NewProofSet([]Proof{ 40 {"keybase", "max"}, 41 }) 42 require.True(t, expr.MatchSet(*proofset)) 43 } 44 45 func TestUsernameMultiple(t *testing.T) { 46 a := "max,chris" 47 expr, err := AssertionParse(testAssertionContext{}, a) 48 require.NoError(t, err) 49 50 usernameSet := func(username string) ProofSet { 51 return *NewProofSet([]Proof{ 52 {"keybase", username}, 53 }) 54 } 55 require.True(t, expr.MatchSet(usernameSet("max"))) 56 require.True(t, expr.MatchSet(usernameSet("chris"))) 57 require.False(t, expr.MatchSet(usernameSet("sam"))) 58 } 59 60 func TestSuccess1(t *testing.T) { 61 a := "web://maxk.org && twitter://maxtaco" 62 expr, err := AssertionParse(testAssertionContext{}, a) 63 proofs := NewProofSet([]Proof{ 64 {"http", "maxk.org"}, 65 {"reddit", "maxtaco"}, 66 {"twitter", "maxtaco"}, 67 }) 68 require.NoError(t, err) 69 require.True(t, expr.MatchSet(*proofs)) 70 } 71 72 func TestAssertions1(t *testing.T) { 73 a := "web://maxk.org && (https://foo.com || http://bar.com) && (bb@twitter || max || pgp://aabbcc) && (keybear@octodon.social || gubble.social:keybear)" 74 goodProofsets := []ProofSet{ 75 *NewProofSet([]Proof{ 76 {"dns", "maxk.org"}, 77 {"https", "bar.com"}, 78 {"twitter", "bb"}, 79 {"github", "xxx"}, 80 {"keybase", "yyy"}, 81 {"gubble.social", "keybear"}, 82 }), 83 *NewProofSet([]Proof{ 84 {"https", "maxk.org"}, 85 {"https", "foo.com"}, 86 {"keybase", "max"}, 87 {"octodon.social", "keybear"}, 88 }), 89 *NewProofSet([]Proof{ 90 {"http", "maxk.org"}, 91 {"https", "foo.com"}, 92 {"pgp", "00aabbcc"}, 93 {"gubble.social", "keybear"}, 94 }), 95 *NewProofSet([]Proof{ 96 {"http", "maxk.org"}, 97 {"https", "foo.com"}, 98 {"twitter", "bb"}, 99 {"octodon.social", "keybear"}, 100 }), 101 *NewProofSet([]Proof{ 102 {"http", "maxk.org"}, 103 {"http", "bar.com"}, 104 {"twitter", "bb"}, 105 {"octodon.social", "keybear"}, 106 }), 107 } 108 109 badProofsets := []ProofSet{ 110 *NewProofSet([]Proof{ 111 {"dns", "max.org"}, 112 {"http", "bar.com"}, 113 {"twitter", "bb"}, 114 {"github", "xxx"}, 115 {"keybase", "yyy"}, 116 {"gubble", "keybear"}, 117 }), 118 *NewProofSet([]Proof{ 119 {"https", "maxk.org"}, 120 {"http", "foo.com"}, 121 {"keybase", "maxi"}, 122 {"gubble.social", "keybase"}, 123 }), 124 *NewProofSet([]Proof{ 125 {"http", "maxk.org"}, 126 {"http", "foo.com"}, 127 {"pgp", "00aabbcc"}, 128 {"octodon.social", "keybase"}, 129 }), 130 *NewProofSet([]Proof{ 131 {"http", "maxk.org"}, 132 {"https", "foo.com"}, 133 }), 134 *NewProofSet([]Proof{ 135 {"http", "maxk.org"}, 136 {"https", "foo.com"}, 137 {"pgp", "00aabbcce"}, 138 {"pentagon.social", "keybear"}, 139 }), 140 *NewProofSet([]Proof{ 141 {"gubble.social", "keybear"}, 142 {"octodon.social", "keybear"}, 143 }), 144 } 145 expr, err := AssertionParse(testAssertionContext{}, a) 146 require.NoError(t, err) 147 for _, proofset := range goodProofsets { 148 require.True(t, expr.MatchSet(proofset)) 149 } 150 for _, proofset := range badProofsets { 151 require.False(t, expr.MatchSet(proofset)) 152 } 153 } 154 155 func TestAssertions2(t *testing.T) { 156 // Coyne-style grammar 157 a := "web:maxk.org+max,malgorithms+https:nutflex.com+pgp:aabbcc,samwise+dns:match.com" 158 goodProofsets := []ProofSet{ 159 *NewProofSet([]Proof{ 160 {"https", "maxk.org"}, 161 {"keybase", "max"}, 162 }), 163 *NewProofSet([]Proof{ 164 {"https", "nutflex.com"}, 165 {"pgp", "2233aabbcc"}, 166 {"keybase", "malgorithms"}, 167 }), 168 *NewProofSet([]Proof{ 169 {"keybase", "samwise"}, 170 {"dns", "match.com"}, 171 }), 172 } 173 expr, err := AssertionParse(testAssertionContext{}, a) 174 require.NoError(t, err) 175 for _, proofset := range goodProofsets { 176 require.True(t, expr.MatchSet(proofset), "matching to %+v", proofset) 177 } 178 } 179 180 func TestAssertions3(t *testing.T) { 181 a := "t_bob+twitter:kbtester1" 182 goodProofsets := []ProofSet{ 183 *NewProofSet([]Proof{ 184 {"twitter", "kbtester1"}, 185 {"keybase", "t_bob"}, 186 }), 187 } 188 expr, err := AssertionParseAndOnly(testAssertionContext{}, a) 189 require.NoError(t, err) 190 for _, proofset := range goodProofsets { 191 require.True(t, expr.MatchSet(proofset)) 192 } 193 } 194 195 func TestAssertions4(t *testing.T) { 196 // Coyne-style grammar (2), now with 100% more paramproof assertions 197 a := "alice@rooter+alice@cat.cafe+alice,https:nutflex.com+bob,jun@gubblers.eu+aabbcc@pgp" 198 goodProofsets := []ProofSet{ 199 *NewProofSet([]Proof{ 200 {"rooter", "alice"}, 201 {"cat.cafe", "alice"}, 202 {"keybase", "alice"}, 203 }), 204 *NewProofSet([]Proof{ 205 {"https", "nutflex.com"}, 206 {"keybase", "bob"}, 207 }), 208 *NewProofSet([]Proof{ 209 {"gubblers.eu", "jun"}, 210 {"pgp", "2233aabbcc"}, 211 }), 212 } 213 badProofsets := []ProofSet{ 214 *NewProofSet([]Proof{ 215 {"cat.cafe", "alice"}, 216 }), 217 *NewProofSet([]Proof{ 218 {"keybase", "bob"}, 219 }), 220 *NewProofSet([]Proof{ 221 {"gubblers.eu", "jun"}, 222 {"cat.cafe", "alice"}, // alice, no! your cat.cafe account got compromised! 223 }), 224 } 225 expr, err := AssertionParse(testAssertionContext{}, a) 226 require.NoError(t, err) 227 for _, proofset := range goodProofsets { 228 require.True(t, expr.MatchSet(proofset), "matching to %+v", proofset) 229 } 230 for _, proofset := range badProofsets { 231 require.False(t, expr.MatchSet(proofset), "matching to %+v", proofset) 232 } 233 } 234 235 func TestAssertionsUsernames(t *testing.T) { 236 exprs := []string{"x_", "A2", "ed", "bob", "o_o"} 237 fmts := []string{"%s", "%s@keybase", "keybase:%s"} 238 for _, str := range exprs { 239 for _, f := range fmts { 240 expr, err := AssertionParse(testAssertionContext{}, fmt.Sprintf(f, str)) 241 require.NoError(t, err) 242 require.IsType(t, AssertionKeybase{}, expr) 243 require.Equal(t, strings.ToLower(str), expr.String()) 244 } 245 } 246 } 247 248 func TestProofSetEmail(t *testing.T) { 249 exprs := []string{ 250 "[m@keybasers.de]@email", 251 "email:[m@keybasers.de]", 252 "email://[m@keybasers.de]", 253 } 254 proofset := *NewProofSet([]Proof{ 255 {"email", "m@keybasers.de"}, 256 }) 257 for _, expr := range exprs { 258 expr, err := AssertionParse(testAssertionContext{}, expr) 259 require.NoError(t, err) 260 require.Equal(t, "[m@keybasers.de]@email", expr.String()) 261 require.True(t, expr.MatchSet(proofset), "when checking %q", expr) 262 } 263 } 264 265 func TestEmailAssertions(t *testing.T) { 266 exprs := []string{ 267 "[m.a.x+2@kb.eu]@email", 268 "email:[h.e.l.l.o@kb.eu]", 269 "email://[test+spam@kb.eu]", 270 "email://[test+spam@kb.eu]+[other@example.com]@email", 271 } 272 for _, expr := range exprs { 273 _, err := AssertionParse(testAssertionContext{}, expr) 274 require.NoError(t, err) 275 } 276 } 277 278 func TestAssertionEmailsMultiple(t *testing.T) { 279 exprs := []string{ 280 "[m@keybasers.de]@email,max", 281 "max,[m@keybasers.de]@email", 282 "email:[m@keybasers.de],max", 283 "max,email:[m@keybasers.de]", 284 "max,email://[m@keybasers.de]", 285 "(max||[max@keybase.io]@email),email://[m@keybasers.de]", 286 } 287 goodProofsets := []ProofSet{ 288 *NewProofSet([]Proof{ 289 {"email", "m@keybasers.de"}, 290 }), 291 *NewProofSet([]Proof{ 292 {"keybase", "max"}, 293 }), 294 *NewProofSet([]Proof{ 295 {"email", "m@keybasers.de"}, 296 {"keybase", "m"}, 297 }), 298 } 299 badProofsets := []ProofSet{ 300 *NewProofSet([]Proof{ 301 {"keybase", "m"}, 302 }), 303 *NewProofSet([]Proof{ 304 {"https", "keybase.io"}, 305 }), 306 *NewProofSet([]Proof{ 307 {"http", "keybase.io"}, 308 }), 309 } 310 for _, expr := range exprs { 311 ret, err := AssertionParse(testAssertionContext{}, expr) 312 require.NoError(t, err, "when parsing %q", expr) 313 for _, proofset := range goodProofsets { 314 require.True(t, ret.MatchSet(proofset), "when checking %q with pset: %v", expr, proofset) 315 } 316 for _, proofset := range badProofsets { 317 require.False(t, ret.MatchSet(proofset), "when checking %q with pset: %v", expr, proofset) 318 } 319 } 320 } 321 322 func TestNeedsParens(t *testing.T) { 323 tests := []struct { 324 expr string 325 needsParens bool 326 }{ 327 {"max+foo@twitter,chris+chris@keybase", false}, 328 {"max+foo@twitter+(chris,bob)", true}, 329 {"max+foo@twitter+(chris)", false}, 330 {"max+foo@twitter+((chris))", false}, 331 {"max+foo@twitter+(chris+sam)", false}, 332 {"max", false}, 333 } 334 335 for _, test := range tests { 336 expr, err := AssertionParse(testAssertionContext{}, test.expr) 337 require.NoError(t, err) 338 require.Equal(t, expr.NeedsParens(), test.needsParens) 339 } 340 } 341 342 func TestAssertionCtxFailures(t *testing.T) { 343 a := "michal@twitter,mark@zapu.net" 344 _, err := AssertionParse(testAlwaysFailAssertionContext{}, a) 345 require.Error(t, err) 346 require.Contains(t, err.Error(), failAssertionContextErr) 347 require.Contains(t, err.Error(), "zapu.net") 348 }