Re: [PATCH v5 0/4] docs: update email credential helpers and improve formatting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 28-05-2025 03:06 pm, Aditya Garg wrote:
> 
> 
> On 28-05-2025 12:53 pm, Eric Sunshine wrote:
>> On Wed, May 28, 2025 at 3:05 AM Aditya Garg <gargaditya08@xxxxxxxx> wrote:
>>> v5: Added a patch to make the purpose of using app password for Gmail
>>>     more clear in `send-email` documentation.
>>>
>>> Range-diff:
>>> -:  ---------- > 1:  2c47cc5396 docs: add credential helper for yahoo and link Google's sendgmail tool
>>> -:  ---------- > 2:  bc1d0471ca docs: improve formatting in git-send-email documentation
>>> -:  ---------- > 3:  b9e41e2492 docs: remove credential helper links for emails from gitcredentials
>>> -:  ---------- > 4:  a6ad7ac810 docs: make the purpose of using app password for Gmail more clear in send-email
>>
>> Strange range-diff.
> 
> I think because I used git version 2.43. When I compiled my branch with changes, git format-patch over there
> had a very different range-diff from this.

I get this range-diff with git 2.49

Range-diff:
-:  ---------- > 1:  4757d0305d imap-send: fix bug causing cfg->folder being set to NULL
1:  62edbcfc6e ! 2:  f5ad01abc5 imap-send: enable specifying the folder using the command line
    @@ Metadata
     Author: Aditya Garg <gargaditya08@xxxxxxxx>
     
      ## Commit message ##
    -    imap-send: enable specifying the folder using the command line
    +    imap-send: add support for OAuth2.0 authentication
     
    -    Some users may very often want to imap-send messages to a folder
    -    other than the default set in the config. Add a command line
    -    argument for the same.
    +    OAuth2.0 is a new way of authentication supported by various email providers
    +    these days. OAUTHBEARER and XOAUTH2 are the two most common mechanisms used
    +    for OAuth2.0. OAUTHBEARER is described in RFC5801[1] and RFC7628[2], whereas
    +    XOAUTH2 is Google's proprietary mechanism (See [3]).
    +
    +    [1]: https://datatracker.ietf.org/doc/html/rfc5801
    +    [2]: https://datatracker.ietf.org/doc/html/rfc7628
    +    [3]: https://developers.google.com/workspace/gmail/imap/xoauth2-protocol#initial_client_response
     
         Signed-off-by: Aditya Garg <gargaditya08@xxxxxxxx>
     
      ## Documentation/config/imap.adoc ##
    -@@
    - imap.folder::
    - 	The folder to drop the mails into, which is typically the Drafts
    --	folder. For example: "INBOX.Drafts", "INBOX/Drafts" or
    --	"[Gmail]/Drafts". Required.
    -+	folder. For example: 'INBOX.Drafts', 'INBOX/Drafts' or
    -+	'[Gmail]/Drafts'. Required if `--folder` argument is not used. If
    -+	set and `--folder` is also used, `--folder` will be preferred.
    - 
    - imap.tunnel::
    - 	Command used to set up a tunnel to the IMAP server through which
    +@@ Documentation/config/imap.adoc: imap.authMethod::
    + 	Specify the authentication method for authenticating with the IMAP server.
    + 	If Git was built with the NO_CURL option, or if your curl version is older
    + 	than 7.34.0, or if you're running git-imap-send with the `--no-curl`
    +-	option, the only supported method is 'CRAM-MD5'. If this is not set
    +-	then 'git imap-send' uses the basic IMAP plaintext LOGIN command.
    ++	option, the only supported methods are 'CRAM-MD5', 'OAUTHBEARER' and
    ++	'XOAUTH2'. If this is not set then `git imap-send` uses the basic IMAP
    ++	plaintext LOGIN command.
     
      ## Documentation/git-imap-send.adoc ##
    -@@ Documentation/git-imap-send.adoc: OPTIONS
    - --quiet::
    - 	Be quiet.
    - 
    -+-f <folder>::
    -+--folder <folder>::
    -+	Specify the folder in which the emails have to saved.
    -+	For example: `--folder [Gmail]/Drafts` or `-f INBOX/Drafts`.
    -+
    - --curl::
    - 	Use libcurl to communicate with the IMAP server, unless tunneling
    - 	into it.  Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
    +@@ Documentation/git-imap-send.adoc: Using Gmail's IMAP interface:
    + 
    + ---------
    + [imap]
    +-	folder = "[Gmail]/Drafts"
    +-	host = imaps://imap.gmail.com
    +-	user = user@xxxxxxxxx
    +-	port = 993
    ++    folder = "[Gmail]/Drafts"
    ++    host = imaps://imap.gmail.com
    ++    user = user@xxxxxxxxx
    ++    port = 993
    + ---------
    + 
    ++Gmail does not allow using your account password for `git imap-send`.
    ++If you have multi-factor authentication set up on your Gmail account, you can generate
    ++an app-specific password for use with `git imap-send`.
    ++Visit https://security.google.com/settings/security/apppasswords to create it.
    ++If you do not want to enable multi-factor authentication, you can use OAuth2.0
    ++authentication as described below.
    ++
    + [NOTE]
    + You might need to instead use: `folder = "[Google Mail]/Drafts"` if you get an error
    + that the "Folder doesn't exist".
    +@@ Documentation/git-imap-send.adoc: that the "Folder doesn't exist".
    + If your Gmail account is set to another language than English, the name of the "Drafts"
    + folder will be localized.
    + 
    ++If you want to use OAuth2.0 based authentication, you can specify `OAUTHBEARER`
    ++or `XOAUTH2` mechanism in your config. In such a case you will have to use an
    ++OAuth2.0 access token in place of your password.
    ++
    ++---------
    ++[imap]
    ++    folder = "[Gmail]/Drafts"
    ++    host = imaps://imap.gmail.com
    ++    user = user@xxxxxxxxx
    ++    port = 993
    ++    authmethod = OAUTHBEARER
    ++---------
    ++
    ++Using Outlook's IMAP interface:
    ++
    ++Unlike Gmail, Outlook only supports OAuth2.0 based authentication. Also, it
    ++supports only `XOAUTH2` as the mechanism.
    ++
    ++---------
    ++[imap]
    ++    folder = "Drafts"
    ++    host = imaps://outlook.office365.com
    ++    user = user@xxxxxxxxxxx
    ++    port = 993
    ++    authmethod = XOAUTH2
    ++---------
    ++
    + Once the commits are ready to be sent, run the following command:
    + 
    +   $ git format-patch --cover-letter -M --stdout origin/master | git imap-send
    +@@ Documentation/git-imap-send.adoc: Just make sure to disable line wrapping in the email client (Gmail's web
    + interface will wrap lines no matter what, so you need to use a real
    + IMAP client).
    + 
    ++In case you are using OAuth2.0 authentication, it is easier to use credential
    ++helpers to generate tokens. Credential helpers suggested in
    ++linkgit:git-send-email[1] can be used for `git imap-send` as well.
    ++
    + CAUTION
    + -------
    + It is still your responsibility to make sure that the email message
     
      ## imap-send.c ##
    -@@
    +@@ imap-send.c: enum CAPABILITY {
    + 	LITERALPLUS,
    + 	NAMESPACE,
    + 	STARTTLS,
    +-	AUTH_CRAM_MD5
    ++	AUTH_CRAM_MD5,
    ++	AUTH_OAUTHBEARER,
    ++	AUTH_XOAUTH2
    + };
      
    - static int verbosity;
    - static int use_curl = USE_CURL_DEFAULT;
    -+static char *opt_folder = NULL;
    + static const char *cap_list[] = {
    +@@ imap-send.c: static const char *cap_list[] = {
    + 	"NAMESPACE",
    + 	"STARTTLS",
    + 	"AUTH=CRAM-MD5",
    ++	"AUTH=OAUTHBEARER",
    ++	"AUTH=XOAUTH2",
    + };
      
    - static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] [--[no-]curl] < <mbox>", NULL };
    + #define RESP_OK    0
    +@@ imap-send.c: static char *cram(const char *challenge_64, const char *user, const char *pass)
    + 	return (char *)response_64;
    + }
      
    - static struct option imap_send_options[] = {
    - 	OPT__VERBOSITY(&verbosity),
    - 	OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
    -+	OPT_STRING('f', "folder", &opt_folder, "folder", "specify the IMAP folder"),
    - 	OPT_END()
    - };
    ++static char *oauthbearer_base64(const char *user, const char *access_token)
    ++{
    ++	int raw_len, b64_len;
    ++	char *raw, *b64;
    ++
    ++	/* Compose the OAUTHBEARER string
    ++	 *
    ++	 * "n,a=" {User} ",^Ahost=" {Host} "^Aport=" {Port} "^Aauth=Bearer " {Access Token} "^A^A
    ++	 *
    ++	 * The first part `n,a=" {User} ",` is the gs2 header described in RFC5801.
    ++	 * * gs2-cb-flag `n` -> client does not support CB
    ++	 * * gs2-authzid `a=" {User} "`
    ++	 *
    ++	 * The second part are key value pairs containing host, port and auth as
    ++	 * described in RFC7628.
    ++	 *
    ++	 * https://datatracker.ietf.org/doc/html/rfc5801
    ++	 * https://datatracker.ietf.org/doc/html/rfc7628
    ++	 */
    ++	raw_len = strlen(user) + strlen(access_token) + 20;
    ++	raw = xmallocz(raw_len + 1);
    ++	snprintf(raw, raw_len + 1, "n,a=%s,\001auth=Bearer %s\001\001", user, access_token);
    ++
    ++	/* Base64 encode */
    ++	b64 = xmallocz(ENCODED_SIZE(strlen(raw)));
    ++	b64_len = EVP_EncodeBlock((unsigned char *)b64, (unsigned char *)raw, strlen(raw));
    ++	free(raw);
    ++
    ++	if (b64_len < 0) {
    ++		free(b64);
    ++		return NULL;
    ++	}
    ++	return b64;
    ++}
    ++
    ++static char *xoauth2_base64(const char *user, const char *access_token)
    ++{
    ++	int raw_len, b64_len;
    ++	char *raw, *b64;
    ++
    ++	/* Compose the XOAUTH2 string
    ++	 * "user=" {User} "^Aauth=Bearer " {Access Token} "^A^A"
    ++	 * https://developers.google.com/workspace/gmail/imap/xoauth2-protocol#initial_client_response
    ++	 */
    ++	raw_len = strlen(user) + strlen(access_token) + 20;
    ++	raw = xmallocz(raw_len + 1);
    ++	snprintf(raw, raw_len + 1, "user=%s\001auth=Bearer %s\001\001", user, access_token);
    ++
    ++	/* Base64 encode */
    ++	b64 = xmallocz(ENCODED_SIZE(strlen(raw)));
    ++	b64_len = EVP_EncodeBlock((unsigned char *)b64, (unsigned char *)raw, strlen(raw));
    ++	free(raw);
    ++
    ++	if (b64_len < 0) {
    ++		free(b64);
    ++		return NULL;
    ++	}
    ++	return b64;
    ++}
    ++
    + #else
      
    -@@ imap-send.c: int cmd_main(int argc, const char **argv)
    + static char *cram(const char *challenge_64 UNUSED,
    +@@ imap-send.c: static char *cram(const char *challenge_64 UNUSED,
    + 	    "you have to build git-imap-send with OpenSSL library.");
    + }
      
    - 	argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0);
    ++static char *oauthbearer_base64(const char *user UNUSED,
    ++		  const char *access_token UNUSED)
    ++{
    ++	die("You are trying to use OAUTHBEARER authenticate method "
    ++	    "with OpenSSL library, but it's support has not been compiled in.");
    ++}
    ++
    ++static char *xoauth2_base64(const char *user UNUSED,
    ++		  const char *access_token UNUSED)
    ++{
    ++	die("You are trying to use XOAUTH2 authenticate method "
    ++	    "with OpenSSL library, but it's support has not been compiled in.");
    ++}
    ++
    + #endif
      
    -+	if (opt_folder) {
    -+		free(server.folder);
    -+		server.folder = xstrdup(opt_folder);
    + static int auth_cram_md5(struct imap_store *ctx, const char *prompt)
    +@@ imap-send.c: static int auth_cram_md5(struct imap_store *ctx, const char *prompt)
    + 	return 0;
    + }
    + 
    ++static int auth_oauthbearer(struct imap_store *ctx, const char *prompt UNUSED)
    ++{
    ++	int ret;
    ++	char *b64;
    ++
    ++	b64 = oauthbearer_base64(ctx->cfg->user, ctx->cfg->pass);
    ++	if (!b64)
    ++		return error("OAUTHBEARER: base64 encoding failed");
    ++
    ++	/* Send the base64-encoded response */
    ++	ret = socket_write(&ctx->imap->buf.sock, b64, strlen(b64));
    ++	if (ret != (int)strlen(b64)) {
    ++		free(b64);
    ++		return error("IMAP error: sending OAUTHBEARER response failed");
    ++	}
    ++
    ++	free(b64);
    ++	return 0;
    ++}
    ++
    ++static int auth_xoauth2(struct imap_store *ctx, const char *prompt UNUSED)
    ++{
    ++	int ret;
    ++	char *b64;
    ++
    ++	b64 = xoauth2_base64(ctx->cfg->user, ctx->cfg->pass);
    ++	if (!b64)
    ++		return error("XOAUTH2: base64 encoding failed");
    ++
    ++	/* Send the base64-encoded response */
    ++	ret = socket_write(&ctx->imap->buf.sock, b64, strlen(b64));
    ++	if (ret != (int)strlen(b64)) {
    ++		free(b64);
    ++		return error("IMAP error: sending XOAUTH2 response failed");
     +	}
     +
    - 	if (argc)
    - 		usage_with_options(imap_send_usage, imap_send_options);
    ++	free(b64);
    ++	return 0;
    ++}
    ++
    + static void server_fill_credential(struct imap_server_conf *srvc, struct credential *cred)
    + {
    + 	if (srvc->user && srvc->pass)
    +@@ imap-send.c: static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
    + 					fprintf(stderr, "IMAP error: AUTHENTICATE CRAM-MD5 failed\n");
    + 					goto bail;
    + 				}
    ++			} else if (!strcmp(srvc->auth_method, "OAUTHBEARER")) {
    ++				if (!CAP(AUTH_OAUTHBEARER)) {
    ++					fprintf(stderr, "You specified "
    ++						"OAUTHBEARER as authentication method, "
    ++						"but %s doesn't support it.\n", srvc->host);
    ++					goto bail;
    ++				}
    ++				/* OAUTHBEARER */
    ++
    ++				memset(&cb, 0, sizeof(cb));
    ++				cb.cont = auth_oauthbearer;
    ++				if (imap_exec(ctx, &cb, "AUTHENTICATE OAUTHBEARER") != RESP_OK) {
    ++					fprintf(stderr, "IMAP error: AUTHENTICATE OAUTHBEARER failed\n");
    ++					goto bail;
    ++				}
    ++			} else if (!strcmp(srvc->auth_method, "XOAUTH2")) {
    ++				if (!CAP(AUTH_XOAUTH2)) {
    ++					fprintf(stderr, "You specified "
    ++						"XOAUTH2 as authentication method, "
    ++						"but %s doesn't support it.\n", srvc->host);
    ++					goto bail;
    ++				}
    ++				/* XOAUTH2 */
    ++
    ++				memset(&cb, 0, sizeof(cb));
    ++				cb.cont = auth_xoauth2;
    ++				if (imap_exec(ctx, &cb, "AUTHENTICATE XOAUTH2") != RESP_OK) {
    ++					fprintf(stderr, "IMAP error: AUTHENTICATE XOAUTH2 failed\n");
    ++					goto bail;
    ++				}
    + 			} else {
    + 				fprintf(stderr, "Unknown authentication method:%s\n", srvc->host);
    + 				goto bail;
    +@@ imap-send.c: static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
    + 
    + 	server_fill_credential(srvc, cred);
    + 	curl_easy_setopt(curl, CURLOPT_USERNAME, srvc->user);
    +-	curl_easy_setopt(curl, CURLOPT_PASSWORD, srvc->pass);
    ++
    ++	if (!srvc->auth_method ||
    ++	    strcmp(srvc->auth_method, "XOAUTH2") ||
    ++	    strcmp(srvc->auth_method, "OAUTHBEARER"))
    ++		curl_easy_setopt(curl, CURLOPT_PASSWORD, srvc->pass);
    + 
    + 	strbuf_addstr(&path, srvc->use_ssl ? "imaps://" : "imap://");
    + 	strbuf_addstr(&path, srvc->host);
    +@@ imap-send.c: static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
    + 	curl_easy_setopt(curl, CURLOPT_PORT, srvc->port);
    + 
    + 	if (srvc->auth_method) {
    +-		struct strbuf auth = STRBUF_INIT;
    +-		strbuf_addstr(&auth, "AUTH=");
    +-		strbuf_addstr(&auth, srvc->auth_method);
    +-		curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
    +-		strbuf_release(&auth);
    ++		if (!strcmp(srvc->auth_method, "XOAUTH2") ||
    ++		    !strcmp(srvc->auth_method, "OAUTHBEARER")) {
    ++
    ++			/* While CURLOPT_XOAUTH2_BEARER looks as if it only supports XOAUTH2,
    ++			 * upon debugging, it has been found that it is capable of detecting
    ++			 * the best option out of OAUTHBEARER and XOAUTH2.
    ++			 */
    ++			curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, srvc->pass);
    ++		} else {
    ++			struct strbuf auth = STRBUF_INIT;
    ++			strbuf_addstr(&auth, "AUTH=");
    ++			strbuf_addstr(&auth, srvc->auth_method);
    ++			curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
    ++			strbuf_release(&auth);
    ++		}
    + 	}
      
    + 	if (!srvc->use_ssl)
-:  ---------- > 3:  e3dc19dc49 imap-send: add PLAIN authentication method to OpenSSL
-:  ---------- > 4:  11f7ac1325 imap-send: fix memory leak in case auth_cram_md5 fails
-:  ---------- > 5:  f6e7a5498e imap-send: enable specifying the folder using the command line
2:  245cc89cca = 6:  4769924781 imap-send: enable user to choose between libcurl and openssl using the config
-- 
2.49.0.windows.1






[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux