Ejemplo n.º 1
0
def test_protect():
    #> From foo
    msg='''Content-Type: multipart/mixed;
 boundary="------------030608090900090202040409"

This is a multi-part message in MIME format.
--------------030608090900090202040409
Content-Type: text/plain; charset=ISO-8859-15
Content-Transfer-Encoding: quoted-printable

body
line2

--------------030608090900090202040409
Content-Type: text/plain; charset=UTF-8;
 name="attach.txt"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
 filename="attach.txt"

attachment
line2
--------------030608090900090202040409--
'''
    prot = protect_mail(msg,linesep='\n',sevenbit=True)
    assert prot.as_string() == msg
    prot = protect_mail(msg,linesep='\r\n',sevenbit=True)
    assert prot.as_string() == fix_lines(msg,'\r\n')
    msg = create_mail(sender,receiver,'subject','body\nmessage')
    prot = protect_mail(msg,linesep='\n')
    assert msg.get_payload() == prot.get_payload()
    prot = protect_mail(msg,linesep='\r\n')
    assert fix_lines(msg.get_payload(),'\r\n') == prot.get_payload()
Ejemplo n.º 2
0
def test_sign(gpgsender, inline, attach, asstr, protect):
    # protect = use protected CRLF message
    import copy
    if inline and attach: return

    if attach:  # with attachment
        nmsg, pmsg = protect_mail(msgatt, linesep='\n'), protatt
        inmsg = protatt if protect else nmsg
    else:
        inmsg = prot if protect else msg
        nmsg, pmsg = msg, prot
    if asstr:
        inmsg, nmsg, pmsg = inmsg.as_string(), nmsg.as_string(
        ), pmsg.as_string()
    omsg = copy.deepcopy(inmsg)
    sgn, result = gpgsender.sign(inmsg, inline=inline, verify=True)
    assert sgn
    compare_mail(omsg, inmsg)  # unmodified
    if inline:
        assert not sgn.is_multipart()
        body = gpgsender.without_signature(sgn.get_payload())
        if not asstr: assert body == pmsg.get_payload()
    if asstr: sgn = sgn.as_string()
    if protect: sgn = protect_mail(sgn, linesep='\r\n')
    osgn = copy.deepcopy(sgn)
    assert gpgsender.verify(sgn, strict=True)[0]
    compare_mail(osgn, sgn)  # unmodified
    msg2, signed, results = gpgsender.decrypt(sgn, strict=True)
    assert signed and msg2
    compare_mail(osgn, sgn)  # unmodified
    if asstr: msg2 = msg2.as_string()
    compare_mail(pmsg, msg2)

    assert gpgsender.verify(sgn, strict=False)[0]
    compare_mail(osgn, sgn)  # unmodified
    msg2, signed, results = gpgsender.decrypt(sgn, strict=False)
    assert signed and msg2
    compare_mail(osgn, sgn)  # unmodified
    if asstr: msg2 = msg2.as_string()
    compare_mail(pmsg, msg2)

    nsgn = protect_mail(sgn, linesep='\n')  # use LF message as input
    if asstr: nsgn = nsgn.as_string()
    compare_mail(osgn, sgn)  # unmodified
    onsgn = copy.deepcopy(nsgn)
    msg2, signed, results = gpgsender.decrypt(nsgn, strict=True)
    assert signed == bool(
        inline) and msg2  # sgn was modified, should fail for detached
    compare_mail(onsgn, nsgn)  # unmodified
    if asstr: msg2 = msg2.as_string()
    compare_mail(nmsg, msg2)

    msg2, signed, results = gpgsender.decrypt(nsgn, strict=False)
    assert signed and msg2
    compare_mail(onsgn, nsgn)
    if asstr: msg2 = msg2.as_string()
    if inline:
        compare_mail(nmsg, msg2)
    else:
        compare_mail(pmsg, msg2)
Ejemplo n.º 3
0
def test_sign(gpgsender,inline,attach,asstr,protect):
    # protect = use protected CRLF message
    import copy
    if inline and attach: return

    if attach: # with attachment
        nmsg, pmsg = protect_mail(msgatt,linesep='\n'), protatt
        inmsg = protatt if protect else nmsg
    else:
        inmsg = prot if protect else msg
        nmsg, pmsg = msg, prot
    if asstr: inmsg, nmsg, pmsg = inmsg.as_string(), nmsg.as_string(), pmsg.as_string()
    omsg = copy.deepcopy(inmsg)
    sgn, result = gpgsender.sign(inmsg,inline=inline,verify=True)
    assert sgn
    compare_mail(omsg,inmsg) # unmodified
    if inline:
        assert not sgn.is_multipart()
        body = gpgsender.without_signature(sgn.get_payload())
        if not asstr: assert body==pmsg.get_payload()
    if asstr: sgn = sgn.as_string()
    if protect: sgn = protect_mail(sgn,linesep='\r\n')
    osgn = copy.deepcopy(sgn)
    assert gpgsender.verify(sgn,strict=True)[0]
    compare_mail(osgn,sgn) # unmodified
    msg2, signed, results = gpgsender.decrypt(sgn,strict=True)
    assert signed and msg2
    compare_mail(osgn,sgn) # unmodified
    if asstr: msg2 = msg2.as_string()
    compare_mail(pmsg,msg2)

    assert gpgsender.verify(sgn,strict=False)[0]
    compare_mail(osgn,sgn) # unmodified
    msg2, signed, results = gpgsender.decrypt(sgn,strict=False)
    assert signed and msg2
    compare_mail(osgn,sgn) # unmodified
    if asstr: msg2 = msg2.as_string()
    compare_mail(pmsg,msg2)

    nsgn = protect_mail(sgn,linesep='\n') # use LF message as input
    if asstr: nsgn = nsgn.as_string()
    compare_mail(osgn,sgn) # unmodified
    onsgn = copy.deepcopy(nsgn)
    msg2, signed, results = gpgsender.decrypt(nsgn,strict=True)
    assert signed==bool(inline) and msg2 # sgn was modified, should fail for detached
    compare_mail(onsgn,nsgn) # unmodified
    if asstr: msg2 = msg2.as_string()
    compare_mail(nmsg,msg2)

    msg2, signed, results = gpgsender.decrypt(nsgn,strict=False)
    assert signed and msg2
    compare_mail(onsgn,nsgn)
    if asstr: msg2 = msg2.as_string()
    if inline:
        compare_mail(nmsg,msg2)
    else:
        compare_mail(pmsg,msg2)
Ejemplo n.º 4
0
 def __iter__(self):
     from kryptomime.mail import protect_mail
     filter = "(OR UNSEEN FLAGGED)" if self.filter else 'ALL'
     status, response = self.imap.uid('search', None, filter)
     if not status == 'OK': return
     email_ids = response[0].split()
     for e_id in email_ids:
         status, response = self.imap.uid('fetch', e_id, '(FLAGS)')
         flags = ''
         for flag in imaplib.ParseFlags(response[0]):
             if 'Flagged' in flag: flags += 'F'
             elif 'Seen' in flag: flags += 'S'
             elif 'Deleted' in flag: flags += 'D'
         if 'D' in flags: continue
         # mark for processing
         status, response = self.imap.uid('store', e_id, '+FLAGS',
                                          r'(\Flagged)')
         status, response = self.imap.uid('fetch', e_id, '(RFC822)')
         raw = response[0][1]
         yield protect_mail(raw), flags
         if self.keep:
             status, response = self.imap.uid('store', e_id, '-FLAGS',
                                              r'(\Flagged)')
         else:
             status, response = self.imap.uid('store', e_id, '+FLAGS',
                                              r'(\Deleted)')
Ejemplo n.º 5
0
def store_mail(mail,identity=None,decrypt=False,notify=None):
    from six import iteritems
    from kryptomime.mail import protect_mail

    mail = protect_mail(mail,sevenbit=False)
    ids = settings.EMAIL_IDS

    def find_identity(recv):
        for id,opts in iteritems(ids):
            idemail = opts.get('email',id)
            if idemail in recv: return id, opts, idemail
        return None, None, None

    if identity:
        opts = ids[identity]
        idemail = opts.get('email',identity)
    else:
        import email.utils
        recv = mail.get_all('to', []) + mail.get_all('cc', [])
        recv = [to[1] for to in email.utils.getaddresses(recv)]
        identity, opts, idemail = find_identity(recv)
        if not identity:
            log.error('unknown receiver')
            return False

    indep_crypto = getattr(settings, 'EMAIL_INDEP_CRYPT', False)
    if indep_crypto and not decrypt:
        gpg, crypto, skey = None, None, None
    else:
        from kryptomime.pgp import GPGMIME
        gpg = gnupg_init()
        if not 'key' in opts: skey = None
        else: skey = get_full_key(GPGMIME(gpg),opts,identity)
        crypto = GPGMIME(gpg,default_key=skey)
    return save_mail(mail, identity, idemail, crypto, gpg, skey, notify)
Ejemplo n.º 6
0
def test_encrypt(gpgsender, asstr, protect):
    import copy
    inmsg = protect_mail(msgrev,linesep='\r\n') if protect else msgrev
    if asstr: inmsg = inmsg.as_string()
    omsg = copy.deepcopy(inmsg)
    enc, results = gpgsender.encrypt(inmsg,toself=False,sign=False) # we only know sender keys
    assert enc
    compare_mail(omsg,inmsg)
    if protect: enc = protect_mail(enc,linesep='\r\n')
    if asstr: enc = enc.as_string()
    oenc = copy.deepcopy(enc)
    msg2, signed, results = gpgsender.decrypt(enc,strict=True)
    assert not signed and msg2
    compare_mail(oenc,enc)
    if asstr: msg2 = msg2.as_string()
    compare_mail(inmsg,msg2)
Ejemplo n.º 7
0
def test_encrypt(gpgsender, asstr, protect):
    import copy
    inmsg = protect_mail(msgrev, linesep='\r\n') if protect else msgrev
    if asstr: inmsg = inmsg.as_string()
    omsg = copy.deepcopy(inmsg)
    enc, results = gpgsender.encrypt(inmsg, toself=False,
                                     sign=False)  # we only know sender keys
    assert enc
    compare_mail(omsg, inmsg)
    if protect: enc = protect_mail(enc, linesep='\r\n')
    if asstr: enc = enc.as_string()
    oenc = copy.deepcopy(enc)
    msg2, signed, results = gpgsender.decrypt(enc, strict=True)
    assert not signed and msg2
    compare_mail(oenc, enc)
    if asstr: msg2 = msg2.as_string()
    compare_mail(inmsg, msg2)
Ejemplo n.º 8
0
def test_attach():
    attachment = create_mime('some\nattachment')
    msg = create_mail(sender,receiver,'subject','body\nmessage',attach=[attachment])
    # boundary is generated randomly by as_string - hardcode here
    msg.set_boundary('===============1808028167789866750==')
    prot = _protected(msg)
    assert prot.as_string() == msg.as_string()
    prot = protect_mail(msg,linesep='\n',sevenbit=True)
    assert prot.as_string() == msg.as_string()
Ejemplo n.º 9
0
 def test_sender_signed_nl(self,unilateral,gpgreceiver):
     # good self sign
     id1, id2, sgn = unilateral['id'], gpgreceiver, unilateral['sgn']
     sgn = protect_mail(sgn,linesep='\n')
     raw, verified, result1 = id1.decrypt(sgn,strict=False)
     verified2, result2 = id1.verify(sgn,strict=False)
     assert raw and result1 and result2
     assert not result1['encrypted'] and verified and result1['signed'] and result2['signed'] and result1['fingerprints']
     assert result1['fingerprints']==result2['fingerprints']
Ejemplo n.º 10
0
 def test_sender_signed_nl(self, unilateral, gpgreceiver):
     # good self sign
     id1, id2, sgn = unilateral['id'], gpgreceiver, unilateral['sgn']
     sgn = protect_mail(sgn, linesep='\n')
     raw, verified, result1 = id1.decrypt(sgn, strict=False)
     verified2, result2 = id1.verify(sgn, strict=False)
     assert raw and result1 and result2
     assert not result1['encrypted'] and verified and result1[
         'signed'] and result2['signed'] and result1['fingerprints']
     assert result1['fingerprints'] == result2['fingerprints']
Ejemplo n.º 11
0
 def sign(self,ids,msg,inline):
     id1, id2 = ids['id1'], ids['id2']
     prot = protect_mail(msg,linesep='\r\n')
     sgn,_ = id1.sign(msg,inline=inline)
     assert sgn and id2.analyze(sgn) == (False,True)
     mail, verified, result1 = id2.decrypt(sgn)
     verified2, result2 = id2.verify(sgn)
     rawmail, signed = id2.strip_signature(sgn)
     assert mail and verified==verified2
     compare_mail(mail,rawmail)
     assert result1 and result2
     assert not result1['encrypted'] and verified and result1['signed'] and result2['signed']
     assert result1['fingerprints']==result2['fingerprints']
     compare_mail(rawmail,prot)
Ejemplo n.º 12
0
 def sign(self, ids, msg, inline):
     id1, id2 = ids['id1'], ids['id2']
     prot = protect_mail(msg, linesep='\r\n')
     sgn, _ = id1.sign(msg, inline=inline)
     assert sgn and id2.analyze(sgn) == (False, True)
     mail, verified, result1 = id2.decrypt(sgn)
     verified2, result2 = id2.verify(sgn)
     rawmail, signed = id2.strip_signature(sgn)
     assert mail and verified == verified2
     compare_mail(mail, rawmail)
     assert result1 and result2
     assert not result1['encrypted'] and verified and result1[
         'signed'] and result2['signed']
     assert result1['fingerprints'] == result2['fingerprints']
     compare_mail(rawmail, prot)
Ejemplo n.º 13
0
 def bad_sign(self,ids,receiver,msg,encrypt):
     # id1 signs, but id2 doesn't know id1
     id1, id2 = ids['id1'], receiver
     prot = protect_mail(msg,linesep='\r\n')
     if encrypt: out,_ = id1.encrypt(msg,sign=True)
     else: out,_ = id1.sign(msg)
     assert out
     if encrypt: assert id2.analyze(out) == (True,None)
     else: assert id2.analyze(out) == (False,True)
     mail, verified, result1 = id2.decrypt(out)
     verified2, result2 = id2.verify(out)
     assert mail and result1 and result2
     assert result1['encrypted']==encrypt and not verified and not verified2
     assert result1['signed'] and result2['signed']
     assert not result1['fingerprints'] and not result2['fingerprints']
Ejemplo n.º 14
0
 def bad_sign(self, ids, receiver, msg, encrypt):
     # id1 signs, but id2 doesn't know id1
     id1, id2 = ids['id1'], receiver
     prot = protect_mail(msg, linesep='\r\n')
     if encrypt: out, _ = id1.encrypt(msg, sign=True)
     else: out, _ = id1.sign(msg)
     assert out
     if encrypt: assert id2.analyze(out) == (True, None)
     else: assert id2.analyze(out) == (False, True)
     mail, verified, result1 = id2.decrypt(out)
     verified2, result2 = id2.verify(out)
     assert mail and result1 and result2
     assert result1[
         'encrypted'] == encrypt and not verified and not verified2
     assert result1['signed'] and result2['signed']
     assert not result1['fingerprints'] and not result2['fingerprints']
Ejemplo n.º 15
0
def encode_mail(sender, receiver, data):
    "data must be validated by check_mail"
    from kryptomime.mail import create_mail, create_mime, check_charset, protect_mail
    from time import time as epochtime
    import email.utils
    from email.mime.text import MIMEText
    from six import iteritems
    from idapi.models import Message
    subject = data['subject']
    time = data.get('date')
    if not time: time = epochtime()
    parts = data.get('parts',None)
    if parts: # multi-part
        mail = None
        for i,part in enumerate(parts):
            ctype = part.get('content-type','text/plain').lower().split('/')
            encoding = part.get('content-encoding')
            content = part['content']
            content, charset = check_charset(content,part.get('content-charset'))
            if not i:
                msg = create_mail(sender,receiver,subject,content,time=time,subtype=ctype[1],
                    charset=charset,encoding=encoding,attach=[])
            else:
                msg = create_mime(content,*ctype,charset=charset,encoding=encoding)
                filename= part.get('filename')
                filename = dict(filename=filename) if filename else {}
                msg.add_header('Content-Disposition', 'attachment', **filename)
            params = part.get('content-params',{})
            if params:
                for k,v in iteritems(params):
                    msg.set_param(k,v)
            if i: mail.attach(msg)
            else: mail = msg
    else: # single part
        ctype = data.get('content-type','text/plain').lower().split('/')
        encoding = data.get('content-encoding')
        body, charset = check_charset(data['content'],data.get('content-charset'))
        mail = create_mail(sender,receiver,subject,body,time=time,subtype=ctype[1],
                charset=charset,encoding=encoding)
        params = data.get('content-params',{})
        if params:
            for k,v in iteritems(params):
                mail.set_param(k,v)
    return protect_mail(mail)
Ejemplo n.º 16
0
 def __iter__(self):
     from mailbox import Maildir
     from kryptomime.mail import protect_mail
     haveflags = isinstance(self.mailbox,Maildir)
     for key, mail in list(self.mailbox.items()):
         if haveflags:
             flags = mail.get_flags()
             if self.filter and 'S' in flags and not 'F' in flags: continue
             if not self.readonly:
                 mail.set_subdir('cur')
                 mail.add_flag('F')
         else: flags = ''
         if not self.readonly: self.mailbox[key] = mail
         yield protect_mail(mail,sevenbit=False),flags
         if self.readonly: continue
         if self.keep:
             if haveflags:
                 mail.remove_flag('F')
                 mail.add_flag('S')
             self.mailbox[key] = mail
         else: self.mailbox.remove(key) 
Ejemplo n.º 17
0
 def __iter__(self):
     from mailbox import Maildir
     from kryptomime.mail import protect_mail
     haveflags = isinstance(self.mailbox,Maildir)
     for key, mail in list(self.mailbox.items()):
         if haveflags:
             flags = mail.get_flags()
             if self.filter and 'S' in flags and not 'F' in flags: continue
             if not self.readonly:
                 mail.set_subdir('cur')
                 mail.add_flag('F')
         else: flags = ''
         if not self.readonly: self.mailbox[key] = mail
         yield protect_mail(mail,sevenbit=False),flags
         if self.readonly: continue
         if self.keep:
             if haveflags:
                 mail.remove_flag('F')
                 mail.add_flag('S')
             self.mailbox[key] = mail
         else: self.mailbox.remove(key) 
Ejemplo n.º 18
0
 def __iter__(self):
     from kryptomime.mail import protect_mail
     filter = "(OR UNSEEN FLAGGED)" if self.filter else 'ALL'
     status, response = self.imap.uid('search', None, filter)
     if not status=='OK': return
     email_ids= response[0].split()
     for e_id in email_ids:
         status, response = self.imap.uid('fetch',e_id, '(FLAGS)')
         flags = ''
         for flag in imaplib.ParseFlags(response[0]):
             if 'Flagged' in flag: flags += 'F'
             elif 'Seen' in flag: flags += 'S'
             elif 'Deleted' in flag: flags += 'D'
         if 'D' in flags: continue
         # mark for processing
         status, response = self.imap.uid('store',e_id, '+FLAGS', r'(\Flagged)')
         status, response = self.imap.uid('fetch',e_id, '(RFC822)')
         raw = response[0][1]
         yield protect_mail(raw,sevenbit=False), flags
         if self.keep:
             status,response = self.imap.uid('store',e_id, '-FLAGS', r'(\Flagged)')
         else:
             status,response = self.imap.uid('store',e_id, '+FLAGS', r'(\Deleted)')
Ejemplo n.º 19
0
from kryptomime.mail import create_mail, protect_mail
from kryptomime.smime import OpenSMIME, Certificate, PrivateKey, MemoryKeyStore, OpenSSL, OpenSSL_CA

import email.mime.text

from conftest import sender, receiver
from test_openssl import x509keys, openssl

passphrase='mysecret'
attachment = email.mime.text.MIMEText('some\nattachment')
msg = create_mail(sender,receiver,'subject','body\nmessage')
msg.epilogue=''
msgatt = create_mail(sender,receiver,'subject','body\nmessage',attach=[attachment])
msgrev = create_mail(receiver,sender,'subject','body\nmessage')
msgself = create_mail(sender,sender,'subject','body\nmessage')
prot = protect_mail(msg,linesep='\r\n')
protatt = protect_mail(msgatt,linesep='\r\n')

def compare_mail(a,b):
    if type(a)==str: return a==b
    assert a.is_multipart() == b.is_multipart()
    #from kryptomime.mail import ProtectedMessage
    #assert isinstance(a,ProtectedMessage)==isinstance(b,ProtectedMessage)
    # todo headers
    if a.is_multipart():
        for i in range(len(a.get_payload())):
            ap = a.get_payload(i)
            bp = b.get_payload(i)
            assert ap.as_string() == bp.as_string()
    else:
        assert a.get_payload() == b.get_payload()
Ejemplo n.º 20
0
def test_8bit(attachments):
    expect=b'''Content-Type: multipart/mixed; boundary="===============6661726347990728450=="
MIME-Version: 1.0
From: Foo <foo@localhost>
To: Bar <bar@localhost>
Subject: subject
Date: Mon, 02 Feb 2015 12:00:00 +0100

--===============6661726347990728450==
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64

w7xiZXIKMQoy
--===============6661726347990728450==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

uber
--===============6661726347990728450==
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64

w7xiZXIKMQoy
--===============6661726347990728450==
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64

w7xiZXIKMQoy
--===============6661726347990728450==
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable

=C3=BCber
1
2
--===============6661726347990728450==
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit

\xc3\xbcber
1
2
--===============6661726347990728450==
Content-Type: text/plain; charset="iso8859-1"
MIME-Version: 1.0
Content-Transfer-Encoding: base64

/GJlcgoxCjI=
--===============6661726347990728450==
Content-Type: text/plain; charset="iso8859-1"
MIME-Version: 1.0
Content-Transfer-Encoding: base64

/GJlcgoxCjI=
--===============6661726347990728450==
Content-Type: text/plain; charset="iso8859-1"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable

=FCber
1
2
--===============6661726347990728450==
Content-Type: text/plain; charset="iso8859-1"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

\xfcber
1
2
--===============6661726347990728450==--
'''
    s = u'über\n1\n2'
    msg = create_mail(sender,receiver,'subject',s,attach=attachments,time='Mon, 02 Feb 2015 12:00:00 +0100')
    msg.set_boundary('===============6661726347990728450==')
    out = mail_binary(msg)
    assert out==expect
    prot = protect_mail(out,linesep='\n',sevenbit=False)
    att = prot.get_payload()
    out2 = mail_binary(prot)
    assert out==out2
    compare_mail(msg,prot)
Ejemplo n.º 21
0
TODO: 'multipart/encrypted' but single-part, text/plain but encrypted, 'multipart/mixed' but signed
"""
from conftest import sender, receiver, compare_mail

passphrase = 'mysecret'
attachment = email.mime.text.MIMEText('some\nattachment')
msg = create_mail(sender, receiver, 'subject', 'body\nmessage')
msg.epilogue = ''
msgatt = create_mail(sender,
                     receiver,
                     'subject',
                     'body\nmessage',
                     attach=[attachment])
msgrev = create_mail(receiver, sender, 'subject', 'body\nmessage')
msgself = create_mail(sender, sender, 'subject', 'body\nmessage')
prot = protect_mail(msg, linesep='\r\n')
protatt = protect_mail(msgatt, linesep='\r\n')
bools = [False, True]


@fixture(scope='module')
def keys(request):
    import os
    generate = request.config.getoption('generate')
    verbose = request.config.getoption('gpglog')
    if verbose: gnupg._logger.create_logger(10)
    keyrings = [tmpfname() for i in range(2)]
    secrings = [tmpfname() for i in range(2)]
    home = os.path.dirname(os.path.abspath(__file__))
    fpubkey = [os.path.join(home, 'pubkey%i.asc' % (i + 1)) for i in range(2)]
    fseckey = [os.path.join(home, 'seckey%i.asc' % (i + 1)) for i in range(2)]