/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/pvl/interp_test.go
2 402 строки
55 KB
chrisnojima-zoom
Version 670 - clean2 (#29122)
08 июн 2026, 19:31
Не верифицирован
08 июн 2026, 19:31
1943197
Код
Авторство
О чём код?
// Copyright 2016 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package pvl import ( "fmt" "strings" "testing" "github.com/PuerkitoBio/goquery" libkb "github.com/keybase/client/go/libkb" keybase1 "github.com/keybase/client/go/protocol/keybase1" jsonw "github.com/keybase/go-jsonw" ) type interpUnitTest struct { name string proofinfo ProofInfo // Only one of prepvl or prepvlstr should be specified. prepvl map[keybase1.ProofType]string prepvlstr string service keybase1.ProofType // What api call to expect (for non-DNS) restype libkb.XAPIResType resjson string reshtml string restext string resdns map[string]([]string) // (Optional) Expect a different url to be fetched than proofinfo.APIURL urloverride string // (Optional) Don't check that the xapi was hit exactly once. allowmanyfetches bool // Whether the proof should validate shouldwork bool // (Optional) error status must equal. Must be specified for INVALID_PVL errstatus keybase1.ProofStatus // (Optional) error string must equal errstr string } var interpUnitTests = []interpUnitTest{ // There are a lot of these tests in a line. // They are organized into sections with markdown-style headings. // All tests are run by the single runPvlTest function. If you want to run // just one test, set the `solo` variable there. // # Basic tests { name: "basichtml", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_TWITTER: `[[ {"assert_regex_match": { "pattern": "^https://rooter\\.example\\.com/proofs/%{username_service}/[\\d]+\\.htjsxt$", "from": "hint_url" } }, {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": [".twit", 0], "into": "tmp1" } }, {"whitespace_normalize": { "from": "tmp1", "into": "tmp2" } }, {"assert_regex_match": { "pattern": "^.*goodproof.*$", "from": "tmp2" } } ]]`, }, service: keybase1.ProofType_TWITTER, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: true, }, // # Tests for individual valid instructions. // Test match and fail of each instruction. // ## AssertRegexMatch { name: "AssertRegexMatch-url-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_COINBASE: `[[ {"assert_regex_match": { "pattern": "^https://rooter\\.example\\.com/proofs/%{username_service}/[\\d]+\\.htjsxt$", "from": "hint_url" } }, {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_COINBASE, restype: libkb.XAPIResText, restext: "1234", shouldwork: true, }, { name: "AssertRegexMatch-url-fail", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_HACKERNEWS: `[[ {"assert_regex_match": { "pattern": "^https://rooter\\.example\\.com/proofs/%{username_service}/+\\.htjsxt$", "from": "hint_url" } }, {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_HACKERNEWS, restype: libkb.XAPIResText, restext: "1234", shouldwork: false, }, { name: "AssertRegexMatch-content-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_REDDIT: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": [".twit", -1], "into": "tmp1" } }, {"whitespace_normalize": { "from": "tmp1", "into": "tmp2" }}, {"assert_regex_match": { "pattern": "^short %{sig_id_short}$", "from": "tmp2" } } ]]`, }, service: keybase1.ProofType_REDDIT, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: true, }, { name: "AssertRegexMatch-content-fail", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_TWITTER: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": [".twit", -1], "into": "tmp1" } }, {"whitespace_normalize": { "from": "tmp1", "into": "tmp2" } }, {"assert_regex_match": { "pattern": "^wrong %{sig_id_short}$", "from": "tmp2" } } ]]`, }, service: keybase1.ProofType_TWITTER, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, }, { name: "AssertRegexMatch-content-fail-case", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_TWITTER: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": [".twit", -1], "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^.*SHORT.*$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_TWITTER, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, }, { name: "AssertRegexMatch-negate-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_COINBASE: `[[ {"assert_regex_match": { "pattern": "^.*notacommonstringatall.*$", "from": "hint_url", "negate": true } }, {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_COINBASE, restype: libkb.XAPIResText, restext: "1234", shouldwork: true, }, { name: "AssertRegexMatch-negate-fail", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_COINBASE: `[[ {"assert_regex_match": { "pattern": "^.*rooter.*$", "negate": true, "from": "hint_url" } }, {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_COINBASE, restype: libkb.XAPIResText, restext: "1234", shouldwork: false, }, // ## AssertFindBase64 { name: "AssertFindBase64-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_find_base64": { "needle": "sig", "haystack": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, // the sig must be on a line with only spacing. restext: fmt.Sprintf(" asdf\n \t\t .\n %v\t\nzad\t.\n", sig1), shouldwork: true, }, { name: "AssertFindBase64-fail", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_find_base64": { "needle": "sig", "haystack": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: sig1[1:], shouldwork: false, }, // ## AssertCompare { name: "AssertCompare-cicmp-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_compare": { "cmp": "cicmp", "a": "username_keybase", "b": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "krONK", shouldwork: true, }, { name: "AssertCompare-cicmp-fail", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_compare": { "cmp": "cicmp", "a": "username_keybase", "b": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "kr0nk", shouldwork: false, }, { name: "AssertCompare-stripdots-then-cicmp-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_compare": { "cmp": "stripdots-then-cicmp", "a": "username_keybase", "b": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "kr.O..NK", shouldwork: true, }, { name: "AssertCompare-stripdots-then-cicmp-fail", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_compare": { "cmp": "stripdots-then-cicmp", "a": "username_keybase", "b": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "kr0nk", shouldwork: false, }, { name: "AssertCompare-exact-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_compare": { "cmp": "exact", "a": "username_keybase", "b": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "kronk", shouldwork: true, }, { name: "AssertCompare-exact-fail", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_compare": { "cmp": "exact", "a": "username_keybase", "b": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "kroNk", shouldwork: false, }, // ## RegexCapture and WhitespaceNormalize tested together { name: "RegexCapture-ok-ignoregroup", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["div.twit", -1], "into": "tmp1" } }, {"whitespace_normalize": { "from": "tmp1", "into": "tmp2" } }, {"regex_capture": { "pattern": "^(?:sHoRt) ([A-Za-z0-9+/=]+)$", "case_insensitive": true, "from": "tmp2", "into": ["tmp3"] } }, {"assert_regex_match": { "pattern": "^%{sig_id_short}$", "from": "tmp3" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: true, }, { // A repeated capture group returns its last match. name: "RegexCapture-ok-multimatch", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["div.twit", -1], "into": "tmp1" } }, {"whitespace_normalize": { "from": "tmp1", "into": "tmp2" } }, {"regex_capture": { "pattern": "^(short).*$", "from": "tmp2", "into": ["tmp3"] } }, {"regex_capture": { "pattern": "^(\\w)+$", "from": "tmp3", "into": ["tmp4"] } }, {"assert_regex_match": { "pattern": "^t$", "from": "tmp4" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: true, }, { // Capturing into multiple variables // also more capture groups than 'into' variables name: "RegexCapture-ok-multi-capture", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"regex_capture": { "pattern": "^(\\w) (\\w) (\\w) (\\w) (\\w).*$", "from": "tmp1", "into": ["a", "b", "c"] } }, {"assert_regex_match": { "pattern": "^%{a} %{b} %{c} d e f$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "a b c d e f", shouldwork: true, }, { // Less capture groups than `into` variables name: "RegexCapture-ok-multi-capture", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"regex_capture": { "pattern": "^(\\w) (\\w) .*$", "from": "tmp1", "into": ["a", "b", "c"] } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "a b c d e f", shouldwork: false, }, { name: "RegexCapture-fail-nomatch", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["div.twit", -1], "into": "tmp1" } }, {"regex_capture": { "pattern": "^(nowhere)$", "case_insensitive": true, "from": "tmp1", "into": ["tmp2"] } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, }, { name: "RegexCapture-fail-nogroup", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["div.twit", -1], "into": "tmp1" } }, {"whitespace_normalize": { "from": "tmp1", "into": "tmp2" } }, {"regex_capture": { "pattern": "^sHoRt.*$", "case_insensitive": true, "from": "tmp2", "into": ["tmp3"] } }, {"assert_regex_match": { "pattern": "^%{sig_id_short}$/s", "from": "tmp3" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, }, // ## ReplaceAll { name: "ReplaceAll-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "a" } }, {"replace_all": { "old": "foo", "new": "pow", "from": "a", "into": "b" } }, {"assert_regex_match": { "pattern": "^pow bar powz barz$", "from": "b" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "foo bar fooz barz", shouldwork: true, }, { name: "ReplaceAll-ok-no-matches", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "a" } }, {"replace_all": { "old": "foo", "new": "pow", "from": "a", "into": "b" } }, {"assert_regex_match": { "pattern": "^%{a}$", "from": "b" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "glue bar gluez barz", shouldwork: true, }, { // Test unescaping the weird escaping that facebook comments use. name: "ReplaceAll-ok-facebook", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"replace_all": { "old": "-\\-\\", "new": "--", "from": "tmp1", "into": "tmp2" } }, {"replace_all": { "old": "\\\\", "new": "\\", "from": "tmp2", "into": "tmp3" } }, {"assert_regex_match": { "pattern": "^double -- back \\\\$", "from": "tmp3" } }, {"fill": { "with": "double -- back \\", "into": "ref" } }, {"assert_compare": { "cmp": "exact", "a": "tmp3", "b": "ref" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "double -\\-\\ back \\\\", shouldwork: true, }, // ## ParseURL { name: "ParseURL-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"parse_url": { "from": "tmp1", "path": "path", "host": "host", "scheme": "scheme" } }, {"assert_regex_match": { "pattern": "^/noodle$", "from": "path" } }, {"assert_regex_match": { "pattern": "^digg.example.com$", "from": "host" } }, {"assert_regex_match": { "pattern": "^http$", "from": "scheme" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "http://digg.example.com/noodle", shouldwork: true, }, { name: "ParseURL-fail", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"parse_url": { "from": "tmp1", "path": "path" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "htj0*#)%*J)*H^dle", shouldwork: false, }, // ## Fetch { name: "Fetch-string", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^str9\n$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "str9\n", shouldwork: true, }, { name: "Fetch-html", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["head title"], "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^proofer$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: true, }, { name: "Fetch-json", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": ["data", 2, "type"], "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^useful$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: true, }, // ## ParseHTML { name: "ParseHTML-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"parse_html": { "from": "tmp1" } }, {"selector_css": { "selectors": ["p", 2], "into": "tmp2" } }, {"assert_regex_match": { "pattern": "^c$", "from": "tmp2" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "<p>a</p><p>b</p><p>c</p>", shouldwork: true, }, // ## SelectorJSON { name: "SelectorJSON-simple", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": ["data", 2, "type"], "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^useful$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: true, }, { name: "SelectorJSON-index-dne", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": ["data", 500], "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: false, }, { name: "SelectorJSON-key-dne", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": ["data", "a500"], "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: false, }, { name: "SelectorJSON-index-neg", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": ["data", -1, "poster"], "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^eve$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: true, }, { name: "SelectorJSON-index-all", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": ["data", {"all": true }, "poster"], "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^kronk eve$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: true, }, { // Index into a non-array name: "SelectorJSON-index-nonarray", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": ["data", {"all": true }, "extra", 0, 0], "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^4$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: true, }, // ## SelectorCSS { name: "SelectorCSS-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["body .twit", -1], "into": "tmp1" } }, {"whitespace_normalize": { "from": "tmp1", "into": "tmp2" } }, {"assert_regex_match": { "pattern": "^short %{sig_id_short}$", "from": "tmp2" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: true, }, { name: "SelectorCSS-fail-dontcrash", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["body .twit:eq(0)"], "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, }, { name: "SelectorCSS-ok-multi", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["body .twit"], "multi": true, "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^[\\s\\S]*goodproof[\\s\\S]*evil\\.com[\\s\\S]*short[\\s\\S]*$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: true, }, { name: "SelectorCSS-fail-nonmulti", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["body .twit"], "into": "tmp1" } }, {"whitespace_normalize": { "from": "tmp1", "into": "tmp2" } }, {"assert_regex_match": { "pattern": "^short %{sig_id_short}$", "from": "tmp2" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, }, { name: "SelectorCSS-ok-attr", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["body .twit[data-x]"], "attr": "data-x", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^y$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: true, }, { name: "SelectorCSS-ok-attr-dne", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": ["body .twit"], "multi": true, "attr": "dne", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: true, }, { name: "SelectorCSS-ok-contents", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": [".a .b", {"contents": true}], "multi": true, "data": true, "into": "tmp1" } }, {"whitespace_normalize": { "from": "tmp1", "into": "tmp2" } }, {"replace_all": { "old": " ", "new": "", "from": "tmp2", "into": "tmp3" } }, {"assert_regex_match": { "pattern": "^cowabunga$", "from": "tmp3" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html2, shouldwork: true, }, // ## Fill { name: "Fill-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"fill": { "with": "%{tmp1}-%{username_keybase}", "into": "tmp2" } }, {"assert_regex_match": { "pattern": "^foozle-kronk$", "from": "tmp2" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "foozle", shouldwork: true, }, { name: "Fill-ok-noregexesc", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"fill": { "with": "%{tmp1}-%{username_keybase}", "into": "tmp2" } }, {"assert_regex_match": { "pattern": "^\\(x\\)-kronk$", "from": "tmp2" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "(x)", shouldwork: true, }, // # Tests for invalid PVL at the top level { name: "omitted-service", proofinfo: info1, // Empty service entries should fail. prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_TWITTER: `[[ {"fetch": { "kind": "html", "from": "hint_url" } } ]]`, }, // GITHUB here isn't TWITTER service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "omitted-version", proofinfo: info1, prepvlstr: `{"revision": 1, "services": {}}`, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "omitted-revision", proofinfo: info1, prepvlstr: `{"pvl_version": 1, "services": {}}`, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "bad-services", proofinfo: info1, prepvlstr: `{"pvl_version": 1, "revision": 2, "services": []}`, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "non-array-script", proofinfo: info1, prepvlstr: `{"pvl_version": 1, "revision": 2, "services": {"github": "bad"}}`, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "empty-script", proofinfo: info1, prepvlstr: `{"pvl_version": 1, "revision": 2, "services": {"github": [[]]}}`, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "empty-script-multi", proofinfo: info1, prepvlstr: `{"pvl_version": 1, "revision": 2, "services": {"github": [[], []]}}`, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "no-scripts", proofinfo: info1, prepvlstr: `{"pvl_version": 1, "revision": 2, "services": {"github": []}}`, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, // ## Tests for bad proofinfo { name: "bad-sig-path-in-domain-web", proofinfo: infoBadDomain, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_BAD_SIGNATURE, }, { name: "bad-sig-path-in-domain-dns", proofinfo: infoBadDomain, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_DNS: `[[ {"assert_regex_match": { "pattern": "^foo$", "from": "hint_url" } } ]]`, }, service: keybase1.ProofType_DNS, resdns: map[string][]string{ info1.Hostname: {"NO", "ok"}, }, shouldwork: false, errstatus: keybase1.ProofStatus_BAD_SIGNATURE, }, { name: "bad-sig-proto", proofinfo: infoBadProto, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_BAD_SIGNATURE, }, { name: "bad-sig-sig", proofinfo: infoBadSig, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_BAD_SIGNATURE, }, // ## (Invalid) AssertRegexMatch { name: "AssertRegexMatch-invalid-missing^", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "foobar$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "AssertRegexMatch-invalid-missing$", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^foobar", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "AssertRegexMatch-invalid-badvar", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^%{hostname}$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "AssertRegexMatch-invalid-redesc", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": ["^foobar$"], "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "AssertRegexMatch-invalid-badre", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^foo)(bar$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, // ## (Invalid) AssertFindBase64 { name: "AssertFindBase64-invalid-badtarget", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_find_base64": { "needle": "username_keybase", "haystack": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "foobar", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, // ## (Invalid) AssertCompare { name: "AssertCompare-invalid-strategy", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_compare": { "cmp": "", "a": "username_keybase", "b": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "krONK", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "AssertCompare-invalid-noa", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GENERIC_WEB_SITE: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_compare": { "cmp": "", "a": "", "b": "tmp1" } } ]]`, }, service: keybase1.ProofType_GENERIC_WEB_SITE, restype: libkb.XAPIResText, restext: "krONK", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, // ## (Invalid) WhitespaceNormalize // No tests // ## (Invalid) RegexCapture // Mostly the same as AssertRegexMatch { name: "RegexCapture-invalid-missing^", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"regex_capture": { "pattern": "(f)oobar$", "from": "tmp1", "into": ["tmp2"] } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "RegexCapture-invalid-missing$", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"regex_capture": { "pattern": "^(f)oobar", "from": "tmp1", "into": ["tmp2"] } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "RegexCapture-invalid-badvar", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"regex_capture": { "pattern": "^(%{hostname})$", "from": "tmp1", "into": ["tmp2"] } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "RegexCapture-invalid-redesc", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"regex_capture": { "pattern": ["^(f)oobar$"], "from": "tmp1", "into": ["tmp2"] } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "fuzztroo", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, // ## (Invalid) ParseURL { name: "ParseURL-invalid-missing-from", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"parse_url": { "path": "path" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "http://example.com/", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, // ## (Invalid) ReplaceAll // No tests // ## (Invalid) Fetch { name: "Fetch-invalid-type", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "whatsthis", "from": "hint_url" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "foobar", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "Fetch-invalid-indns", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_DNS: `[[ {"fetch": { "kind": "whatsthis", "from": "hint_url" } } ]]`, }, service: keybase1.ProofType_DNS, restype: libkb.XAPIResText, restext: "foobar", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "Fetch-invalid-multiple", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp2" } }, {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp2" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "foobar", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, // ## (Invalid) ParseHTML // No tests // ## (Invalid) SelectorJSON { name: "SelectorJSON-invalid-scripttype", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"selector_json": { "selectors": [0], "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "foobar", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "SelectorJSON-invalid-selectorlist", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": 0 } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "SelectorJSON-invalid-empty", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": [], "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "SelectorJSON-invalid-contents", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": [{"contents": true}], "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "SelectorJSON-invalid-spec", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_json": { "selectors": [{"foo": "bar" }], "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, // ## (Invalid) SelectorCSS { name: "SelectorCSS-invalid-scripttype", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "json", "from": "hint_url" } }, {"selector_css": { "selectors": [0], "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResJSON, resjson: json1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "SelectorCSS-invalid-selectorlist", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": 0 }, "into": "tmp1" } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "SelectorCSS-invalid-empty", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html", "from": "hint_url" } }, {"selector_css": { "selectors": [], "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "SelectorCSS-invalid-spec", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "html" } }, {"selector_css": { "selectors": [{"foo": "bar" }], "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResHTML, reshtml: html1, shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, // ## (Invalid) Fill { name: "Fill-invalid-badreg", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"fill": { "with": "%{hostname}", "into": "tmp2" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "foozle", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "Fill-invalid-overwrite", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"fill": { "with": "yeck", "into": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "foozle", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, // # Multiple Scripts { name: "MultipleScripts-first-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_FACEBOOK: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^ok$", "from": "tmp1" } } ], [ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^NO$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_FACEBOOK, restype: libkb.XAPIResText, restext: "ok", shouldwork: true, }, { name: "MultipleScripts-second-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_FACEBOOK: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^NO$", "from": "tmp1" } } ], [ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^ok$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_FACEBOOK, restype: libkb.XAPIResText, restext: "ok", allowmanyfetches: true, shouldwork: true, }, { name: "MultipleScripts-both-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_FACEBOOK: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^ok$", "from": "tmp1" } } ], [ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^ok", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_FACEBOOK, restype: libkb.XAPIResText, restext: "ok", shouldwork: true, }, { name: "MultipleScripts-both-fail", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_FACEBOOK: `[[ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^NO$", "error": ["HOST_UNREACHABLE", "x"], "from": "tmp1" } } ], [ {"fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, {"assert_regex_match": { "pattern": "^NO$", "error": ["HOST_UNREACHABLE", "x"], "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_FACEBOOK, restype: libkb.XAPIResText, restext: "ok", shouldwork: false, errstatus: keybase1.ProofStatus_HOST_UNREACHABLE, }, // # DNS tests // Checking a DNS proof is different from checking other proofs. // It runs each script against each TXT record of 2 domains. // That mechanism is tested here. { name: "DNS-second-record-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_DNS: `[[ {"assert_regex_match": { "pattern": "^ok$", "from": "txt" } } ]]`, }, service: keybase1.ProofType_DNS, resdns: map[string][]string{ info1.Hostname: {"NO", "ok"}, }, shouldwork: true, }, { name: "DNS-_keybase-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_DNS: `[[ {"assert_regex_match": { "pattern": "^ok$", "from": "txt" } } ]]`, }, service: keybase1.ProofType_DNS, resdns: map[string][]string{ info1.Hostname: {"NO_1", "NO_2"}, "_keybase." + info1.Hostname: {"NO_3", "ok"}, }, shouldwork: true, }, { name: "DNS-no-records", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_DNS: `[[ {"assert_regex_match": { "pattern": "^ok$", "from": "txt" } } ]]`, }, service: keybase1.ProofType_DNS, resdns: map[string][]string{ info1.Hostname: {}, "_keybase." + info1.Hostname: {}, }, shouldwork: false, }, { name: "DNS-no-matching-records", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_DNS: `[[ {"assert_regex_match": { "pattern": "^ok$", "from": "txt" } } ]]`, }, service: keybase1.ProofType_DNS, resdns: map[string][]string{ info1.Hostname: {"NO_1"}, "_keybase." + info1.Hostname: {"NO_2", "NO_3"}, }, shouldwork: false, }, { name: "DNS-error-then-succeed", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_DNS: `[[ {"assert_regex_match": { "pattern": "^ok$", "from": "txt" } } ]]`, }, service: keybase1.ProofType_DNS, resdns: map[string][]string{ info1.Hostname: {"ERROR"}, "_keybase." + info1.Hostname: {"ok"}, }, shouldwork: true, }, { name: "DNS-error-then-succeed-2", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_DNS: `[[ {"assert_regex_match": { "pattern": "^ok1$", "from": "txt" } } ], [ {"assert_regex_match": { "pattern": "^ok2$", "from": "txt" } } ]]`, }, service: keybase1.ProofType_DNS, resdns: map[string][]string{ info1.Hostname: {"NO_1", "ok2"}, }, shouldwork: true, }, // # Custom Errors { name: "CustomError-ok", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ { "fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, { "assert_regex_match": { "pattern": "^foo$", "error": ["PERMISSION_DENIED", "whoops!"], "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "bar", shouldwork: false, errstatus: keybase1.ProofStatus_PERMISSION_DENIED, errstr: "whoops!", }, { name: "CustomError-wrong-short-array", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ { "fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, { "assert_regex_match": { "pattern": "^foo$", "error": ["PERMISSION_DENIED"], "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "bar", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "CustomError-wrong-type1", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ { "fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, { "assert_regex_match": { "pattern": "^foo$", "error": 108, "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "bar", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { name: "CustomError-wrong-type2", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ { "fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, { "assert_regex_match": { "pattern": "^foo$", "error": ["TIMEOUT", []], "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "bar", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { // A custom error should not affect invalidity. // Here the regex contains invalid var name. name: "CustomError-and-invalid", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ { "fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, { "assert_regex_match": { "pattern": "^%{invalid}$", "error": ["PERMISSION_DENIED", "whoops"], "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "bar", shouldwork: false, errstatus: keybase1.ProofStatus_INVALID_PVL, }, { // Without a custom error, a default will appear. name: "CustomError-none", proofinfo: info1, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_GITHUB: `[[ { "fetch": { "kind": "string", "from": "hint_url", "into": "tmp1" } }, { "assert_regex_match": { "pattern": "^foo$", "from": "tmp1" } } ]]`, }, service: keybase1.ProofType_GITHUB, restype: libkb.XAPIResText, restext: "bar", shouldwork: false, errstatus: keybase1.ProofStatus_CONTENT_FAILURE, errstr: "Regex did not match (^foo$)", }, { name: "TwitterOEmbed-accepts-xcom", proofinfo: infoTwitterX, prepvl: map[keybase1.ProofType]string{ keybase1.ProofType_TWITTER: `[[ {"regex_capture": { "pattern": "^https://(?:twitter|x)\\.com/([^/]+)/status/(\\d+)(.*)$", "from": "hint_url", "into": ["username_from_url", "tweet_id", "remainder"] } }, {"assert_compare": { "cmp": "cicmp", "a": "username_from_url", "b": "username_service" } }, {"fill": { "with": "https://api.twitter.com/1/statuses/oembed.json?id=%{tweet_id}", "into": "our_url" } }, {"fetch": { "from": "our_url", "kind": "json" } }, {"selector_json": { "selectors": ["author_url"], "into": "author_url" } }, {"regex_capture": { "pattern": "^https://(?:twitter|x)\\.com/(.+)$", "from": "author_url", "into": ["author_username"] } }, {"assert_compare": { "cmp": "cicmp", "a": "author_username", "b": "username_service" } } ]]`, }, service: keybase1.ProofType_TWITTER, restype: libkb.XAPIResJSON, urloverride: "https://api.twitter.com/1/statuses/oembed.json?id=5", resjson: `{"author_url":"https://x.com/kronkinator","html":"<blockquote><p>Verifying myself: I am kronk on Keybase.io. 9JHQ8ZNOFRORQUpmH0jLbNbFClOccMEghH5l /</p></blockquote>"}`, shouldwork: true, }, } func TestUnits(t *testing.T) { solo := "" for _, unit := range interpUnitTests { if len(solo) == 0 || unit.name == solo { t.Logf("Testing: %v", unit.name) runPvlTest(t, &unit) } } if len(solo) > 0 { // Soloing a test shall never be checked in. t.Fatalf("soloed a test that passed\n\n\n*\n*\n*\n*\n*\n*\n*") } } type failer func(string, ...any) func runPvlTest(t *testing.T, unit *interpUnitTest) { tc := libkb.SetupTest(t, unit.name, 1) defer tc.Cleanup() fail := func(f string, arg ...any) { f2 := fmt.Sprintf("[%v] ", unit.name) + f t.Fatalf(f2, arg...) } g := tc.G xapi := newStubAPIEngine() g.XAPI = xapi var pvl string var err error switch { case (unit.prepvl == nil) == (unit.prepvlstr == ""): fail("one of prepvl or prepvlstr must be specified") case unit.prepvlstr == "": pvl, err = makeTestPvl(unit.prepvl) if err != nil { fail("Error in prepvl: %v", err) } default: pvl = unit.prepvlstr } url := unit.proofinfo.APIURL if unit.urloverride != "" { url = unit.urloverride } isdns := unit.service == keybase1.ProofType_DNS if isdns { unit.proofinfo.stubDNS = newStubDNSEngine(unit.resdns) } else { switch unit.restype { case libkb.XAPIResJSON: xapi.Set(url, newExternalJSONRes(unit.resjson, fail)) case libkb.XAPIResHTML: xapi.SetHTML(url, newExternalHTMLRes(unit.reshtml, fail)) case libkb.XAPIResText: xapi.SetText(url, newExternalTextRes(unit.restext, fail)) default: fail("unsupported restype: %v", unit.restype) } } m := libkb.NewMetaContextForTest(tc) perr := CheckProof(m, pvl, unit.service, unit.proofinfo) if perr == nil { if !unit.shouldwork { fail("proof should have failed") } // err is definitely nil here. if isdns { if !unit.proofinfo.stubDNS.IsOk() { fail("DNS stub ran out of bounds") } } else { if unit.allowmanyfetches { err = xapi.AssertCalledWith(unit.restype, url) } else { err = xapi.AssertCalledOnceWith(unit.restype, url) } if err != nil { fail("%v", err) } } } else { if unit.shouldwork { fail("proof failed: %v", perr) } none := keybase1.ProofStatus_NONE if unit.errstatus != none && perr.GetProofStatus() != unit.errstatus { fail("status mismatch:\n expected: %v\n got: %v", unit.errstatus, perr.GetProofStatus()) } if len(unit.errstr) > 0 && unit.errstr != perr.GetDesc() { fail("status mismatch:\n expected: %v\n got: %v", unit.errstr, perr.GetDesc()) } if unit.errstatus == none && perr.GetProofStatus() == keybase1.ProofStatus_INVALID_PVL { fail("unexpected INVALID_PVL:\n expected: %v\n got: %v", unit.errstatus, perr.Error()) } } } func makeTestPvl(rules map[keybase1.ProofType]string) (string, error) { var pvl string services := jsonw.NewDictionary() for ptype, v1 := range rules { var err error ptypestr, err := serviceToString(ptype) if err != nil { return pvl, err } v2, err := jsonw.Unmarshal([]byte(v1)) if err != nil { return pvl, err } err = services.SetKey(ptypestr, v2) if err != nil { return pvl, err } } pvlStr := jsonw.NewDictionary() err := pvlStr.SetKey("pvl_version", jsonw.NewInt(SupportedVersion)) if err != nil { return pvl, err } err = pvlStr.SetKey("revision", jsonw.NewInt(1)) if err != nil { return pvl, err } err = pvlStr.SetKey("services", services) if err != nil { return pvl, err } pvlB, err := pvlStr.Marshal() if err != nil { return pvl, err } pvl = string(pvlB) return pvl, nil } func newExternalJSONRes(json string, fail failer) *libkb.ExternalAPIRes { if json == "" { fail("empty json string") } w, err := jsonw.Unmarshal([]byte(json)) if err != nil { fail("invalid json: %v", err) } return &libkb.ExternalAPIRes{HTTPStatus: 200, Body: w} } func newExternalHTMLRes(html string, fail failer) *libkb.ExternalHTMLRes { if html == "" { fail("empty html string") } reader := strings.NewReader(html) doc, err := goquery.NewDocumentFromReader(reader) if err != nil { fail("invalid html: %v", err) } return &libkb.ExternalHTMLRes{HTTPStatus: 200, GoQuery: doc} } func newExternalTextRes(text string, fail failer) *libkb.ExternalTextRes { if text == "" { fail("empty text response") } return &libkb.ExternalTextRes{HTTPStatus: 200, Body: text} }