commit ec9b5f0bbac26b3fa439f7fe48c4bdf066545911 from: Omar Polo via: Thomas Adam date: Tue Jul 19 10:16:29 2022 UTC fix email address parsing we were both too strict and too lose. To avoid breaking got object parser (and to some extent ours too) we need to ensure that there aren't any line feeds, extra < or > and no trailing gibberish. The '@' is not actually required in the email. various tweaks and ok stsp commit - f69c5a468f5e08db053b390fc00d2e2e70bf4d53 commit + ec9b5f0bbac26b3fa439f7fe48c4bdf066545911 blob - 034dde68216bb0a706cedd6e96ebac3012ccb8ab blob + fdedddacfa4bbde46e722c1066f24c0ff20ab7b1 --- got/got.c +++ got/got.c @@ -548,24 +548,28 @@ import_progress(void *arg, const char *path) return NULL; } -static int +static const struct got_error * valid_author(const char *author) { + const char *email = author; + /* - * Really dumb email address check; we're only doing this to - * avoid git's object parser breaking on commits we create. + * Git' expects the author (or committer) to be in the form + * "name ", which are mostly free form (see the + * "committer" description in git-fast-import(1)). We're only + * doing this to avoid git's object parser breaking on commits + * we create. */ - while (*author && *author != '<') - author++; - if (*author != '<') - return 0; - while (*author && *author != '@') + + while (*author && *author != '\n' && *author != '<' && *author != '>') author++; - if (*author != '@') - return 0; - while (*author && *author != '>') + if (*author++ != '<') + return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email); + while (*author && *author != '\n' && *author != '<' && *author != '>') author++; - return *author == '>'; + if (strcmp(author, ">") != 0) + return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email); + return NULL; } static const struct got_error * @@ -625,8 +629,8 @@ get_author(char **author, struct got_repository *repo, if (*author == NULL) return got_error_from_errno("strdup"); - if (!valid_author(*author)) { - err = got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", *author); + err = valid_author(*author); + if (err) { free(*author); *author = NULL; } blob - 49458051f4c21c319a884feb707cc3aa39e543db blob + cf2c3ea32defbab535ace771de28f684e7e74ff7 --- regress/cmdline/commit.sh +++ regress/cmdline/commit.sh @@ -640,6 +640,10 @@ test_commit_outside_refs_heads() { test_commit_no_email() { local testroot=`test_init commit_no_email` + local errmsg="" + + errmsg="commit author's email address is required for" + errmsg="$errmsg compatibility with Git" got checkout $testroot/repo $testroot/wt > /dev/null ret=$? @@ -653,10 +657,7 @@ test_commit_no_email() { got commit -m 'test no email' > $testroot/stdout \ 2> $testroot/stderr) - echo -n "got: :flan_hacker:: commit author's email address " \ - > $testroot/stderr.expected - echo "is required for compatibility with Git" \ - >> $testroot/stderr.expected + printf "got: :flan_hacker:: %s\n" "$errmsg" > $testroot/stderr.expected cmp -s $testroot/stderr.expected $testroot/stderr ret=$? if [ $ret -ne 0 ]; then @@ -670,8 +671,56 @@ test_commit_no_email() { ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" $ret + return 1 fi - test_done "$testroot" "$ret" + + # try again with a newline inside the email + (cd $testroot/wt \ + && FS=' ' env GOT_AUTHOR="$(printf "Flan ")" \ + got commit -m 'test invalid email' > $testroot/stdout \ + 2> $testroot/stderr) + + printf "got: Flan : %s\n" "$errmsg" \ + > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" $ret + return 1 + fi + + echo -n > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" $ret + return 1 + fi + + # try again with a < inside the email + (cd $testroot/wt && env GOT_AUTHOR="$(printf "Flan ")" \ + got commit -m 'test invalid email' > $testroot/stdout \ + 2> $testroot/stderr) + + printf "got: Flan : %s\n" "$errmsg" > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" $ret + return 1 + fi + + echo -n > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" $ret } test_commit_tree_entry_sorting() {