dkg wites:

> the typesafety checks in imap-dl turn out to make imap-dl fail when
> python3-gssapi is installed.  In particular:
>
> try:
>     import gssapi # type: ignore
> except ModuleNotFoundError:
>     gssapi = None
> […]
> class GSSAPI_handler():
>     gss_vc:gssapi.SecurityContext
>
>
> this fails when the gssapi module isn't installed.  I should have caught
> it earlier, sorry!
>
> not sure the right way to handle this while retaining the type-safety
> though.

Ugh.  My suggestion is to just make the class definition contingent on
the library's presence.  Patch for that attached.

Thanks,
--Robbie

Attachment: signature.asc
Description: PGP signature

>From 2a6d814dbe9976e55edd152982e60d1111a6ce61 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharw...@redhat.com>
Date: Fri, 27 Mar 2020 13:46:42 -0400
Subject: [PATCH] imap-dl: Fix failure when python3-gssapi isn't installed

The type annotation of the SecurityContext in GSSAPI_helper causes
python to actually use the gssapi object, which is None when
python3-gssapi isn't present.  Work around this by making the class
definition contingent on the presence of python3-gssapi.

Also adjust shebang to work properly with venvs.

Signed-off-by: Robbie Harwood <rharw...@redhat.com>
---
 imap-dl | 60 +++++++++++++++++++++++++++++----------------------------
 1 file changed, 31 insertions(+), 29 deletions(-)

diff --git a/imap-dl b/imap-dl
index 5a8494c..2052842 100755
--- a/imap-dl
+++ b/imap-dl
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
 # PYTHON_ARGCOMPLETE_OK
 # -*- coding: utf-8 -*-
 
@@ -95,39 +95,41 @@ def auth_builtin(username:str, imap:imaplib.IMAP4_SSL,
     if resp[0] != 'OK':
         raise Exception(f'login failed with {resp} as user {username} on {server}')
 
-# imaplib auth methods need to be in the form of callables, and they all
-# requre both additional parameters and storage beyond what the function
-# interface provides.
-class GSSAPI_handler():
-    gss_vc:gssapi.SecurityContext
-    username:str
+if gssapi:
+    # imaplib auth methods need to be in the form of callables, and they all
+    # requre both additional parameters and storage beyond what the function
+    # interface provides.
+    class GSSAPI_handler():
+        gss_vc:gssapi.SecurityContext
+        username:str
 
-    def __init__(self, server:str, username:str) -> None:
-        name = gssapi.Name(f'imap@{server}', gssapi.NameType.hostbased_service)
-        self.gss_vc = gssapi.SecurityContext(usage="initiate", name=name)
-        self.username = username
+        def __init__(self, server:str, username:str) -> None:
+            name = gssapi.Name(f'imap@{server}',
+                               gssapi.NameType.hostbased_service)
+            self.gss_vc = gssapi.SecurityContext(usage="initiate", name=name)
+            self.username = username
 
-    def __call__(self, token:Optional[bytes]) -> bytes:
-        if token == b"":
-            token = None
-        if not self.gss_vc.complete:
-            response = self.gss_vc.step(token)
-            return response if response else b"" # type: ignore
-        elif token is None:
-            return b""
+        def __call__(self, token:Optional[bytes]) -> bytes:
+            if token == b"":
+                token = None
+            if not self.gss_vc.complete:
+                response = self.gss_vc.step(token)
+                return response if response else b"" # type: ignore
+            elif token is None:
+                return b""
 
-        response = self.gss_vc.unwrap(token)
+            response = self.gss_vc.unwrap(token)
 
-        # Preserve the "length" of the message we received, and set the first
-        # byte to one.  If username is provided, it's next.
-        reply:List[int] = []
-        reply[0:4] = response.message[0:4]
-        reply[0] = 1
-        if self.username:
-            reply[5:] = self.username.encode("utf-8")
+            # Preserve the "length" of the message we received, and set the
+            # first byte to one.  If username is provided, it's next.
+            reply:List[int] = []
+            reply[0:4] = response.message[0:4]
+            reply[0] = 1
+            if self.username:
+                reply[5:] = self.username.encode("utf-8")
 
-        response = self.gss_vc.wrap(bytes(reply), response.encrypted)
-        return response.message if response.message else b"" # type: ignore
+            response = self.gss_vc.wrap(bytes(reply), response.encrypted)
+            return response.message if response.message else b"" # type: ignore
 
 def auth_gssapi(username:str, imap:imaplib.IMAP4_SSL,
                 conf:configparser.ConfigParser, server:str) -> None:
-- 
2.25.1

Reply via email to