Skip to content

Commit 0c857fb

Browse files
committed
Remove redundant connect() arguments, add tests
1 parent 70eb04c commit 0c857fb

10 files changed

+261
-35
lines changed

asyncpg/_testbase/__init__.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,10 @@ def tearDownClass(cls):
330330
@classmethod
331331
def get_connection_spec(cls, kwargs={}):
332332
conn_spec = cls.cluster.get_connection_spec()
333+
if kwargs.get('dsn'):
334+
conn_spec.pop('host')
333335
conn_spec.update(kwargs)
334-
if not os.environ.get('PGHOST'):
336+
if not os.environ.get('PGHOST') and not kwargs.get('dsn'):
335337
if 'database' not in conn_spec:
336338
conn_spec['database'] = 'postgres'
337339
if 'user' not in conn_spec:

asyncpg/connect_utils.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,11 @@ def _parse_hostlist(hostlist, port, *, unquote=False):
222222

223223
def _parse_connect_dsn_and_args(*, dsn, host, port, user,
224224
password, passfile, database, ssl,
225-
sslcert, sslkey, sslrootcert, sslcrl,
226225
connect_timeout, server_settings):
227226
# `auth_hosts` is the version of host information for the purposes
228227
# of reading the pgpass file.
229228
auth_hosts = None
229+
sslcert = sslkey = sslrootcert = sslcrl = None
230230

231231
if dsn:
232232
parsed = urllib.parse.urlparse(dsn)
@@ -451,12 +451,13 @@ def _parse_connect_dsn_and_args(*, dsn, host, port, user,
451451
if sslmode < SSLMode.allow:
452452
ssl = False
453453
else:
454-
ssl = ssl_module.create_default_context()
454+
ssl = ssl_module.create_default_context(
455+
ssl_module.Purpose.SERVER_AUTH)
455456
ssl.check_hostname = sslmode >= SSLMode.verify_full
456457
ssl.verify_mode = ssl_module.CERT_REQUIRED
457458
if sslmode <= SSLMode.require:
458459
ssl.verify_mode = ssl_module.CERT_NONE
459-
460+
460461
if sslcert is None:
461462
sslcert = os.getenv('PGSSLCERT')
462463

@@ -477,6 +478,7 @@ def _parse_connect_dsn_and_args(*, dsn, host, port, user,
477478

478479
if sslcrl:
479480
ssl.load_verify_locations(cafile=sslcrl)
481+
ssl.verify_flags |= ssl_module.VERIFY_CRL_CHECK_CHAIN
480482

481483
elif ssl is True:
482484
ssl = ssl_module.create_default_context()
@@ -505,8 +507,7 @@ def _parse_connect_arguments(*, dsn, host, port, user, password, passfile,
505507
statement_cache_size,
506508
max_cached_statement_lifetime,
507509
max_cacheable_statement_size,
508-
ssl, sslcert, sslkey, sslrootcert, sslcrl,
509-
server_settings):
510+
ssl, server_settings):
510511

511512
local_vars = locals()
512513
for var_name in {'max_cacheable_statement_size',
@@ -534,8 +535,7 @@ def _parse_connect_arguments(*, dsn, host, port, user, password, passfile,
534535
addrs, params = _parse_connect_dsn_and_args(
535536
dsn=dsn, host=host, port=port, user=user,
536537
password=password, passfile=passfile, ssl=ssl,
537-
sslcert=sslcert, sslkey=sslkey, sslrootcert=sslrootcert,
538-
sslcrl=sslcrl, database=database, connect_timeout=timeout,
538+
database=database, connect_timeout=timeout,
539539
server_settings=server_settings)
540540

541541
config = _ClientConfiguration(

asyncpg/connection.py

+51-24
Original file line numberDiff line numberDiff line change
@@ -1758,10 +1758,6 @@ async def connect(dsn=None, *,
17581758
max_cacheable_statement_size=1024 * 15,
17591759
command_timeout=None,
17601760
ssl=None,
1761-
sslcert=None,
1762-
sslkey=None,
1763-
sslrootcert=None,
1764-
sslcrl=None,
17651761
connection_class=Connection,
17661762
record_class=protocol.Record,
17671763
server_settings=None):
@@ -1780,10 +1776,11 @@ async def connect(dsn=None, *,
17801776
Connection arguments specified using as a single string in the
17811777
`libpq connection URI format`_:
17821778
``postgres://user:password@host:port/database?option=value``.
1783-
The following options are recognized by asyncpg: host, port,
1784-
user, database (or dbname), password, passfile, sslmode.
1785-
Unlike libpq, asyncpg will treat unrecognized options
1786-
as `server settings`_ to be used for the connection.
1779+
The following options are recognized by asyncpg: ``host``,
1780+
``port``, ``user``, ``database`` (or ``dbname``), ``password``,
1781+
``passfile``, ``sslmode``, ``sslcert``, ``sslkey``, ``sslrootcert``,
1782+
and ``sslcrl``. Unlike libpq, asyncpg will treat unrecognized
1783+
options as `server settings`_ to be used for the connection.
17871784
17881785
.. note::
17891786
@@ -1904,21 +1901,51 @@ async def connect(dsn=None, *,
19041901
.. note::
19051902
19061903
*ssl* is ignored for Unix domain socket communication.
1907-
1908-
:param sslcert:
1909-
This parameter specifies the file name of the client SSL certificate.
19101904
1911-
:param sslkey:
1912-
This parameter specifies the location for the secret key used for
1913-
the client certificate.
1905+
Example of programmatic SSL context configuration that is equivalent
1906+
to ``sslmode=verify-full&sslcert=..&sslkey=..&sslrootcert=..``:
19141907
1915-
:param sslrootcert:
1916-
This parameter specifies the name of a file containing SSL certificate
1917-
authority (CA) certificate(s).
1908+
.. code-block:: pycon
19181909
1919-
:param sslcrl
1920-
This parameter specifies the file name of the SSL certificate
1921-
revocation list (CRL).
1910+
>>> import asyncpg
1911+
>>> import asyncio
1912+
>>> import ssl
1913+
>>> async def main():
1914+
... # Load CA bundle for server certificate verification,
1915+
... # equivalent to sslrootcert= in DSN.
1916+
... sslctx = ssl.create_default_context(
1917+
... ssl.Purpose.SERVER_AUTH,
1918+
... cafile="path/to/ca_bundle.pem")
1919+
... # If True, equivalent to sslmode=verify-full, if False:
1920+
... # sslmode=verify-ca.
1921+
... sslctx.check_hostname = True
1922+
... # Load client certificate and private key for client
1923+
... # authentication, equivalent to sslcert= and sslkey= in
1924+
... # DSN.
1925+
... sslctx.load_cert_chain(
1926+
... "path/to/client.cert",
1927+
... keyfile="path/to/client.key",
1928+
... )
1929+
... con = await asyncpg.connect(user='postgres', ssl=sslctx)
1930+
... await con.close()
1931+
>>> asyncio.run(run())
1932+
1933+
Example of programmatic SSL context configuration that is equivalent
1934+
to ``sslmode=require`` (no server certificate or host verification):
1935+
1936+
.. code-block:: pycon
1937+
1938+
>>> import asyncpg
1939+
>>> import asyncio
1940+
>>> import ssl
1941+
>>> async def main():
1942+
... sslctx = ssl.create_default_context(
1943+
... ssl.Purpose.SERVER_AUTH)
1944+
... sslctx.check_hostname = False
1945+
... sslctx.verify_mode = ssl.CERT_NONE
1946+
... con = await asyncpg.connect(user='postgres', ssl=sslctx)
1947+
... await con.close()
1948+
>>> asyncio.run(run())
19221949
19231950
:param dict server_settings:
19241951
An optional dict of server runtime parameters. Refer to
@@ -1978,6 +2005,10 @@ async def connect(dsn=None, *,
19782005
.. versionchanged:: 0.22.0
19792006
The *ssl* argument now defaults to ``'prefer'``.
19802007
2008+
.. versionchanged:: 0.24.0
2009+
The ``sslcert``, ``sslkey``, ``sslrootcert``, and ``sslcrl`` options
2010+
are supported in the *dsn* argument.
2011+
19812012
.. _SSLContext: https://docs.python.org/3/library/ssl.html#ssl.SSLContext
19822013
.. _create_default_context:
19832014
https://docs.python.org/3/library/ssl.html#ssl.create_default_context
@@ -2012,10 +2043,6 @@ async def connect(dsn=None, *,
20122043
password=password,
20132044
passfile=passfile,
20142045
ssl=ssl,
2015-
sslcert=sslcert,
2016-
sslkey=sslkey,
2017-
sslrootcert=sslrootcert,
2018-
sslcrl=sslcrl,
20192046
database=database,
20202047
server_settings=server_settings,
20212048
command_timeout=command_timeout,

tests/certs/client.cert.pem

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIEAzCCAuugAwIBAgIUPfej8IQ/5bCrihqWImrq2vKPOq0wDQYJKoZIhvcNAQEL
3+
BQAwgaMxCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdPbnRhcmlvMRAwDgYDVQQHDAdU
4+
b3JvbnRvMRgwFgYDVQQKDA9NYWdpY1N0YWNrIEluYy4xFjAUBgNVBAsMDWFzeW5j
5+
cGcgdGVzdHMxHzAdBgNVBAMMFmFzeW5jcGcgdGVzdCBjbGllbnQgQ0ExHTAbBgkq
6+
hkiG9w0BCQEWDmhlbGxvQG1hZ2ljLmlvMB4XDTIxMDgwOTIxNTA1MloXDTMyMDEw
7+
NDIxNTA1MlowgZUxCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdPbnRhcmlvMRAwDgYD
8+
VQQHDAdUb3JvbnRvMRgwFgYDVQQKDA9NYWdpY1N0YWNrIEluYy4xFjAUBgNVBAsM
9+
DWFzeW5jcGcgdGVzdHMxETAPBgNVBAMMCHNzbF91c2VyMR0wGwYJKoZIhvcNAQkB
10+
Fg5oZWxsb0BtYWdpYy5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
11+
AJjiP9Ik/KRRLK9GMvoH8m1LO+Gyrr8Gz36LpmKJMR/PpwTL+1pOkYSGhOyT3Cw9
12+
/kWWLJRCvYqKgFtYtbr4S6ReGm3GdSVW+sfVRYDrRQZLPgQSPeq25g2v8UZ63Ota
13+
lPAyUPUZKpxyWz8PL77lV8psb9yv14yBH2kv9BbxKPksWOU8p8OCn1Z3WFFl0ItO
14+
nzMvCp5os+xFrt4SpoRGTx9x4QleY+zrEsYZtmnV4wC+JuJkNw4fuCdrX5k7dghs
15+
uZkcsAZof1nMdYsYiazeDfQKZtJqh5kO7mpwvCudKUWaLJJUwiQA87BwSlnCd/Hh
16+
TZDbC+zeFNjTS49/4Q72xVECAwEAAaM7MDkwHwYDVR0jBBgwFoAUi1jMmAisuOib
17+
mHIE2n0W2WnnaL0wCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwDQYJKoZIhvcNAQEL
18+
BQADggEBACbnp5oOp639ko4jn8axF+so91k0vIcgwDg+NqgtSRsuAENGumHAa8ec
19+
YOks0TCTvNN5E6AfNSxRat5CyguIlJ/Vy3KbkkFNXcCIcI/duAJvNphg7JeqYlQM
20+
VIJhrO/5oNQMzzTw8XzTHnciGbrbiZ04hjwrruEkvmIAwgQPhIgq4H6umTZauTvk
21+
DEo7uLm7RuG9hnDyWCdJxLLljefNL/EAuDYpPzgTeEN6JAnOu0ULIbpxpJKiYEId
22+
8I0U2n0I2NTDOHmsAJiXf8BiHHmpK5SXFyY9s2ZuGkCzvmeZlR81tTXmHZ3v1X2z
23+
8NajoAZfJ+QD50DrbF5E00yovZbyIB4=
24+
-----END CERTIFICATE-----

tests/certs/client.csr.pem

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-----BEGIN CERTIFICATE REQUEST-----
2+
MIIC2zCCAcMCAQAwgZUxCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdPbnRhcmlvMRAw
3+
DgYDVQQHDAdUb3JvbnRvMRgwFgYDVQQKDA9NYWdpY1N0YWNrIEluYy4xFjAUBgNV
4+
BAsMDWFzeW5jcGcgdGVzdHMxETAPBgNVBAMMCHNzbF91c2VyMR0wGwYJKoZIhvcN
5+
AQkBFg5oZWxsb0BtYWdpYy5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
6+
ggEBAJjiP9Ik/KRRLK9GMvoH8m1LO+Gyrr8Gz36LpmKJMR/PpwTL+1pOkYSGhOyT
7+
3Cw9/kWWLJRCvYqKgFtYtbr4S6ReGm3GdSVW+sfVRYDrRQZLPgQSPeq25g2v8UZ6
8+
3OtalPAyUPUZKpxyWz8PL77lV8psb9yv14yBH2kv9BbxKPksWOU8p8OCn1Z3WFFl
9+
0ItOnzMvCp5os+xFrt4SpoRGTx9x4QleY+zrEsYZtmnV4wC+JuJkNw4fuCdrX5k7
10+
dghsuZkcsAZof1nMdYsYiazeDfQKZtJqh5kO7mpwvCudKUWaLJJUwiQA87BwSlnC
11+
d/HhTZDbC+zeFNjTS49/4Q72xVECAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCG
12+
irI2ph09V/4BMe6QMhjBFUatwmTa/05PYGjvT3LAhRzEb3/o/gca0XFSAFrE6zIY
13+
DsgMk1c8aLr9DQsn9cf22oMFImKdnIZ3WLE9MXjN+s1Bjkiqt7uxDpxPo/DdfUTQ
14+
RQC5i/Z2tn29y9K09lEjp35ZhPp3tOA0V4CH0FThAjRR+amwaBjxQ7TTSNfoMUd7
15+
i/DrylwnNg1iEQmYUwJYopqgxtwseiBUSDXzEvjFPY4AvZKmEQmE5QkybpWIfivt
16+
1kmKhvKKpn5Cb6c0D3XoYqyPN3TxqjH9L8R+tWUCwhYJeDZj5DumFr3Hw/sx8tOL
17+
EctyS6XfO3S2KbmDiyv8
18+
-----END CERTIFICATE REQUEST-----

tests/certs/client.key.pem

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEowIBAAKCAQEAmOI/0iT8pFEsr0Yy+gfybUs74bKuvwbPfoumYokxH8+nBMv7
3+
Wk6RhIaE7JPcLD3+RZYslEK9ioqAW1i1uvhLpF4abcZ1JVb6x9VFgOtFBks+BBI9
4+
6rbmDa/xRnrc61qU8DJQ9RkqnHJbPw8vvuVXymxv3K/XjIEfaS/0FvEo+SxY5Tyn
5+
w4KfVndYUWXQi06fMy8Knmiz7EWu3hKmhEZPH3HhCV5j7OsSxhm2adXjAL4m4mQ3
6+
Dh+4J2tfmTt2CGy5mRywBmh/Wcx1ixiJrN4N9Apm0mqHmQ7uanC8K50pRZosklTC
7+
JADzsHBKWcJ38eFNkNsL7N4U2NNLj3/hDvbFUQIDAQABAoIBAAIMVeqM0E2rQLwA
8+
ZsJuxNKuBVlauXiZsMHzQQFk8SGJ+KTZzr5A+zYZT0KUIIj/M57fCi3aTwvCG0Ie
9+
CCE/HlRPZm8+D2e2qJlwxAOcI0qYS3ZmgCna1W4tgz/8eWU1y3UEV41RDv8VkR9h
10+
JrSaAfkWRtFgEbUyLaeNGuoLxQ7Bggo9zi1/xDJz/aZ/y4L4y8l1xs2eNVmbRGnj
11+
mPr1daeYhsWgaNiT/Wm3CAxvykptHavyWSsrXzCp0bEw6fAXxBqkeDFGIMVC9q3t
12+
ZRFtqMHi9i7SJtH1XauOC6QxLYgSEmNEie1JYbNx2Zf4h2KvSwDxpTqWhOjJ/m5j
13+
/NSkASECgYEAyHQAqG90yz5QaYnC9lgUhGIMokg9O3LcEbeK7IKIPtC9xINOrnj6
14+
ecCfhfc1aP3wQI+VKC3kiYerfTJvVsU5CEawBQSRiBY/TZZ7hTR7Rkm3s4xeM+o6
15+
2zADdVUwmTVYwu0gUKCeDKO4iD8Uhh8J54JrKUejuG50VWZQWGVgqo0CgYEAwz+2
16+
VdYcfuQykMA3jQBnXmMMK92/Toq6FPDgsa45guEFD6Zfdi9347/0Ipt+cTNg0sUZ
17+
YBLOnNPwLn+yInfFa88Myf0UxCAOoZKfpJg/J27soUJzpd/CGx+vaAHrxMP6t/qo
18+
JAGMBIyOoqquId7jvErlC/sGBk/duya7IdiT1tUCgYBuvM8EPhaKlVE9DJL9Hmmv
19+
PK94E2poZiq3SutffzkfYpgDcPrNnh3ZlxVJn+kMqITKVcfz226On7mYP32MtQWt
20+
0cc57m0rfgbYqRJx4y1bBiyK7ze3fGWpYxv1/OsNKJBxlygsAp9toiC2fAqtkYYa
21+
NE1ZD6+dmr9/0jb+rnq5nQKBgQCtZvwsp4ePOmOeItgzJdSoAxdgLgQlYRd6WaN0
22+
qeLx1Z6FE6FceTPk1SmhQq+9IYAwMFQk+w78QU3iPg6ahfyTjsMw8M9sj3vvCyU1
23+
LPGJt/34CehjvKHLLQy/NlWJ3vPgSYDi2Wzc7WgQF72m3ykqpOlfBoWHPY8TE4bG
24+
vG4wMQKBgFSq2GDAJ1ovBl7yWYW7w4SM8X96YPOff+OmI4G/8+U7u3dDM1dYeQxD
25+
7BHLuvr4AXg27LC97u8/eFIBXC1elbco/nAKE1YHj2xcIb/4TsgAqkcysGV08ngi
26+
dULh3q0GpTYyuELZV4bfWE8MjSiGAH+nuMdXYDGuY2QnBq8MdSOH
27+
-----END RSA PRIVATE KEY-----

tests/certs/client_ca.cert.pem

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIEKTCCAxGgAwIBAgIUKmL8tfNS9LIB6GLB9RpZpTyk3uIwDQYJKoZIhvcNAQEL
3+
BQAwgaMxCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdPbnRhcmlvMRAwDgYDVQQHDAdU
4+
b3JvbnRvMRgwFgYDVQQKDA9NYWdpY1N0YWNrIEluYy4xFjAUBgNVBAsMDWFzeW5j
5+
cGcgdGVzdHMxHzAdBgNVBAMMFmFzeW5jcGcgdGVzdCBjbGllbnQgQ0ExHTAbBgkq
6+
hkiG9w0BCQEWDmhlbGxvQG1hZ2ljLmlvMB4XDTIxMDgwOTIxNDQxM1oXDTQxMDgw
7+
NDIxNDQxM1owgaMxCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdPbnRhcmlvMRAwDgYD
8+
VQQHDAdUb3JvbnRvMRgwFgYDVQQKDA9NYWdpY1N0YWNrIEluYy4xFjAUBgNVBAsM
9+
DWFzeW5jcGcgdGVzdHMxHzAdBgNVBAMMFmFzeW5jcGcgdGVzdCBjbGllbnQgQ0Ex
10+
HTAbBgkqhkiG9w0BCQEWDmhlbGxvQG1hZ2ljLmlvMIIBIjANBgkqhkiG9w0BAQEF
11+
AAOCAQ8AMIIBCgKCAQEAptRYfxKiWExfZguQDva53bIqYa4lJwZA86Qu0peBUcsd
12+
E6zyHNgVv4XSMim1FH12KQ4KPKuQAcVqRMCRAHqB96kUfWQqF//fLajr0umdzcbx
13+
+UTgNux8TkScTl9KNAxhiR/oOGbKFcNSs4raaG8puwwEN66uMhoKk2pN2NwDVfHa
14+
bTekJ3jouTcTCnqCynx4qwI4WStJkuW4IPCmDRVXxOOauT7YalElYLWYtAOqGEvf
15+
noDK2Imhc0h6B5XW8nI54rVCXWwhW1v3RLAJGP+LwSy++bf08xmpHXdKkAj5BmUO
16+
QwJRiJ33Xa17rmi385egx8KpqV04YEAPdV1Z4QM6PQIDAQABo1MwUTAdBgNVHQ4E
17+
FgQUi1jMmAisuOibmHIE2n0W2WnnaL0wHwYDVR0jBBgwFoAUi1jMmAisuOibmHIE
18+
2n0W2WnnaL0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAifNE
19+
ZLZXxECp2Sl6jCViZxgFf2+OHDvRORgI6J0heckYyYF/JHvLaDphh6TkSJAdT6Y3
20+
hAb7jueTMI+6RIdRzIjTKCGdJqUetiSfAbnQyIp2qmVqdjeFoXTvQL7BdkIE+kOW
21+
0iomMqDB3czTl//LrgVQCYqKM0D/Ytecpg2mbshLfpPxdHyliCJcb4SqfdrDnKoV
22+
HUduBjOVot+6bkB5SEGCrrB4KMFTzbAu+zriKWWz+uycIyeVMLEyhDs59vptOK6e
23+
gWkraG43LZY3cHPiVeN3tA/dWdyJf9rgK21zQDSMB8OSH4yQjdQmkkvRQBjp3Fcy
24+
w2SZIP4o9l1Y7+hMMw==
25+
-----END CERTIFICATE-----

tests/certs/client_ca.cert.srl

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3DF7A3F0843FE5B0AB8A1A96226AEADAF28F3AAD

tests/certs/client_ca.key.pem

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEpAIBAAKCAQEAptRYfxKiWExfZguQDva53bIqYa4lJwZA86Qu0peBUcsdE6zy
3+
HNgVv4XSMim1FH12KQ4KPKuQAcVqRMCRAHqB96kUfWQqF//fLajr0umdzcbx+UTg
4+
Nux8TkScTl9KNAxhiR/oOGbKFcNSs4raaG8puwwEN66uMhoKk2pN2NwDVfHabTek
5+
J3jouTcTCnqCynx4qwI4WStJkuW4IPCmDRVXxOOauT7YalElYLWYtAOqGEvfnoDK
6+
2Imhc0h6B5XW8nI54rVCXWwhW1v3RLAJGP+LwSy++bf08xmpHXdKkAj5BmUOQwJR
7+
iJ33Xa17rmi385egx8KpqV04YEAPdV1Z4QM6PQIDAQABAoIBABQrKcO7CftoyEO6
8+
9CCK/W9q4arLddxg6itKVwrInC66QnqlduO7z+1GjWHZHvYqMMXH17778r30EuPa
9+
7+zB4sKBI2QBXwFlwqJvgIsQCS7edVRwWjbpoiGIM+lZpcvjD0uXmuhurNGyumXQ
10+
TJVBkyb0zfG5YX/XHB40RNMJzjFuiMPDLVQmmDE//FOuWqBG88MgJP9Ghk3J7wA2
11+
JfDPavb49EzOCSh74zJWP7/QyybzF3ABCMu4OFkaOdqso8FS659XI55QReBbUppu
12+
FRkOgao1BclJhbBdrdtLNjlETM82tfVgW56vaIrrU2z7HskihEyMdB4c+CYbBnPx
13+
QqIhkhUCgYEA0SLVExtNy5Gmi6/ZY9tcd3QIuxcN6Xiup+LgIhWK3+GIoVOPsOjN
14+
27dlVRINPKhrCfVbrLxUtDN5PzphwSA2Qddm4jg3d5FzX+FgKHQpoaU1WjtRPP+w
15+
K+t6W/NbZ8Rn4JyhZQ3Yqj264NA2l3QmuTfZSUQ5m4x7EUakfGU7G1sCgYEAzDaU
16+
jHsovn0FedOUaaYl6pgzjFV8ByPeT9usN54PZyuzyc+WunjJkxCQqD88J9jyG8XB
17+
3V3tQj/CNbMczrS2ZaJ29aI4b/8NwBNR9e6t01bY3B90GJi8S4B4Hf8tYyIlVdeL
18+
tCC4FCZhvl4peaK3AWBj4NhjvdB32ThDXSGxLEcCgYEAiA5tKHz+44ziGMZSW1B+
19+
m4f1liGtf1Jv7fD/d60kJ/qF9M50ENej9Wkel3Wi/u9ik5v4BCyRvpouKyBEMGxQ
20+
YA1OdaW1ECikMqBg+nB4FR1x1D364ABIEIqlk+SCdsOkANBlf2S+rCJ0zYUnvuhl
21+
uOHIjo3AHJ4MAnU+1V7WUTkCgYBkMedioc7U34x/QJNR3sY9ux2Xnh2zdyLNdc+i
22+
njeafDPDMcoXhcoJERiYpCYEuwnXHIlI7pvJZHUKWe4pcTsI1NSfIk+ki7SYaCJP
23+
kyLQTY0rO3d/1fiU5tyIgzomqIs++fm+kEsg/8/3UkXxOyelUkDPAfy2FgGnn1ZV
24+
7ID8YwKBgQCeZCapdGJ6Iu5oYB17TyE5pLwb+QzaofR5uO8H4pXGVQyilKVCG9Dp
25+
GMnlXD7bwXPVKa8Icow2OIbmgrZ2mzOo9BSY3BlkKbpJDy7UNtAhzsHHN5/AEk8z
26+
YycWQtMiXI+cRsYO0eyHhJeSS2hX+JTe++iZX65twV53agzCHWRIbg==
27+
-----END RSA PRIVATE KEY-----

0 commit comments

Comments
 (0)