Merge pull request #130 from jMyles/mypy

Various type hints and other mypy-inspired fixes.
pull/131/head
Justin Holmes 2017-11-27 13:35:11 -08:00 committed by GitHub
commit f106235a65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1138 additions and 342 deletions

12
Pipfile
View File

@ -1,8 +1,10 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
rpcudp = {git = "https://github.com/nucypher/rpcudp", ref = "kms-dependency"}
@ -12,17 +14,21 @@ lmdb = "*"
pynacl = "*"
"pysha3" = "*"
bidict = "*"
"py-ecc" = "*"
py-ecc = "*"
sqlalchemy = "*"
twisted = "*"
pyopenssl = "*"
"service-identity" = "*"
service-identity = "*"
apistar = "*"
mypy = "*"
pytest-mypy = "*"
[dev-packages]
pytest = "*"
coverage = "*"
"pytest-cov" = "*"
pytest-cov = "*"
pdbpp = "*"
ipython = "*"
appdirs = "*"

695
Pipfile.lock generated Normal file
View File

@ -0,0 +1,695 @@
{
"_meta": {
"hash": {
"sha256": "f34600b0576547b08dbe3f8d0563a6fc7019bad8faff15ef2f0ade2fedab7af1"
},
"host-environment-markers": {
"implementation_name": "cpython",
"implementation_version": "3.6.3",
"os_name": "posix",
"platform_machine": "x86_64",
"platform_python_implementation": "CPython",
"platform_release": "4.13.0-16-generic",
"platform_system": "Linux",
"platform_version": "#19-Ubuntu SMP Wed Oct 11 18:35:14 UTC 2017",
"python_full_version": "3.6.3",
"python_version": "3.6",
"sys_platform": "linux"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"apistar": {
"hashes": [
"sha256:572cc48e27531607f2a8761009783de26daf60eb616f9b665e2c4cb8b23b473a"
],
"version": "==0.3.9"
},
"asn1crypto": {
"hashes": [
"sha256:654b7db3b120e23474e9a1e5e38d268c77e58a9e17d2cb595456c37309846494",
"sha256:0874981329cfebb366d6584c3d16e913f2a0eb026c9463efcc4aaf42a9d94d70"
],
"version": "==0.23.0"
},
"attrs": {
"hashes": [
"sha256:e7d51b70f19a4da5fe6b3c9938983e0af3b91e230edc504bd73c443d98037063",
"sha256:c78f53e32d7cf36d8597c8a2c7e3c0ad210f97b9509e152e4c37fa80869f823c"
],
"version": "==17.3.0"
},
"automat": {
"hashes": [
"sha256:2140297df155f7990f6f4c73b2ab0583bd8150db9ed2a1b48122abe66e9908c1",
"sha256:3c1fd04ecf08ac87b4dd3feae409542e9bf7827257097b2b6ed5692f69d6f6a8"
],
"version": "==0.6.0"
},
"bidict": {
"hashes": [
"sha256:d39699e569b757893cf0397148b3452357a95ecd88fd1ab0db663c77c93778f3"
],
"version": "==0.13.1"
},
"certifi": {
"hashes": [
"sha256:244be0d93b71e93fc0a0a479862051414d0e00e16435707e5bf5000f92e04694",
"sha256:5ec74291ca1136b40f0379e1128ff80e866597e4e2c1e755739a913bbc3613c0"
],
"version": "==2017.11.5"
},
"cffi": {
"hashes": [
"sha256:2c707e97ad7b0417713543be7cb87315c015bb5dd97903480168d60ebe3e313e",
"sha256:6d8c7e20eb90be9e1ccce8e8dd4ee5163b37289fc5708f9eeafc00adc07ba891",
"sha256:627298d788edcb317b6a01347428501e773f5e8f2988407231c07e50e3f6c1cf",
"sha256:bdd28cf8302eeca1b4c70ec727de384d4f6ea640b0e698934fd9b4c3bc88eeb1",
"sha256:248198cb714fe09f5c60b6acba3675d52199c6142641536796cdf89dd45e5590",
"sha256:c962cb68987cbfb70b034f153bfa467c615c0b55305d39b3237c4bdbdbc8b0f4",
"sha256:401ba2f6c1f1672b6c38670e1c00fa5f84f841edd30c32742dab5c7151cd89bf",
"sha256:1c103c0ee8235c47c4892288b2287014f33e7cb24b9d4a665be3aa744377dcb9",
"sha256:d7461ef8671ae40f991384bbc4a6b1b79f4e7175d8052584be44041996f46517",
"sha256:3ac9be5763238da1d6fa467c43e3f86472626837a478588c94165df09e62e120",
"sha256:d54a7c37f954fdbb971873c935a77ddc33690cec9b7ac254d9f948c43c32fa83",
"sha256:4d9bf1b23896bcd4d042e823f50ad36fb6d8e1e645a3dfb2fe2f070851489b92",
"sha256:61cf049b1c649d8eec360a1a1d09a61c37b9b2d542364506e8feb4afd232363d",
"sha256:ce3da410ae2ab8709565cc3b18fbe9a0eb96ea7b2189416098c48d839ecced84",
"sha256:e72d8b5056f967ecb57e166537408bc913f2f97dc568027fb6342fcfa9f81d64",
"sha256:11a8ba88ef6ae89110ef029dae7f1a293365e50bdd0c6ca973beed80cec95ae4",
"sha256:974f69112721ba2e8a6acd0f6b68a5e11432710a3eca4e4e6f4d7aaf99214ed1",
"sha256:062c66dabc3faf8e0db1ca09a6b8e308846e5d35f43bed1a68c492b0d96ac171",
"sha256:03a9b9efc280dbe6be149a7fa689f59a822df009eee633fdaf55a6f38795861f",
"sha256:8b3d6dc9981cedfb1ddcd4600ec0c7f5ac2c6ad2dc482011c7eecb4ae9c819e0",
"sha256:09b7d195d163b515ef7c2b2e26a689c9816c83d5319cceac6c36ffdab97ab048",
"sha256:943b94667749d1cfcd964e215a20b9c891deae913202ee8eacaf2b94164b155f",
"sha256:89829f5cfbcb5ad568a3d61bd23a8e33ad69b488d8f6a385e0097a4c20742a9b",
"sha256:ba78da7c940b041cdbb5aaff5afe11e8a8f25fe19564c12eefea5c5bd86930ca",
"sha256:a79b15b9bb4726672865cf5b0f63dee4835974a2b11b49652d70d49003f5d1f4",
"sha256:f6799913eb510b682de971ddef062bbb4a200f190e55cae81c413bc1fd4733c1",
"sha256:e7f5ad6b12f21b77d3a37d5c67260e464f4e9068eb0c0622f61d0e30390b31b6",
"sha256:5f96c92d5f5713ccb71e76dfa14cf819c59ecb9778e94bcb541e13e6d96d1ce5",
"sha256:5357b465e3d6b98972b7810f9969c913d365e75b09b7ba813f5f0577fe1ac9f4",
"sha256:75e1de9ba7c155d89bcf67d149b1c741df553c8158536e8d27e63167403159af",
"sha256:ab87dd91c0c4073758d07334c1e5f712ce8fe48f007b86f8238773963ee700a6"
],
"version": "==1.11.2"
},
"chardet": {
"hashes": [
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691",
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"
],
"version": "==3.0.4"
},
"constantly": {
"hashes": [
"sha256:dd2fa9d6b1a51a83f0d7dd76293d734046aa176e384bf6e33b7e44880eb37c5d",
"sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"
],
"version": "==15.1.0"
},
"coreapi": {
"hashes": [
"sha256:bf39d118d6d3e171f10df9ede5666f63ad80bba9a29a8ec17726a66cf52ee6f3",
"sha256:46145fcc1f7017c076a2ef684969b641d18a2991051fddec9458ad3f78ffc1cb"
],
"version": "==2.3.3"
},
"coreschema": {
"hashes": [
"sha256:5e6ef7bf38c1525d5e55a895934ab4273548629f16aed5c0a6caa74ebf45551f",
"sha256:9503506007d482ab0867ba14724b93c18a33b22b6d19fb419ef2d239dd4a1607"
],
"version": "==0.0.4"
},
"cryptography": {
"hashes": [
"sha256:e130218bfb20d644510f24950cbeee350b15f4b318099b627c29975f12b9b7b3",
"sha256:f2ff1dda46f63b59bf01287c9a5bc8c8278b875a30c0ef26bac807ea4c1632ce",
"sha256:2d51a144f3447d0d87e07a433a11761e6b50c3ed89de6d0406e191d52612150f",
"sha256:4cc18262270dc0266934cfdfea7199dc65b9e3b31c68ead8685eb3649498dbe4",
"sha256:1fc1c6ad9f04871399de407a4f0f555adba5c7ec68068fd27d7ceee9e493755c",
"sha256:317ab5134ea176c03d068de5094e5b6ab580af2ba42ce596536bcc2e694057bc",
"sha256:af5b36499d6790480de0b9876982d027a698149c3f195c888be53fe48faff8e7",
"sha256:58d4c74cd6e6f54a60fd32874c03ba6230c9a1673699ee16811a6b96f91faf56",
"sha256:05cb4130ebe2d591141501ed06b85072cb3be5e5a0e943a5c487bd6858adcf64",
"sha256:791e228b5df8f124bfa33384195864cb9f5420b619580258d9002f14e625312e",
"sha256:b03dc0e2ab4bf02b43cf37ecc994344dc34e90567a8a563fb7538832475974c1",
"sha256:2ec3de13c3b0c5901820a58c337aca0f00be185c49bfc2c07eee0fe0af201c64",
"sha256:af8a9241bc8e1d2c9f10b7f5c3be8540af0c20b8e9af8c8cf4412971b7f78de5",
"sha256:57b7f8be4c817032dcd2c94f4dac6204ec2e85ef1881b4a660e56e7a63529eeb",
"sha256:35eb35340fdc0b772301f9de985db8d732f3c79dbd647d06b9a8e4e111b53950",
"sha256:12a16d4c7324166d78e112892236dd07e9b734cbee267ebf58a66c0f2a6fb3ae",
"sha256:346db72935450d2fb5c807e7f2051830e9bd33ea9471cd14bbf585ea2d5b7c0d",
"sha256:d4dbf045ee55aabdeb1e8e7550783f42c6f51d70a6069bd63669f34a4408b506",
"sha256:3beb79972cc26fa7fb553e59a0e96e476cd73c29c3d80456ac6562e7b217a677",
"sha256:2d72c8cd1e2be9942052b85b1481c74b2eb36780889696ce66afe602c04b9c67",
"sha256:0764c38c8e2e83238be5821757271cd3ef91dc3ee5bd7915c6b8e255bf1ad5c8",
"sha256:06c5a28e12539485c0c9e2e561335b835f5f0fdf2d5700b49835bad8607952ba",
"sha256:68a26c353627163d74ee769d4749f2ee243866e9dac43c93bb33ebd8fbed1199"
],
"version": "==2.1.3"
},
"hyperlink": {
"hashes": [
"sha256:1ec8e11fb4f5b330f25864bf8cfd3133dff1a3637dfd14fa441297df15fc7cf9",
"sha256:bc4ffdbde9bdad204d507bd8f554f16bba82dd356f6130cb16f41422909c33bc"
],
"version": "==17.3.1"
},
"idna": {
"hashes": [
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4",
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f"
],
"version": "==2.6"
},
"incremental": {
"hashes": [
"sha256:717e12246dddf231a349175f48d74d93e2897244939173b01974ab6661406b9f",
"sha256:7b751696aaf36eebfab537e458929e194460051ccad279c72b755a167eebd4b3"
],
"version": "==17.5.0"
},
"itypes": {
"hashes": [
"sha256:c6e77bb9fd68a4bfeb9d958fea421802282451a25bac4913ec94db82a899c073"
],
"version": "==1.1.0"
},
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
],
"version": "==2.10"
},
"kademlia": {
"git": "https://github.com/nucypher/kademlia",
"ref": "kms-dependency"
},
"lmdb": {
"hashes": [
"sha256:724234c4df6a8ef987957b6db92417c42afc3091d88765e9a8e52143b1309948",
"sha256:348ee17a618ea3afb1c981d262bfa0f2105d2833858747ef1b2c7307a09b5b18",
"sha256:8d7b1ac8dcd06c0a4f01569f8b4dfdcccf8baeaf1fed58fe6ec686de811168e7",
"sha256:6ec5220c3b84469f613c1332363f8a316c4742236f380b7c4e20f317690c8ff7",
"sha256:46f331b63a6daacc4a160a7d587f1a0f2caebaf37a72d1884e4d80fc6539e2cc",
"sha256:335a549e8f93e69edf154f1b760f5225f0f4799b15e7e85892e6f05c131062bb",
"sha256:70d75e3def0d28e08c1684140a63edeb2bbc8a871a4d510e84460a3257ca8234",
"sha256:cb95bb4ffcb1b586f6034a3c60172a6ab757d09dc925e04c5d8e2ce8076230a7",
"sha256:1edd081cf17fa75ca93adc20bca17d0d87bbbc214cd7cfd397faa4d2a9f5acf2",
"sha256:e7cefb0677fd2f8bc2df45846022fca9d0d95d2fdbd8490d4c5ea4b32d5cd014",
"sha256:41a303e7fbfd8e54f32e66a91ff24631eccd2bc904780e833116891712e47b67",
"sha256:df568e740ba04287ae47e50992730717418a142772d1e8596638f4841103736d",
"sha256:f891bb6fb0f745191af601e036f92afc509ee291749e23f4c8ac88ed8fb3c993",
"sha256:c56981dde168316df6307dfd4fcb53363a424f01e4c1b8dddca1609f4fcea2e9",
"sha256:4068da0133368ffd79afddbc466e2d8b573e14e4047340f91d8ec0f4f9e27bec",
"sha256:31675ce3415172ab6da3606d9397b3326bed685d49b2b4db09de4cd10d14e698",
"sha256:6bd267e925aeaff5a7d1a035ade4c3db2b18be3c69e00a55ee7f91ebb63cf0ee",
"sha256:1ea17dabcbfc1824ebedb7b40250f8157e80c0316d03e2bca3dce173386cdb0b",
"sha256:43779624301537e4d7ee9512a2562ea10b937bca562b16ecddde97db1985cffc",
"sha256:d2bbe03e76fc7cd99d8c94102aa4a10b900544096fdd610746c7118bc56e9c2a",
"sha256:aca81006366fb8fadc64c1ce90995ed08fe7bb075f55bed59631078fd2d76a04",
"sha256:78f46e6bb36750ff94d87a05c3f22778e909b4b035fa6d9cdd4dafd4c9ef49e2",
"sha256:744b1d0d4d965e72cec69405e23dafff1f162595697bace489699e9b3f5818ea",
"sha256:ebf73217e208a6ff5d9fe4ecdaed08f09767aaaecc50ac4a10cbdc050f4e056a",
"sha256:e8280656248d7c10aadc74e694bdb0947c3dbb096f9d6dc42e2441471b070e52",
"sha256:146b085b698bf480b35da4eac3a0bd8e331e002a9bafa69842867a879258b775"
],
"version": "==0.93"
},
"markupsafe": {
"hashes": [
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
],
"version": "==1.0"
},
"npre": {
"editable": true,
"git": "https://github.com/nucypher/nucypher-pre-python",
"ref": "kms-dependency"
},
"py": {
"hashes": [
"sha256:8cca5c229d225f8c1e3085be4fcf306090b00850fefad892f9d96c7b6e2f310f",
"sha256:ca18943e28235417756316bfada6cd96b23ce60dd532642690dcfdaba988a76d"
],
"version": "==1.5.2"
},
"py-ecc": {
"hashes": [
"sha256:f747ea69d40160c0a158c116bc3656eece9457cec446c8bfaffffd62f835de56",
"sha256:c7808a70c08bfc5c07b328f4df4406cfd3e365dd81f63bdd997c3c1eae34334a"
],
"version": "==1.4.2"
},
"pyasn1": {
"hashes": [
"sha256:5eac8d0c1c1282842c9145ae134990a1baf7616eb4cee9129213fad76eba4f54",
"sha256:960a603e677897ea29b9a1327b789b7b8a9e187a89e05fed9c3152b3b7c22954",
"sha256:4bb562b9f1fc4526028b2aa4dc027dce08f3ade0780abc593a02ce6dbade6e6c",
"sha256:8fa8884056bd5b2c92ca1685e6344121b6b43718b44f0c6eb223958003c9d14a",
"sha256:16e896433f84575f0636cd9aa8b24659689268a62e00f17235e1fc23c6b00b25",
"sha256:bb6f5d5507621e0298794bc3e75b8f963e886cee388a378ab58e5c35ac024276",
"sha256:60bf78784b117979f5517c38308f6965fff6c803660fbb16368d94433953b62a",
"sha256:4a677c6c9e484977ed6c6a93714ff06ac374220408afeaeef4ef2af652af0f3d",
"sha256:b16fb6097d00bbafc114861b16ea41cfe63e32fed1bdc7cd5905a3e02a992fa3",
"sha256:8212bde51ec192e30654efe10e636082738ed728e316049f3685d66b8c92941c",
"sha256:8d4f0971682203bdfc93740ee7d3fcba0a7f55629451dbe2d32af2335c55b2be",
"sha256:187f2a66d617683f8e82d5c00033b7c8a0287e1da88a9d577aebec321cad4965"
],
"version": "==0.3.7"
},
"pyasn1-modules": {
"hashes": [
"sha256:ea8b89f79724c3cf4ca88bc7327964f0750e5219618805dcc85ca0fdae9e5b34",
"sha256:16b086729c7af47a67c9e64cea2f763975b602155319b6c63f1f20e5f0179be7",
"sha256:7fc70766b8ef5a62eb43767cd7a1c1b3a6aa5095b263a6f2a734987fd90a35d6",
"sha256:92caf877c06c033786f0149dd37ea1abfd2c398a007bb40ae6b1f2c96804c1b2",
"sha256:018225e6718cfff7e515bd23efe8c0956e5226e3a416ba829e695c607e8ac58f",
"sha256:773641c73f6eaac19b5ed7c3e6c3e733dc43b494282ef067325ea6583763f531",
"sha256:3350c74c22eb821acfd22ecf4bbb9abfc1de2bd5befb5befd5b1b7ede2d92ace",
"sha256:6c457b5037e6a145a43bf3b5b1db622d20a08d4d1ad9a9bdc22dbef7229b250c",
"sha256:d37774d5de3887b1cdce7415209e92da49fcd13b99db1c44c179a93a5f87c8b2",
"sha256:6d8ad92e399b3140259b2c5249c49e67806a3eee332ed3734da807733925f04e",
"sha256:b437be576bdf440fc0e9307a4334303d117a577f2d809ecb9abd715539cb0109",
"sha256:1d303eed5aa54cafeca209d16b8c7ea2c6064735fb61f1bee2e0ed63a0816988"
],
"version": "==0.1.5"
},
"pycparser": {
"hashes": [
"sha256:99a8ca03e29851d96616ad0404b4aad7d9ee16f25c9f9708a11faf2810f7b226"
],
"version": "==2.18"
},
"pynacl": {
"hashes": [
"sha256:64d5132fdb54bcfdcc7a531c03980d630469258d8e70d7594ea0d27366fcf834",
"sha256:aa788cff8c027d7d621806d740fb4759028b0bba6dcdf4f316092698ecaad9ab",
"sha256:352584f80d52d53849037d60b90be787638f86d0234209959f68496300425013",
"sha256:abe8bf8908e735db77fd88b972ab1de240962ef91e6b044942f60cfe5a785107",
"sha256:b83e4232b43a52c8802234d575f992f82c1e9c466acd911983613a3823c4dc4e",
"sha256:c7c165b5d43198751651b33d562e57a7bd55d57062678ad14453ef715be415c4",
"sha256:74101b214305b6856d20593ee7e9f77a8f12e24a19caeda7f5fef3638cd8fe17",
"sha256:df4e44c34f3d4d199a06e1c11b7a7357e9adfdfaab34211991b33a58a155daba",
"sha256:976667758a7eb2e555cefbd131df54eea9967002beb73d06f1943127993db566",
"sha256:77c3b6d6fbf8b2137d41be9aed9eff30232287aeba00a6d353aa48fc9de4c55e",
"sha256:2fda81371b8dae1d18e2df9ce06961b66ef0b4226c6c98287e3e4661d9e64317",
"sha256:5bd2f0652fafd61669cbeb6312e9a87817e2e9613a471c588fd2e108e3119bb8",
"sha256:d0c0ca0a0548ed67301424f143c2b8b9d97956b152f8a56a7ebbdadb2071737d",
"sha256:0a85d5dde05a48377675f0c60d4b96127cc1b70097e24f4a4557ae3fa18a0038",
"sha256:8e194ea19c447c4caa94a84316412ad11cfb61f029d408fd4bdc1164ec694578",
"sha256:c05b6e17903509b6fb24f1c41c9760a33a0e0ed2a5aedc8eb9d988e5226377ce",
"sha256:afd47e36aaad8a3b6b92c98e45ca0e7de9627b51d577920af2e2620794503ea1",
"sha256:ac23923052341f35369be898c9673774937aad500fd5693365e3e5e509cbc664",
"sha256:2a8efeb6d442322836e70e6df0094ce8ea46e156e2b4ea38a86fd553c5665fff",
"sha256:189410422028e7b0543dee6aca3da026bbd66bbad078143c46c5a3faf2733acb",
"sha256:5be1af61b69a8dcc0264777c206305a7156c216ba98f6a7864254dfe60be35cf",
"sha256:a018ee272dc064a50cd799fc265d634c54e64a8bdba7a914877f9e1d32184e5e",
"sha256:45c5bcdf8ddefe2e9381f5d37fe778bbda6991fe7004e0b1ea3570df2fc07207"
],
"version": "==1.2.0"
},
"pyopenssl": {
"hashes": [
"sha256:aade9985b93eaec51b0c0a2a60d14bb8dcff1ff8e36fe542e3c22812ec07315e",
"sha256:29630b9064a82e04d8242ea01d7c93d70ec320f5e3ed48e95fcabc6b1d0f6c76"
],
"version": "==17.3.0"
},
"pysha3": {
"hashes": [
"sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9",
"sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf",
"sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5",
"sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f",
"sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b",
"sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d",
"sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603",
"sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24",
"sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48",
"sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f",
"sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608",
"sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07",
"sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d",
"sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9",
"sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8",
"sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77",
"sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4",
"sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030",
"sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef",
"sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0",
"sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e"
],
"version": "==1.0.2"
},
"pytest": {
"hashes": [
"sha256:241d7e7798d79192a123ceaf64c602b4d233eacf6d6e42ae27caa97f498b7dc6",
"sha256:6d5bd4f7113b444c55a3bbb5c738a3dd80d43563d063fc42dcb0aaefbdd78b81"
],
"version": "==3.2.5"
},
"requests": {
"hashes": [
"sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
"sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
],
"version": "==2.18.4"
},
"rpcudp": {
"git": "https://github.com/nucypher/rpcudp",
"ref": "kms-dependency"
},
"service-identity": {
"hashes": [
"sha256:0e76f3c042cc0f5c7e6da002cf646f59dc4023962d1d1166343ce53bdad39e17",
"sha256:4001fbb3da19e0df22c47a06d29681a398473af4aa9d745eca525b3b2c2302ab"
],
"version": "==17.0.0"
},
"six": {
"hashes": [
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
],
"version": "==1.11.0"
},
"sqlalchemy": {
"hashes": [
"sha256:8b79a5ed91cdcb5abe97b0045664c55c140aec09e5dd5c01303e23de5fe7a95a"
],
"version": "==1.1.15"
},
"twisted": {
"hashes": [
"sha256:7bc3cdfd1ca5e5b84c7936db3c2cb2feb7d5b77410e713fd346da095a3b6a1d2",
"sha256:716805e624f9396fcc1f47e8aef68e629fd31599a74855b6e1636122c042458d",
"sha256:0da1a7e35d5fcae37bc9c7978970b5feb3bc82822155b8654ec63925c05af75c"
],
"version": "==17.9.0"
},
"uritemplate": {
"hashes": [
"sha256:01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd",
"sha256:1b9c467a940ce9fb9f50df819e8ddd14696f89b9a8cc87ac77952ba416e0a8fd",
"sha256:c02643cebe23fc8adb5e6becffe201185bf06c40bda5c0b4028a93f1527d011d"
],
"version": "==3.0.0"
},
"urllib3": {
"hashes": [
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
],
"version": "==1.22"
},
"werkzeug": {
"hashes": [
"sha256:e8549c143af3ce6559699a01e26fa4174f4c591dbee0a499f3cd4c3781cdec3d",
"sha256:903a7b87b74635244548b30d30db4c8947fe64c5198f58899ddcd3a13c23bb26"
],
"version": "==0.12.2"
},
"whitenoise": {
"hashes": [
"sha256:15f43b2e701821b95c9016cf469d29e2a546cb1c7dead584ba82c36f843995cf",
"sha256:9d81515f2b5b27051910996e1e860b1332e354d9e7bcf30c98f21dcb6713e0dd"
],
"version": "==3.3.1"
},
"zope.interface": {
"hashes": [
"sha256:9902d5fc11309e17cdce6574243dc114b9c30de5c60ab53c90f6e3e962688565",
"sha256:4cb1c56b0356da9a33249ef77a688c47107f54191c12a0055d284b6bee7f447e",
"sha256:ff20038fbc0e7ea050a7e28fcb8ae6ed8378a8d08ac70b848ea39960dda86bbf",
"sha256:f6868378fffbb8651f1f8a767d17e42aed39926c8f6bb9c56f184022fe6c2090",
"sha256:a6375035a4b45d199a8b990e3a2f6b71906c318c56dfc14b2d58350b6ca59392",
"sha256:dec19181cf6af58ccb8ba3fa3ca9d4ec555b2f3cb31f589f6e86d15df0926c31",
"sha256:b8f3491c9df4f0ffed32b275033e74041f420e5dcdefa4b1500d753c64ef42cf",
"sha256:5d8813e438ab67a793b09e1223742b757dd95a4a64d466855a53cb113cc9c9c4",
"sha256:5a8cc535f4212b134e66a3e1c6b93b19d453dbad0e2f89d0df2c01deefc8cad9",
"sha256:bd626cd76b7e5cbecac9d3e0dd8f98e3eada15ead95713238a523f877327633d",
"sha256:16fe824b3d93ee0629aa1f04848a1b515d6b5dc9e98cc7a04feaa35fdb0de5f1",
"sha256:f47d4138405eb67e5f059b9ab74e0a1147adc3277f5fe37d5bae5209b67e89e7",
"sha256:8dfdc1588db31895f81bcba6c36dc981b4cf4a526c62eae3745bbfbe102477ef",
"sha256:88e3d54e88a601f45d03e2a062d5d16852d20e0863a92c19260ae72e2586378a",
"sha256:3d033abd27cd54157cf42a3bfd4d8c28d7fc5c6f775df3332307d2632a79925b",
"sha256:a21d69de2ee89fc59de93e7a43c0379ecedb5149739ff94e910c2bf0ca18e181",
"sha256:aef398a5b92e70b8152d2c4850bad0fe185adb50d948f32d0bba5694d82b67c7",
"sha256:11b068fc9916556f3820f38c2376c28d8e55e4a2c51c34915aaac38b75706d2e",
"sha256:78321a6c0c8cc6ac928e44ef04d50384bc864a7f5e3c25b84110da2ede83739f",
"sha256:4be05f79e952793f31a0c2d6a0672c81a3300315da587ce6a590357595217005",
"sha256:1d954d557b63124a65f2247ac6ed66fa36df18d1e8538d08c9b432e808a634de",
"sha256:a16a3e07511fb6806bb48c8c661d38cdb91cd4bc6c2b6b0b173e72362ec1ceb4",
"sha256:d6d26d5dfbfd60c65152938fcb82f949e8dada37c041f72916fef6621ba5c5ce"
],
"version": "==4.4.3"
}
},
"develop": {
"appdirs": {
"hashes": [
"sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e",
"sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"
],
"version": "==1.4.3"
},
"certifi": {
"hashes": [
"sha256:244be0d93b71e93fc0a0a479862051414d0e00e16435707e5bf5000f92e04694",
"sha256:5ec74291ca1136b40f0379e1128ff80e866597e4e2c1e755739a913bbc3613c0"
],
"version": "==2017.11.5"
},
"chardet": {
"hashes": [
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691",
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"
],
"version": "==3.0.4"
},
"codecov": {
"hashes": [
"sha256:ad82f054837b02081f86ed1eb6c04cddc029fbc734eaf92ff73da1db3a79188b",
"sha256:db1c182ca896244d8644d8410a33f6f6dd1cc24d80209907a65077445923f00c"
],
"version": "==2.0.9"
},
"coverage": {
"hashes": [
"sha256:d1ee76f560c3c3e8faada866a07a32485445e16ed2206ac8378bd90dadffb9f0",
"sha256:007eeef7e23f9473622f7d94a3e029a45d55a92a1f083f0f3512f5ab9a669b05",
"sha256:17307429935f96c986a1b1674f78079528833410750321d22b5fb35d1883828e",
"sha256:845fddf89dca1e94abe168760a38271abfc2e31863fbb4ada7f9a99337d7c3dc",
"sha256:3f4d0b3403d3e110d2588c275540649b1841725f5a11a7162620224155d00ba2",
"sha256:4c4f368ffe1c2e7602359c2c50233269f3abe1c48ca6b288dcd0fb1d1c679733",
"sha256:f8c55dd0f56d3d618dfacf129e010cbe5d5f94b6951c1b2f13ab1a2f79c284da",
"sha256:cdd92dd9471e624cd1d8c1a2703d25f114b59b736b0f1f659a98414e535ffb3d",
"sha256:2ad357d12971e77360034c1596011a03f50c0f9e1ecd12e081342b8d1aee2236",
"sha256:e9a0e1caed2a52f15c96507ab78a48f346c05681a49c5b003172f8073da6aa6b",
"sha256:eea9135432428d3ca7ee9be86af27cb8e56243f73764a9b6c3e0bda1394916be",
"sha256:700d7579995044dc724847560b78ac786f0ca292867447afda7727a6fbaa082e",
"sha256:66f393e10dd866be267deb3feca39babba08ae13763e0fc7a1063cbe1f8e49f6",
"sha256:5ff16548492e8a12e65ff3d55857ccd818584ed587a6c2898a9ebbe09a880674",
"sha256:d00e29b78ff610d300b2c37049a41234d48ea4f2d2581759ebcf67caaf731c31",
"sha256:87d942863fe74b1c3be83a045996addf1639218c2cb89c5da18c06c0fe3917ea",
"sha256:358d635b1fc22a425444d52f26287ae5aea9e96e254ff3c59c407426f44574f4",
"sha256:81912cfe276e0069dca99e1e4e6be7b06b5fc8342641c6b472cb2fed7de7ae18",
"sha256:079248312838c4c8f3494934ab7382a42d42d5f365f0cf7516f938dbb3f53f3f",
"sha256:b0059630ca5c6b297690a6bf57bf2fdac1395c24b7935fd73ee64190276b743b",
"sha256:493082f104b5ca920e97a485913de254cbe351900deed72d4264571c73464cd0",
"sha256:e3ba9b14607c23623cf38f90b23f5bed4a3be87cbfa96e2e9f4eabb975d1e98b",
"sha256:82cbd3317320aa63c65555aa4894bf33a13fb3a77f079059eb5935eea415938d",
"sha256:9721f1b7275d3112dc7ccf63f0553c769f09b5c25a26ee45872c7f5c09edf6c1",
"sha256:bd4800e32b4c8d99c3a2c943f1ac430cbf80658d884123d19639bcde90dad44a",
"sha256:f29841e865590af72c4b90d7b5b8e93fd560f5dea436c1d5ee8053788f9285de",
"sha256:f3a5c6d054c531536a83521c00e5d4004f1e126e2e2556ce399bef4180fbe540",
"sha256:dd707a21332615108b736ef0b8513d3edaf12d2a7d5fc26cd04a169a8ae9b526",
"sha256:2e1a5c6adebb93c3b175103c2f855eda957283c10cf937d791d81bef8872d6ca",
"sha256:f87f522bde5540d8a4b11df80058281ac38c44b13ce29ced1e294963dd51a8f8",
"sha256:a7cfaebd8f24c2b537fa6a271229b051cdac9c1734bb6f939ccfc7c055689baa",
"sha256:309d91bd7a35063ec7a0e4d75645488bfab3f0b66373e7722f23da7f5b0f34cc",
"sha256:0388c12539372bb92d6dde68b4627f0300d948965bbb7fc104924d715fdc0965",
"sha256:ab3508df9a92c1d3362343d235420d08e2662969b83134f8a97dc1451cbe5e84",
"sha256:43a155eb76025c61fc20c3d03b89ca28efa6f5be572ab6110b2fb68eda96bfea",
"sha256:f98b461cb59f117887aa634a66022c0bd394278245ed51189f63a036516e32de",
"sha256:b6cebae1502ce5b87d7c6f532fa90ab345cfbda62b95aeea4e431e164d498a3d",
"sha256:a4497faa4f1c0fc365ba05eaecfb6b5d24e3c8c72e95938f9524e29dadb15e76",
"sha256:2b4d7f03a8a6632598cbc5df15bbca9f778c43db7cf1a838f4fa2c8599a8691a",
"sha256:1afccd7e27cac1b9617be8c769f6d8a6d363699c9b86820f40c74cfb3328921c"
],
"version": "==4.4.2"
},
"decorator": {
"hashes": [
"sha256:95a26b17806e284452bfd97fa20aa1e8cb4ee23542bda4dbac5e4562aa1642cd",
"sha256:7cb64d38cb8002971710c8899fbdfb859a23a364b7c99dab19d1f719c2ba16b5"
],
"version": "==4.1.2"
},
"fancycompleter": {
"hashes": [
"sha256:d2522f1f3512371f295379c4c0d1962de06762eb586c199620a2a5d423539b12"
],
"version": "==0.8"
},
"idna": {
"hashes": [
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4",
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f"
],
"version": "==2.6"
},
"ipython": {
"hashes": [
"sha256:fcc6d46f08c3c4de7b15ae1c426e15be1b7932bcda9d83ce1a4304e8c1129df3",
"sha256:51c158a6c8b899898d1c91c6b51a34110196815cc905f9be0fa5878e19355608"
],
"version": "==6.2.1"
},
"ipython-genutils": {
"hashes": [
"sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8",
"sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"
],
"version": "==0.2.0"
},
"jedi": {
"hashes": [
"sha256:3af518490ffcd00a3074c135b42511e081575e9abd115c216a34491411ceebb0",
"sha256:f6d5973573e76b1fd2ea75f6dcd6445d02d41ff3af5fc61b275b4e323d1dd396"
],
"version": "==0.11.0"
},
"parso": {
"hashes": [
"sha256:b573acb69f66a970197b5fdbbdfad3b8a417a520e383133b2b4e708f104bfc9a",
"sha256:c5279916bb417aa2bf634648ff895cf35dce371d7319744884827bfad06f8d7b"
],
"version": "==0.1.0"
},
"pdbpp": {
"hashes": [
"sha256:dde77326e4ea41439c243ed065826d53539530eeabd1b6615aae15cfbb9fda05"
],
"version": "==0.9.2"
},
"pexpect": {
"hashes": [
"sha256:2b50dd8caa5007b10b0afcf075095814780b104b4a5cf9d8fbdc8bbc754e5ca4",
"sha256:00ab0872f80f5db740499e7a1283a7c3b97bea542d72df84d83dea17d0afd2d9"
],
"markers": "sys_platform != 'win32'",
"version": "==4.3.0"
},
"pickleshare": {
"hashes": [
"sha256:c9a2541f25aeabc070f12f452e1f2a8eae2abd51e1cd19e8430402bdf4c1d8b5",
"sha256:84a9257227dfdd6fe1b4be1319096c20eb85ff1e82c7932f36efccfe1b09737b"
],
"version": "==0.7.4"
},
"prompt-toolkit": {
"hashes": [
"sha256:3f473ae040ddaa52b52f97f6b4a493cfa9f5920c255a12dc56a7d34397a398a4",
"sha256:1df952620eccb399c53ebb359cc7d9a8d3a9538cb34c5a1344bdbeb29fbcc381",
"sha256:858588f1983ca497f1cf4ffde01d978a3ea02b01c8a26a8bbc5cd2e66d816917"
],
"version": "==1.0.15"
},
"ptyprocess": {
"hashes": [
"sha256:e8c43b5eee76b2083a9badde89fd1bbce6c8942d1045146e100b7b5e014f4f1a",
"sha256:e64193f0047ad603b71f202332ab5527c5e52aa7c8b609704fc28c0dc20c4365"
],
"version": "==0.5.2"
},
"py": {
"hashes": [
"sha256:8cca5c229d225f8c1e3085be4fcf306090b00850fefad892f9d96c7b6e2f310f",
"sha256:ca18943e28235417756316bfada6cd96b23ce60dd532642690dcfdaba988a76d"
],
"version": "==1.5.2"
},
"pygments": {
"hashes": [
"sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
"sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
],
"version": "==2.2.0"
},
"pytest": {
"hashes": [
"sha256:241d7e7798d79192a123ceaf64c602b4d233eacf6d6e42ae27caa97f498b7dc6",
"sha256:6d5bd4f7113b444c55a3bbb5c738a3dd80d43563d063fc42dcb0aaefbdd78b81"
],
"version": "==3.2.5"
},
"pytest-cov": {
"hashes": [
"sha256:890fe5565400902b0c78b5357004aab1c814115894f4f21370e2433256a3eeec",
"sha256:03aa752cf11db41d281ea1d807d954c4eda35cfa1b21d6971966cc041bbf6e2d"
],
"version": "==2.5.1"
},
"requests": {
"hashes": [
"sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
"sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
],
"version": "==2.18.4"
},
"simplegeneric": {
"hashes": [
"sha256:dc972e06094b9af5b855b3df4a646395e43d1c9d0d39ed345b7393560d0b9173"
],
"version": "==0.8.1"
},
"six": {
"hashes": [
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
],
"version": "==1.11.0"
},
"traitlets": {
"hashes": [
"sha256:c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9",
"sha256:9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835"
],
"version": "==4.3.2"
},
"urllib3": {
"hashes": [
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
],
"version": "==1.22"
},
"wcwidth": {
"hashes": [
"sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c",
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e"
],
"version": "==0.1.7"
},
"wmctrl": {
"hashes": [
"sha256:d806f65ac1554366b6e31d29d7be2e8893996c0acbb2824bbf2b1f49cf628a13"
],
"version": "==0.3"
}
}
}

2
mypy.ini Normal file
View File

@ -0,0 +1,2 @@
[mypy]
ignore_missing_imports=True

View File

@ -1,6 +1,12 @@
import asyncio
import binascii
from logging import getLogger
import msgpack
from apistar import http
from apistar.core import Route
from apistar.frameworks.wsgi import WSGIApp as App
from sqlalchemy.exc import IntegrityError
from kademlia.network import Server
from kademlia.utils import digest
@ -8,9 +14,10 @@ from nkms.crypto import api as API
from nkms.crypto.api import secure_random, keccak_digest
from nkms.crypto.constants import NOT_SIGNED, NO_DECRYPTION_PERFORMED
from nkms.crypto.powers import CryptoPower, SigningPower, EncryptingPower
from nkms.crypto.signature import Signature
from nkms.crypto.utils import BytestringSplitter
from nkms.keystore.keypairs import Keypair
from nkms.network import blockchain_client
from nkms.network.blockchain_client import list_all_ursulas
from nkms.network.protocols import dht_value_splitter
from nkms.network.server import NuCypherDHTServer, NuCypherSeedOnlyDHTServer
from nkms.policy.constants import NOT_FROM_ALICE
@ -25,11 +32,8 @@ class Character(object):
_default_crypto_powerups = None
_seal = None
class NotFound(KeyError):
"""raised when we try to interact with an actor of whom we haven't learned yet."""
def __init__(self, attach_server=True, crypto_power: CryptoPower = None,
crypto_power_ups=[], is_me=True):
crypto_power_ups=[], is_me=True) -> None:
"""
:param attach_server: Whether to attach a Server when this Character is born.
:param crypto_power: A CryptoPower object; if provided, this will be the character's CryptoPower.
@ -38,7 +42,14 @@ class Character(object):
If neither crypto_power nor crypto_power_ups are provided, we give this Character all CryptoPowerUps
listed in their _default_crypto_powerups attribute.
:param is_me: Set this to True when you want this Character to represent the owner of the configuration under
which the program is being run. A Character who is_me can do things that other Characters can't, like run
servers, sign messages, and decrypt messages which are encrypted for them. Typically this will be True
for exactly one Character, but there are scenarios in which its imaginable to be represented by zero Characters
or by more than one Character.
"""
self.log = getLogger("characters")
if crypto_power and crypto_power_ups:
raise ValueError("Pass crypto_power or crypto_power_ups (or neither), but not both.")
@ -59,6 +70,13 @@ class Character(object):
else:
self._seal = StrangerSeal(self)
class NotFound(KeyError):
"""raised when we try to interact with an actor of whom we haven't learned yet."""
@classmethod
def from_pubkey_sig_bytes(cls, pubkey_sig_bytes):
return cls(is_me=False, crypto_power_ups=[SigningPower(keypair=Keypair.deserialize_key(pubkey_sig_bytes))])
def attach_server(self, ksize=20, alpha=3, id=None, storage=None,
*args, **kwargs) -> None:
self._server = self._server_class(ksize, alpha, id, storage, *args, **kwargs)
@ -87,7 +105,7 @@ class Character(object):
def learn_about_actor(self, actor):
self._actor_mapping[actor.id()] = actor
def encrypt_for(self, recipient: str, cleartext: bytes, sign: bool = True,
def encrypt_for(self, recipient: "Character", cleartext: bytes, sign: bool = True,
sign_cleartext=True) -> tuple:
"""
Looks up recipient actor, finds that actor's pubkey_enc on our keyring, and encrypts for them.
@ -101,20 +119,24 @@ class Character(object):
"""
actor = self._lookup_actor(recipient)
ciphertext = self._crypto_power.encrypt_for(actor.public_key(EncryptingPower),
cleartext)
if sign:
if sign_cleartext:
signature = self.seal(cleartext)
ciphertext = self._crypto_power.encrypt_for(actor.public_key(EncryptingPower),
signature + cleartext)
else:
ciphertext = self._crypto_power.encrypt_for(actor.public_key(EncryptingPower),
cleartext)
signature = self.seal(ciphertext)
else:
signature = NOT_SIGNED
ciphertext = self._crypto_power.encrypt_for(actor.public_key(EncryptingPower),
cleartext)
return ciphertext, signature
def verify_from(self, actor_whom_sender_claims_to_be: "Character", signature: bytes,
message: bytes, decrypt=False,
def verify_from(self, actor_whom_sender_claims_to_be: "Character", message: bytes, signature: Signature = None,
decrypt=False,
signature_is_on_cleartext=False) -> tuple:
"""
Inverse of encrypt_for.
@ -125,11 +147,15 @@ class Character(object):
:param signature_is_on_cleartext: True if we expect the signature to be on the cleartext. Otherwise, we presume that the ciphertext is what is signed.
:return: (Whether or not the signature is valid, the decrypted plaintext or NO_DECRYPTION_PERFORMED)
"""
if not signature and not signature_is_on_cleartext:
raise ValueError("You need to either provide the Signature or decrypt and find it on the cleartext.")
cleartext = NO_DECRYPTION_PERFORMED
if signature_is_on_cleartext:
if decrypt:
cleartext = self._crypto_power.decrypt(message)
message = cleartext
signature, message = BytestringSplitter(Signature)(cleartext, return_remainder=True)
else:
raise ValueError(
"Can't look for a signature on the cleartext if we're not decrypting.")
@ -175,7 +201,7 @@ class Alice(Character):
:return: Tuple(kfrags, eph_key_data)
"""
kfrags, eph_key_data = API.ecies_ephemeral_split_rekey(
alice_privkey, bytes(bob.seal), m, n)
alice_privkey, bytes(bob.seal.without_metabytes()), m, n)
return (kfrags, eph_key_data)
def publish_treasure_map(self, policy_group):
@ -228,7 +254,7 @@ class Bob(Character):
self._ursulas[ursula_interface_id] = Ursula.as_discovered_on_network(port=port, interface=interface,
pubkey_sig_bytes=ursula_pubkey_sig)
def get_treasure_map(self, policy_group, signature):
def get_treasure_map(self, policy_group):
dht_key = policy_group.treasure_map_dht_key()
@ -237,8 +263,9 @@ class Bob(Character):
packed_encrypted_treasure_map = event_loop.run_until_complete(ursula_coro)
_signature_for_ursula, pubkey_sig_alice, hrac, encrypted_treasure_map = dht_value_splitter(
packed_encrypted_treasure_map[5::], msgpack_remainder=True)
verified, packed_node_list = self.verify_from(self.alice, signature, encrypted_treasure_map,
verified, cleartext = self.verify_from(self.alice, encrypted_treasure_map,
signature_is_on_cleartext=True, decrypt=True)
alices_signature, packed_node_list = BytestringSplitter(Signature)(cleartext, return_remainder=True)
if not verified:
return NOT_FROM_ALICE
else:
@ -254,9 +281,23 @@ class Ursula(Character):
interface = None
interface_ttl = 0
def __init__(self, urulsas_keystore=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.keystore = urulsas_keystore
self._rest_app = None
@property
def rest_app(self):
if not self._rest_app:
raise AttributeError(
"This Ursula doesn't have a REST app attached. If you want one, init with is_me and attach_server.")
else:
return self._rest_app
@staticmethod
def as_discovered_on_network(port, interface, pubkey_sig_bytes):
ursula = Ursula(is_me=False, crypto_power_ups=[SigningPower(keypair=Keypair.deserialize_key(pubkey_sig_bytes))])
ursula = Ursula.from_pubkey_sig_bytes(pubkey_sig_bytes)
ursula.port = port
ursula.interface = interface
return ursula
@ -269,6 +310,12 @@ class Ursula(Character):
super().attach_server(ksize, alpha, id, storage)
routes = [
Route('/kFrag/{hrac_as_hex}', 'POST', self.set_policy),
]
self._rest_app = App(routes=routes)
def listen(self, port, interface):
self.port = port
self.interface = interface
@ -298,6 +345,24 @@ class Ursula(Character):
loop = asyncio.get_event_loop()
loop.run_until_complete(setter)
def set_policy(self, hrac_as_hex, request: http.Request):
"""
REST endpoint for setting a kFrag.
TODO: Instead of taking a Request, use the apistar typing system to type a payload and validate / split it.
TODO: Validate that the kfrag being saved is pursuant to an approved Policy (see #121).
"""
from nkms.policy.models import Policy # Avoid circular import
hrac = binascii.unhexlify(hrac_as_hex)
policy = Policy.from_ursula(request.body, self)
try:
self.keystore.add_kfrag(hrac, policy.kfrag, policy.alices_signature)
except IntegrityError:
raise
# Do something appropriately RESTful (ie, 4xx).
return # A 200, which whatever policy metadata.
class Seal(object):
"""
@ -331,6 +396,9 @@ class Seal(object):
def __len__(self):
return len(bytes(self))
def without_metabytes(self):
return self.character._crypto_power.pubkey_sig_bytes().without_metabytes()
class StrangerSeal(Seal):
"""

View File

@ -4,8 +4,9 @@ from typing import Tuple, Union, List
import sha3
from nacl.secret import SecretBox
from py_ecc.secp256k1 import N, privtopub, ecdsa_raw_recover, ecdsa_raw_sign
from nkms.crypto import _internal
from nkms.crypto import _internal
from nkms.keystore.constants import SIG_KEYPAIR_BYTE, PUB_KEY_BYTE
from npre import elliptic_curve
from npre import umbral
@ -14,7 +15,7 @@ SYSTEM_RAND = SystemRandom()
def secure_random(
num_bytes: int
num_bytes: int
) -> bytes:
"""
Returns an amount `num_bytes` of data from the OS's random device.
@ -27,13 +28,13 @@ def secure_random(
:return: bytes
"""
# TODO: Should we just use os.urandom or avoid the import w/ this?
return SYSTEM_RAND.getrandbits(num_bytes*8).to_bytes(num_bytes,
byteorder='big')
return SYSTEM_RAND.getrandbits(num_bytes * 8).to_bytes(num_bytes,
byteorder='big')
def secure_random_range(
min: int,
max: int
min: int,
max: int
) -> int:
"""
Returns a number from a secure random source betwee the range of
@ -48,7 +49,7 @@ def secure_random_range(
def keccak_digest(
*messages: bytes
*messages: bytes
) -> bytes:
"""
Accepts an iterable containing bytes and digests it returning a
@ -66,7 +67,7 @@ def keccak_digest(
def ecdsa_pub2bytes(
pubkey: Tuple[int]
pubkey: Tuple[int, int]
) -> bytes:
"""
Takes an ECDSA public key and converts to bytes.
@ -77,12 +78,12 @@ def ecdsa_pub2bytes(
"""
x = pubkey[0].to_bytes(32, byteorder='big')
y = pubkey[1].to_bytes(32, byteorder='big')
return x+y
return x + y
def ecdsa_bytes2pub(
pubkey: bytes
) -> Tuple[int]:
pubkey: bytes
) -> Tuple[int, int]:
"""
Takes a byte encoded ECDSA public key and converts to a Tuple of x, and y
@ -102,12 +103,12 @@ def ecdsa_gen_priv() -> bytes:
:return: Byte encoded ECDSA privkey
"""
privkey = secure_random_range(1, N)
return privkey.to_bytes(32, byteorder='big')
return privkey.to_bytes(32, byteorder='big') # TODO: Add metabytes.
def ecdsa_priv2pub(
privkey: bytes,
to_bytes: bool = True
privkey: bytes,
to_bytes: bool = True
) -> Union[bytes, Tuple[int]]:
"""
Returns the public component of an ECDSA private key.
@ -119,14 +120,14 @@ def ecdsa_priv2pub(
"""
pubkey = privtopub(privkey)
if to_bytes:
return ecdsa_pub2bytes(pubkey)
return SIG_KEYPAIR_BYTE + PUB_KEY_BYTE + ecdsa_pub2bytes(pubkey)
return pubkey
def ecdsa_gen_sig(
v: int,
r: int,
s: int
v: int,
r: int,
s: int
) -> bytes:
"""
Generates an ECDSA signature, in bytes.
@ -137,15 +138,15 @@ def ecdsa_gen_sig(
:return: bytestring of v, r, and s
"""
v = v.to_bytes(1, byteorder='big')
r = r.to_bytes(32, byteorder='big')
s = s.to_bytes(32, byteorder='big')
return v+r+s
_v = v.to_bytes(1, byteorder='big')
_r = r.to_bytes(32, byteorder='big')
_s = s.to_bytes(32, byteorder='big')
return _v + _r + _s
def ecdsa_load_sig(
signature: bytes
) -> Tuple[int]:
signature: bytes
) -> Tuple[int, int, int]:
"""
Loads an ECDSA signature, from a bytestring, to a tuple.
@ -160,9 +161,9 @@ def ecdsa_load_sig(
def ecdsa_sign(
msghash: bytes,
privkey: bytes
) -> Tuple[int]:
msghash: bytes,
privkey: bytes
) -> Tuple[int, int, int]:
"""
Accepts a hashed message and signs it with the private key given.
@ -176,11 +177,11 @@ def ecdsa_sign(
def ecdsa_verify(
v: int,
r: int,
s: int,
msghash: bytes,
pubkey: Union[bytes, Tuple[int]]
v: int,
r: int,
s: int,
msghash: bytes,
pubkey: Union[bytes, Tuple[int, int]]
) -> bool:
"""
Takes a v, r, s, a pubkey, and a hash of a message to verify via ECDSA.

View File

@ -1,5 +1,4 @@
# TODO: Turn these into classes?
PUBKEY_SIG_LENGTH = 64
HASH_DIGEST_LENGTH = 32
NOT_SIGNED = 445

View File

@ -13,7 +13,7 @@ _tl.pre = None
class EncryptingKeypair(object):
KEYSIZE = 32
def __init__(self, privkey: bytes = None):
def __init__(self, privkey: bytes = None) -> None:
"""
:privkey: Optional private key in a serialized form (32-byte string)
If not given, a random one is generated.

View File

@ -1,5 +1,5 @@
import inspect
from typing import Iterable, List, Tuple
from typing import Iterable, List, Tuple, Type
from nkms.crypto import api as API
from nkms.crypto.signature import Signature
@ -104,9 +104,9 @@ class CryptoPowerUp(object):
class KeyPairBasedPower(CryptoPowerUp):
_keypair_class = None
_keypair_class = keypairs.Keypair
def __init__(self, keypair: keypairs.Keypair=None, pubkey_bytes: bytes=None):
def __init__(self, keypair: keypairs.Keypair=None, pubkey_bytes: bytes=None) -> None:
if keypair and pubkey_bytes:
raise ValueError("Pass keypair or pubkey_bytes (or neither), but not both.")
elif keypair:

View File

@ -1,4 +1,5 @@
from nkms.crypto import api as API
from nkms.keystore.keypairs import PublicKey
class Signature(bytes):
@ -34,7 +35,7 @@ class Signature(bytes):
def __repr__(self):
return "{} v{}: {} - {}".format(__class__.__name__, self._v, self._r, self._s)
def verify(self, message: bytes, pubkey: bytes) -> bool:
def verify(self, message: bytes, pubkey: PublicKey) -> bool:
"""
Verifies that a message's signature was valid.
@ -43,8 +44,10 @@ class Signature(bytes):
:return: True if valid, False if invalid
"""
if not len(pubkey) == PublicKey._EXPECTED_LENGTH:
raise TypeError("Need a PublicKey of {} bytes to verify - got {}.".format(PublicKey._EXPECTED_LENGTH, len(pubkey)))
msg_digest = API.keccak_digest(message)
return API.ecdsa_verify(self._v, self._r, self._s, msg_digest, pubkey)
return API.ecdsa_verify(self._v, self._r, self._s, msg_digest, pubkey.without_metabytes())
def __bytes__(self):
"""

View File

@ -1,8 +1,8 @@
ENC_KEYPAIR_BYTE = b'E'
SIG_KEYPAIR_BYTE = b'S'
REKEY_FRAG_ID_LEN = 32
REKEY_FRAG_KEY_LEN = 32
REKEY_FRAG_ID_LEN = 33
REKEY_FRAG_KEY_LEN = 33
PUB_KEY_BYTE = b'0'
PRIV_KEY_BYTE = b'1'

View File

@ -15,7 +15,7 @@ class Keypair(object):
# TODO: Throw error if a key is called and it doesn't exist
# TODO: Maybe write a custome error ofr ^?
def __init__(self, privkey: bytes = None, pubkey: bytes = None):
def __init__(self, privkey: bytes = None, pubkey: "PublicKey" = None) -> None:
if privkey and pubkey:
self.privkey, self.pubkey = privkey, pubkey
elif not privkey and not pubkey:
@ -27,7 +27,7 @@ class Keypair(object):
self._gen_pubkey()
elif pubkey and not privkey:
# We have only the pubkey; this is a public-only pair.
self.pubkey = pubkey
self.pubkey = PublicKey(pubkey)
self.public_only = True
@staticmethod
@ -52,10 +52,25 @@ class Keypair(object):
elif keypair_byte == constants.SIG_KEYPAIR_BYTE:
if key_type_byte == constants.PUB_KEY_BYTE:
return SigningKeypair(pubkey=key)
return SigningKeypair(pubkey=key_data) # Kinda weird for the moment - we're using all 66 bytes here. TODO: Decide whether to make this the norm.
elif key_type_byte == constants.PRIV_KEY_BYTE:
return SigningKeypair(privkey=key)
else:
raise ValueError("Unable to determine which type of keypair this is - keypair_byte was {}".format(keypair_byte))
assert False
def gen_privkey(self):
"""
Generate the private key of the pair.
"""
return NotImplemented
def _gen_pubkey(self):
"""
Generate the public key of the pair.
"""
return NotImplemented
class EncryptingKeypair(Keypair):
@ -152,7 +167,7 @@ class SigningKeypair(Keypair):
self._gen_pubkey()
def _gen_pubkey(self):
self.pubkey = API.ecdsa_priv2pub(self.privkey)
self.pubkey = PublicKey(API.ecdsa_priv2pub(self.privkey))
def sign(self, msghash: bytes) -> bytes:
"""
@ -175,7 +190,7 @@ class SigningKeypair(Keypair):
:return: Boolean if the signature is valid
"""
v, r, s = API.ecdsa_load_sig(signature)
return API.ecdsa_verify(v, r, s, msghash, self.pubkey)
return API.ecdsa_verify(v, r, s, msghash, self.pubkey.without_metabytes())
def serialize_pubkey(self) -> bytes:
"""
@ -198,3 +213,11 @@ class SigningKeypair(Keypair):
constants.PRIV_KEY_BYTE +
self.privkey)
return serialized_key
class PublicKey(bytes):
_EXPECTED_LENGTH = 66
_METABYTES_LENGTH = 2
def without_metabytes(self):
return self[self._METABYTES_LENGTH::]

View File

@ -146,7 +146,7 @@ class KeyStore(object):
kfrag_data = b''
if sig:
kfrag_data += sig
kfrag_data += kfrag.id + kfrag.key
kfrag_data += bytes(kfrag)
kfrag = KeyFrag(hrac, kfrag_data)
self.session.add(kfrag)

View File

@ -1,4 +1 @@
_ursulas_on_blockchain = []
def list_all_ursulas():
return _ursulas_on_blockchain
_ursulas_on_blockchain = []

View File

@ -1,17 +1,16 @@
import msgpack
from kademlia.node import Node
from kademlia.protocol import KademliaProtocol
from kademlia.utils import digest
from nkms.crypto.api import keccak_digest
from nkms.crypto.constants import PUBKEY_SIG_LENGTH, HASH_DIGEST_LENGTH
from nkms.crypto.constants import HASH_DIGEST_LENGTH
from nkms.crypto.signature import Signature
from nkms.crypto.utils import BytestringSplitter
from nkms.keystore.keypairs import PublicKey
from nkms.network.constants import NODE_HAS_NO_STORAGE
from nkms.network.node import NuCypherNode
from nkms.network.routing import NuCypherRoutingTable
dht_value_splitter = BytestringSplitter(Signature, (bytes, PUBKEY_SIG_LENGTH), (bytes, HASH_DIGEST_LENGTH))
dht_value_splitter = BytestringSplitter(Signature, PublicKey, (bytes, HASH_DIGEST_LENGTH))
class NuCypherHashProtocol(KademliaProtocol):
@ -46,13 +45,7 @@ class NuCypherHashProtocol(KademliaProtocol):
def determine_legality_of_dht_key(self, signature, sender_pubkey_sig, message, hrac, dht_key, dht_value):
proper_key = digest(keccak_digest(bytes(sender_pubkey_sig) + bytes(hrac)))
# TODO: This try block is not the right approach - a Ciphertext class can resolve this instead.
try:
# Ursula uaddr scenario
verified = signature.verify(hrac, sender_pubkey_sig)
except Exception as e:
# trmap scenario
verified = signature.verify(msgpack.dumps(message), sender_pubkey_sig)
verified = signature.verify(hrac, sender_pubkey_sig)
if not verified or not proper_key == dht_key:
self.log.warning("Got request to store illegal k/v: {} / {}".format(dht_key, dht_value))

View File

@ -1,10 +1,18 @@
import msgpack
from npre.constants import UNKNOWN_KFRAG
from nkms.characters import Alice, Bob, Ursula
from nkms.crypto import api
from nkms.crypto.api import keccak_digest
from nkms.crypto.constants import HASH_DIGEST_LENGTH, NOT_SIGNED
from nkms.crypto.powers import EncryptingPower
from nkms.crypto.signature import Signature
from nkms.crypto.utils import BytestringSplitter
from nkms.keystore.keypairs import PublicKey
from npre.constants import UNKNOWN_KFRAG
from npre.umbral import RekeyFrag
group_payload_splitter = BytestringSplitter(PublicKey)
policy_payload_splitter = BytestringSplitter((bytes, 66)) # TODO: I wish ReKeyFrag worked with this interface.
class PolicyOffer(object):
@ -33,7 +41,7 @@ class PolicyManager(object):
class PolicyManagerForAlice(PolicyManager):
def __init__(self, owner: Alice):
def __init__(self, owner: Alice) -> None:
self.owner = owner
def create_policy_group(self,
@ -54,6 +62,7 @@ class PolicyManagerForAlice(PolicyManager):
for kfrag_id, rekey in enumerate(re_enc_keys):
policy = Policy.from_alice(
alice=self.owner,
bob=bob,
kfrag=rekey,
)
policies.append(policy)
@ -68,7 +77,7 @@ class PolicyGroup(object):
_id = None
def __init__(self, uri: str, alice: Alice, bob: Bob, policies=None):
def __init__(self, uri: bytes, alice: Alice, bob: Bob, policies=None) -> None:
self.policies = policies or []
self.alice = alice
self.bob = bob
@ -82,11 +91,9 @@ class PolicyGroup(object):
def hash(self, message):
return keccak_digest(message)
def find_n_ursulas(self, networky_stuff, offer: PolicyOffer) -> list:
def find_n_ursulas(self, networky_stuff, offer: PolicyOffer):
"""
:param networky_stuff: A compliant interface (maybe a Client instance) to be used to engage the DHT swarm.
:return: A list, with each element containing an Ursula and an OfferResult.
"""
for policy in self.policies:
try:
@ -121,12 +128,15 @@ class PolicyGroup(object):
"""
return self.hash(bytes(self.alice.seal) + self.hrac())
def transmit_payloads(self, networky_stuff):
def enact_policies(self, networky_stuff):
for policy in self.policies:
payload = policy.encrypt_payload_for_ursula()
_response = networky_stuff.animate_policy(policy.ursula,
payload) # TODO: Parse response for confirmation and update TreasureMap with new Ursula friend.
policy_payload = policy.encrypt_payload_for_ursula()
full_payload = self.alice.seal + msgpack.dumps(policy_payload)
response = networky_stuff.enact_policy(policy.ursula,
self.hrac(),
full_payload) # TODO: Parse response for confirmation.
# Assuming response is what we hope for
self.treasure_map.add_ursula(policy.ursula)
@ -152,9 +162,9 @@ class Policy(object):
hashed_part = None
_id = None
def __init__(self, alice, kfrag=UNKNOWN_KFRAG, challenge_size=20, set_id=True):
def __init__(self, alice, bob=None, kfrag=UNKNOWN_KFRAG, alices_signature=NOT_SIGNED, challenge_size=20,
set_id=True, encrypted_challenge_pack=None):
"""
:param kfrag:
The kFrag obviously, but defaults to UNKNOWN_KFRAG in case the user wants to set it later.
:param deterministic_id_portion: Probably the fingerprint of Alice's public key.
@ -163,10 +173,15 @@ class Policy(object):
:param challenge_size: The number of challenges to create in the ChallengePack.
"""
self.alice = alice
self.bob = bob
self.alices_signature = alices_signature
self.kfrag = kfrag
self.random_id_portion = api.secure_random(32) # TOOD: Where do we actually want this to live?
self.challenge_size = challenge_size
self.treasure_map = []
self.challenge_pack = []
self._encrypted_challenge_pack = encrypted_challenge_pack
@property
def id(self):
@ -190,19 +205,55 @@ class Policy(object):
@staticmethod
def from_alice(kfrag,
alice,
bob,
):
policy = Policy(alice, kfrag)
policy = Policy(alice, bob, kfrag)
policy.generate_challenge_pack()
return policy
@staticmethod
def from_ursula(group_payload, ursula):
alice_pubkey_sig, payload_encrypted_for_ursula = group_payload_splitter(group_payload,
msgpack_remainder=True)
alice = Alice.from_pubkey_sig_bytes(alice_pubkey_sig)
ursula.learn_about_actor(alice)
verified, cleartext = ursula.verify_from(alice, payload_encrypted_for_ursula,
decrypt=True, signature_is_on_cleartext=True)
if not verified:
# TODO: What do we do if it's not signed properly?
pass
alices_signature, policy_payload = BytestringSplitter(Signature)(cleartext, return_remainder=True)
kfrag_bytes, encrypted_challenge_pack = policy_payload_splitter(policy_payload, return_remainder=True)
kfrag = RekeyFrag.from_bytes(kfrag_bytes)
policy = Policy(alice=alice, alices_signature=alices_signature, kfrag=kfrag,
encrypted_challenge_pack=encrypted_challenge_pack)
return policy
def payload(self):
return msgpack.dumps({b"kf": bytes(self.kfrag), b"cp": msgpack.dumps(self.challenge_pack)})
return bytes(self.kfrag) + msgpack.dumps(self.encrypted_treasure_map)
def activate(self, ursula, negotiation_result):
self.ursula = ursula
self.negotiation_result = negotiation_result
@property
def encrypted_challenge_pack(self):
if not self._encrypted_challenge_pack:
if not self.bob:
raise TypeError("This Policy doesn't have a Bob, so there's no way to encrypt a ChallengePack for Bob.")
else:
self._encrypted_challenge_pack = self.alice.encrypt_for(self.bob, msgpack.dumps(self.challenge_pack))
return self._encrypted_challenge_pack
@encrypted_challenge_pack.setter
def encrypted_treasure_map(self, ecp):
self._encrypted_challenge_pack = ecp
def generate_challenge_pack(self):
if self.kfrag == UNKNOWN_KFRAG:
# TODO: Test this branch
@ -211,15 +262,15 @@ class Policy(object):
# TODO: make this work instead of being random. See #46.
import random
self.challenge_pack = [(random.getrandbits(32), random.getrandbits(32)) for x in
range(self.challenge_size)]
self._challenge_pack = [(random.getrandbits(32), random.getrandbits(32)) for x in
range(self.challenge_size)]
return True
def encrypt_payload_for_ursula(self):
"""
Craft an offer to send to Ursula.
"""
return self.alice.encrypt_for(self.ursula, self.payload())
return self.alice.encrypt_for(self.ursula, self.payload())[0] # We don't need the signature separately.
class TreasureMap(object):

View File

@ -47,7 +47,7 @@ def test_actor_with_signing_power_can_sign():
# ...or to get the signer's public key for verification purposes.
sig = api.ecdsa_load_sig(bytes(signature))
verification = api.ecdsa_verify(*sig, api.keccak_digest(message), seal_of_the_signer)
verification = api.ecdsa_verify(*sig, api.keccak_digest(message), seal_of_the_signer.without_metabytes())
assert verification is True
@ -71,7 +71,7 @@ def test_anybody_can_verify():
signature = alice.seal(message)
# Our everyman can verify it.
verification, cleartext = somebody.verify_from(alice, signature, message, decrypt=False)
verification, cleartext = somebody.verify_from(alice, message, signature, decrypt=False)
assert verification is True
assert cleartext is NO_DECRYPTION_PERFORMED
@ -101,7 +101,7 @@ def test_signing_only_power_cannot_encrypt():
can_sign_but_not_encrypt.learn_about_actor(ursula)
# The Character has the message ready...
cleartext = "This is Officer Rod Farva. Come in, Ursula! Come in Ursula!"
cleartext = b"This is Officer Rod Farva. Come in, Ursula! Come in Ursula!"
# But without the proper PowerUp, no encryption happens.
with pytest.raises(NoEncryptingPower) as e_info:
@ -122,4 +122,4 @@ def test_character_with_encrypting_power_can_encrypt():
ciphertext, signature = can_sign_and_encrypt.encrypt_for(ursula, cleartext, sign=False)
assert signature == NOT_SIGNED
assert ciphertext is not None # annnd fail.
assert ciphertext is not None

View File

@ -2,7 +2,7 @@ import nkms.db
import shutil
import os
import appdirs
from .fixtures import *
def pytest_runtest_setup(item):
# Monkey-patching for tests so that we don't overwrite the default db

View File

@ -1,10 +1,13 @@
import unittest
import random
import unittest
import sha3
from nacl.utils import EncryptedMessage
from npre import umbral
from npre import elliptic_curve as ec
from nkms.crypto import api
from nkms.keystore.keypairs import PublicKey
from npre import elliptic_curve as ec
from npre import umbral
class TestCrypto(unittest.TestCase):
@ -85,7 +88,7 @@ class TestCrypto(unittest.TestCase):
pubkey_bytes = api.ecdsa_priv2pub(privkey)
self.assertEqual(bytes, type(pubkey_bytes))
pubkey = api.ecdsa_bytes2pub(pubkey_bytes)
pubkey = api.ecdsa_bytes2pub(pubkey_bytes[PublicKey._METABYTES_LENGTH::])
self.assertEqual(tuple, type(pubkey))
self.assertEqual(2, len(pubkey))
self.assertEqual(int, type(pubkey[0]))
@ -106,7 +109,7 @@ class TestCrypto(unittest.TestCase):
# Test Serialization
pubkey = api.ecdsa_priv2pub(privkey)
self.assertEqual(bytes, type(pubkey))
self.assertEqual(64, len(pubkey))
self.assertEqual(PublicKey._EXPECTED_LENGTH, len(pubkey))
# Test no serialization
pubkey = api.ecdsa_priv2pub(privkey, to_bytes=False)
@ -271,7 +274,7 @@ class TestCrypto(unittest.TestCase):
# Check no serialization
rekey = api.ecies_rekey(self.privkey_a_bytes, self.privkey_b_bytes,
to_bytes=False)
to_bytes=False)
self.assertEqual(umbral.RekeyFrag, type(rekey))
self.assertEqual(ec.ec_element, type(rekey.key))
@ -283,7 +286,7 @@ class TestCrypto(unittest.TestCase):
# Check with conversion
frags = api.ecies_split_rekey(self.privkey_a_bytes,
self.privkey_b_bytes, 3, 4)
self.privkey_b_bytes, 3, 4)
self.assertEqual(list, type(frags))
self.assertEqual(4, len(frags))
@ -338,14 +341,10 @@ class TestCrypto(unittest.TestCase):
self.assertEqual(32, len(plain_key))
rk_eb = api.ecies_rekey(eph_priv, self.privkey_b,
to_bytes=False)
to_bytes=False)
self.assertEqual(umbral.RekeyFrag, type(rk_eb))
self.assertEqual(ec.ec_element, type(rk_eb.key))
reenc_key = api.ecies_reencrypt(rk_eb, enc_key)
dec_key = api.ecies_decapsulate(self.privkey_b, reenc_key)
self.assertEqual(plain_key, dec_key)
def test_alpha_is_resolved(self):
with self.assertRaises(ImportError):
from nkms.crypto import _alpha

67
tests/fixtures.py Normal file
View File

@ -0,0 +1,67 @@
import datetime
import pytest
from nkms.characters import congregate, Alice, Bob
from nkms.network import blockchain_client
from nkms.policy.constants import NON_PAYMENT
from nkms.policy.models import PolicyManagerForAlice, PolicyOffer
from tests.utilities import NUMBER_OF_URSULAS_IN_NETWORK, MockNetworkyStuff, make_ursulas, \
URSULA_PORT, EVENT_LOOP
@pytest.fixture(scope="session")
def alices_policy_group(alice, bob):
"""
Creates a PolicyGroup, in a manner typical of how Alice might do it, with a unique uri.
"""
alice.__resource_id += b"/unique-again" # A unique name each time, like a path.
n = NUMBER_OF_URSULAS_IN_NETWORK
policy_manager = PolicyManagerForAlice(alice)
policy_group = policy_manager.create_policy_group(
bob,
alice.__resource_id,
m=3,
n=n,
)
return policy_group
@pytest.fixture(scope="session")
def enacted_policy_group(alices_policy_group, ursulas):
# Alice has a policy in mind and knows of enough qualifies Ursulas; she crafts an offer for them.
deposit = NON_PAYMENT
contract_end_datetime = datetime.datetime.now() + datetime.timedelta(days=5)
offer = PolicyOffer(alices_policy_group.n, deposit, contract_end_datetime)
networky_stuff = MockNetworkyStuff(ursulas)
alices_policy_group.find_n_ursulas(networky_stuff, offer)
alices_policy_group.enact_policies(networky_stuff)
return alices_policy_group
@pytest.fixture(scope="session")
def alice():
ALICE = Alice()
ALICE.attach_server()
ALICE.server.listen(8471)
ALICE.__resource_id = b"some_resource_id"
EVENT_LOOP.run_until_complete(ALICE.server.bootstrap([("127.0.0.1", URSULA_PORT)]))
return ALICE
@pytest.fixture(scope="session")
def bob(alice, ursulas):
BOB = Bob(alice=alice)
BOB.attach_server()
BOB.server.listen(8475)
EVENT_LOOP.run_until_complete(BOB.server.bootstrap([("127.0.0.1", URSULA_PORT)]))
congregate(alice, BOB, *ursulas)
return BOB
@pytest.fixture(scope="session")
def ursulas():
URSULAS = make_ursulas(NUMBER_OF_URSULAS_IN_NETWORK, URSULA_PORT)
yield URSULAS
blockchain_client._ursulas_on_blockchain.clear()

View File

@ -1,6 +1,7 @@
import unittest
from nkms.crypto import api as API
from nkms.keystore import keypairs
from nkms.keystore.keypairs import PublicKey
class TestKeypairs(unittest.TestCase):
@ -27,8 +28,7 @@ class TestKeypairs(unittest.TestCase):
self.assertEqual(32, len(self.ecdsa_keypair.privkey))
self.assertTrue(self.ecdsa_keypair.pubkey is not None)
self.assertEqual(bytes, type(self.ecdsa_keypair.pubkey))
self.assertEqual(64, len(self.ecdsa_keypair.pubkey))
self.assertEqual(PublicKey._EXPECTED_LENGTH, len(self.ecdsa_keypair.pubkey))
def test_ecdsa_keypair_signing(self):
msghash = API.keccak_digest(b'hello world!')
@ -64,8 +64,7 @@ class TestKeypairs(unittest.TestCase):
self.assertEqual(bytes, type(keypair.privkey))
self.assertEqual(32, len(keypair.privkey))
self.assertEqual(bytes, type(keypair.pubkey))
self.assertEqual(64, len(keypair.pubkey))
self.assertEqual(PublicKey._EXPECTED_LENGTH, len(keypair.pubkey))
# Test no keys (key generation)
keypair = keypairs.SigningKeypair()
@ -74,8 +73,7 @@ class TestKeypairs(unittest.TestCase):
self.assertEqual(bytes, type(keypair.privkey))
self.assertEqual(32, len(keypair.privkey))
self.assertEqual(bytes, type(keypair.pubkey))
self.assertEqual(64, len(keypair.pubkey))
self.assertEqual(PublicKey._EXPECTED_LENGTH, len(keypair.pubkey))
# Test privkey only
keypair = keypairs.SigningKeypair(privkey=self.ecdsa_keypair.privkey)
@ -83,13 +81,10 @@ class TestKeypairs(unittest.TestCase):
self.assertEqual(bytes, type(keypair.privkey))
self.assertEqual(32, len(keypair.privkey))
self.assertEqual(bytes, type(keypair.pubkey))
self.assertEqual(64, len(keypair.pubkey))
self.assertEqual(PublicKey._EXPECTED_LENGTH, len(keypair.pubkey))
# Test pubkey only
keypair = keypairs.SigningKeypair(pubkey=self.ecdsa_keypair.pubkey)
self.assertTrue(keypair.public_only is True)
self.assertEqual(bytes, type(keypair.pubkey))
self.assertEqual(64, len(keypair.pubkey))
self.assertEqual(PublicKey._EXPECTED_LENGTH, len(keypair.pubkey))

View File

@ -24,7 +24,6 @@ class TestKeyStore(unittest.TestCase):
keypair = self.ks.generate_signing_keypair()
self.assertEqual(keypairs.SigningKeypair, type(keypair))
self.assertEqual(bytes, type(keypair.privkey))
self.assertEqual(bytes, type(keypair.pubkey))
def test_key_sqlite_keystore(self):
keypair = self.ks.generate_encrypting_keypair()
@ -74,11 +73,11 @@ class TestKeyStore(unittest.TestCase):
def test_keyfrag_sqlite(self):
rand_sig = API.secure_random(65)
rand_id = API.secure_random(32)
rand_key = API.secure_random(32)
rand_id = b'\x00' + API.secure_random(32)
rand_key = b'\x00' + API.secure_random(32)
rand_hrac = API.secure_random(32)
kfrag = RekeyFrag(id=rand_id, key=rand_key)
kfrag = RekeyFrag.from_bytes(rand_id+rand_key)
self.ks.add_kfrag(rand_hrac, kfrag, sig=rand_sig)
# Check that kfrag was added

View File

@ -1,61 +1,38 @@
import asyncio
import datetime
import msgpack
import pytest
from kademlia.utils import digest
from nkms.characters import Ursula, Alice, Character, Bob, congregate
from nkms.crypto.constants import PUBKEY_SIG_LENGTH, HASH_DIGEST_LENGTH
from nkms.characters import Ursula, Character
from nkms.crypto.signature import Signature
from nkms.crypto.utils import BytestringSplitter
from nkms.network.blockchain_client import list_all_ursulas
from nkms.network import blockchain_client
from nkms.network.protocols import dht_value_splitter
from nkms.policy.constants import NON_PAYMENT
from nkms.policy.models import PolicyManagerForAlice, PolicyOffer, Policy
from tests.test_utilities import make_fake_ursulas, MockNetworkyStuff
EVENT_LOOP = asyncio.get_event_loop()
asyncio.set_event_loop(EVENT_LOOP)
URSULA_PORT = 7468
NUMBER_OF_URSULAS_IN_NETWORK = 6
URSULAS, URSULA_PORTS = make_fake_ursulas(NUMBER_OF_URSULAS_IN_NETWORK, URSULA_PORT)
ALICE = Alice()
ALICE.attach_server()
ALICE.server.listen(8471)
EVENT_LOOP.run_until_complete(ALICE.server.bootstrap([("127.0.0.1", URSULA_PORT)]))
BOB = Bob(alice=ALICE)
BOB.attach_server()
BOB.server.listen(8475)
EVENT_LOOP.run_until_complete(BOB.server.bootstrap([("127.0.0.1", URSULA_PORT)]))
congregate(ALICE, BOB, URSULAS[0])
from nkms.policy.models import Policy
from tests.utilities import MockNetworkyStuff, EVENT_LOOP, URSULA_PORT, NUMBER_OF_URSULAS_IN_NETWORK
def test_all_ursulas_know_about_all_other_ursulas():
def test_all_ursulas_know_about_all_other_ursulas(ursulas):
"""
Once launched, all Ursulas know about - and can help locate - all other Ursulas in the network.
"""
ignorance = []
for acounter, announcing_ursula in enumerate(list_all_ursulas()):
for counter, propagating_ursula in enumerate(URSULAS):
for acounter, announcing_ursula in enumerate(blockchain_client._ursulas_on_blockchain):
for counter, propagating_ursula in enumerate(ursulas):
if not digest(announcing_ursula) in propagating_ursula.server.storage:
ignorance.append((counter, acounter))
if ignorance:
pytest.fail(str(["{} didn't know about {}".format(counter, acounter) for counter, acounter in ignorance]))
def test_vladimir_illegal_interface_key_does_not_propagate():
def test_vladimir_illegal_interface_key_does_not_propagate(ursulas):
"""
Although Ursulas propagate each other's interface information, as demonstrated above, they do not propagate
interface information for Vladimir, an Evil Ursula.
"""
vladimir = URSULAS[0]
ursula = URSULAS[1]
vladimir = ursulas[0]
ursula = ursulas[1]
# Ursula hasn't seen any illegal keys.
assert ursula.server.protocol.illegal_keys_seen == []
@ -73,159 +50,153 @@ def test_vladimir_illegal_interface_key_does_not_propagate():
assert digest(illegal_key) in ursula.server.protocol.illegal_keys_seen
def test_alice_cannot_offer_policy_without_first_finding_ursula():
def test_alice_cannot_offer_policy_without_first_finding_ursula(alice, bob, ursulas):
"""
Alice can't just offer a Policy if she doesn't know whether any Ursulas are available (she gets Ursula.NotFound).
"""
networky_stuff = MockNetworkyStuff(URSULAS)
policy = Policy(Alice())
networky_stuff = MockNetworkyStuff(ursulas)
policy = Policy(alice, bob)
with pytest.raises(Ursula.NotFound):
policy_offer = policy.encrypt_payload_for_ursula()
def test_trying_to_find_unknown_actor_raises_not_found():
def test_trying_to_find_unknown_actor_raises_not_found(alice):
"""
Tony the test character can't make reference to a character he doesn't know about yet.
"""
tony_clifton = Character()
message = b"some_message"
signature = ALICE.seal(message)
signature = alice.seal(message)
# Tony can't reference Alice...
with pytest.raises(Character.NotFound):
verification = tony_clifton.verify_from(ALICE, signature, message)
verification = tony_clifton.verify_from(alice, signature, message)
# ...before learning about Alice.
tony_clifton.learn_about_actor(ALICE)
verification, NO_DECRYPTION_PERFORMED = tony_clifton.verify_from(ALICE, signature, message)
tony_clifton.learn_about_actor(alice)
verification, NO_DECRYPTION_PERFORMED = tony_clifton.verify_from(alice, message, signature)
assert verification is True
def test_alice_finds_ursula():
def test_alice_finds_ursula(alice, ursulas):
"""
With the help of any Ursula, Alice can find a specific Ursula.
"""
ursula_index = 1
all_ursulas = list_all_ursulas()
getter = ALICE.server.get(all_ursulas[ursula_index])
all_ursulas = blockchain_client._ursulas_on_blockchain
getter = alice.server.get(all_ursulas[ursula_index])
loop = asyncio.get_event_loop()
value = loop.run_until_complete(getter)
_signature, _ursula_pubkey_sig, _hrac, interface_info = dht_value_splitter(value.lstrip(b"uaddr-"), return_remainder=True)
_signature, _ursula_pubkey_sig, _hrac, interface_info = dht_value_splitter(value.lstrip(b"uaddr-"),
return_remainder=True)
port = msgpack.loads(interface_info)[0]
assert port == URSULA_PORT + ursula_index
def test_alice_has_ursulas_public_key_and_uses_it_to_encode_policy_payload():
def test_alice_creates_policy_group_with_correct_hrac(alices_policy_group):
"""
Now that Alice has found an Ursula, Alice can make a PolicyGroup, using Ursula's Public Key to encrypt each offer.
Alice creates a PolicyGroup. It has the proper HRAC, unique per her, Bob, and the uri (resource_id).
"""
# For example, a hashed path.
resource_id = b"as098duasdlkj213098asf"
alice = alices_policy_group.alice
bob = alices_policy_group.bob
# Alice has a policy in mind; she crafts an offer.
n = NUMBER_OF_URSULAS_IN_NETWORK
deposit = NON_PAYMENT
contract_end_datetime = datetime.datetime.now() + datetime.timedelta(days=5)
offer = PolicyOffer(n, deposit, contract_end_datetime)
# Now, Alice needs to find N Ursulas to whom to make the offer.
networky_stuff = MockNetworkyStuff(URSULAS)
policy_manager = PolicyManagerForAlice(ALICE)
policy_group = policy_manager.create_policy_group(
BOB,
resource_id,
m=3,
n=n,
)
networky_stuff = MockNetworkyStuff(URSULAS)
policy_group.find_n_ursulas(networky_stuff, offer)
policy_group.transmit_payloads(networky_stuff) # Until we figure out encrypt_for logic
return policy_group
assert alices_policy_group.hrac() == alices_policy_group.hash(
bytes(alice.seal) + bytes(bob.seal) + alice.__resource_id)
def test_alice_sets_treasure_map_on_network():
def test_alice_enacts_policies_in_policy_group_via_rest(enacted_policy_group):
"""
Having made a PolicyGroup, Alice creates a TreasureMap and sends it to Ursula via the DHT.
Now that Alice has made a PolicyGroup, she can enact its policies, using Ursula's Public Key to encrypt each offer
and transmitting them via REST.
"""
policy_group = test_alice_has_ursulas_public_key_and_uses_it_to_encode_policy_payload()
ursula = enacted_policy_group.policies[0].ursula
kfrag_that_was_set = ursula.keystore.get_kfrag(enacted_policy_group.hrac())
assert bool(kfrag_that_was_set) # TODO: This can be a more poignant assertion.
setter, encrypted_treasure_map, packed_encrypted_treasure_map, signature_for_bob, signature_for_ursula = ALICE.publish_treasure_map(
policy_group)
def test_alice_sets_treasure_map_on_network(enacted_policy_group, ursulas):
"""
Having enacted all the policies of a PolicyGroup, Alice creates a TreasureMap and sends it to Ursula via the DHT.
"""
alice = enacted_policy_group.alice
setter, encrypted_treasure_map, packed_encrypted_treasure_map, signature_for_bob, signature_for_ursula = alice.publish_treasure_map(
enacted_policy_group)
_set_event = EVENT_LOOP.run_until_complete(setter)
treasure_map_as_set_on_network = URSULAS[0].server.storage[
digest(policy_group.treasure_map_dht_key())]
treasure_map_as_set_on_network = ursulas[0].server.storage[
digest(enacted_policy_group.treasure_map_dht_key())]
assert treasure_map_as_set_on_network == b"trmap" + packed_encrypted_treasure_map
return treasure_map_as_set_on_network, signature_for_bob, policy_group
def test_treasure_map_with_bad_id_does_not_propagate():
def test_treasure_map_with_bad_id_does_not_propagate(alices_policy_group, ursulas):
"""
In order to prevent spam attacks, Ursula refuses to propagate a TreasureMap whose PolicyGroup ID does not comport to convention.
"""
illegal_policygroup_id = "This is not a conventional policygroup id"
policy_group = test_alice_has_ursulas_public_key_and_uses_it_to_encode_policy_payload()
alice = alices_policy_group.alice
bob = alices_policy_group.bob
treasure_map = alices_policy_group.treasure_map
treasure_map = policy_group.treasure_map
encrypted_treasure_map, signature = alice.encrypt_for(bob, treasure_map.packed_payload())
packed_encrypted_treasure_map = msgpack.dumps(encrypted_treasure_map) # TODO: #114? Do we even need to pack here?
encrypted_treasure_map, signature = ALICE.encrypt_for(BOB, treasure_map.packed_payload())
packed_encrypted_treasure_map = msgpack.dumps(encrypted_treasure_map) #TODO: #114? Do we even need to pack here?
setter = ALICE.server.set(illegal_policygroup_id, packed_encrypted_treasure_map)
setter = alice.server.set(illegal_policygroup_id, packed_encrypted_treasure_map)
_set_event = EVENT_LOOP.run_until_complete(setter)
with pytest.raises(KeyError):
URSULAS[0].server.storage[digest(illegal_policygroup_id)]
ursulas[0].server.storage[digest(illegal_policygroup_id)]
def test_treasure_map_stored_by_ursula_is_the_correct_one_for_bob():
def test_treasure_map_stored_by_ursula_is_the_correct_one_for_bob(alice, bob, ursulas, enacted_policy_group):
"""
The TreasureMap given by Alice to Ursula is the correct one for Bob; he can decrypt and read it.
"""
treasure_map_as_set_on_network = ursulas[0].server.storage[
digest(enacted_policy_group.treasure_map_dht_key())]
treasure_map_as_set_on_network, signature, policy_group = test_alice_sets_treasure_map_on_network()
_signature_for_ursula, pubkey_sig_alice, hrac, encrypted_treasure_map = dht_value_splitter(
treasure_map_as_set_on_network[5::], msgpack_remainder=True) # 5:: to account for prepended "trmap"
verified, treasure_map_as_decrypted_by_bob = BOB.verify_from(ALICE, signature,
verified, cleartext = treasure_map_as_decrypted_by_bob = bob.verify_from(alice,
encrypted_treasure_map,
decrypt=True,
signature_is_on_cleartext=True,
)
assert treasure_map_as_decrypted_by_bob == policy_group.treasure_map.packed_payload()
_alices_signature, treasure_map_as_decrypted_by_bob = BytestringSplitter(Signature)(cleartext, return_remainder=True)
assert treasure_map_as_decrypted_by_bob == enacted_policy_group.treasure_map.packed_payload()
assert verified is True
def test_bob_can_retreive_the_treasure_map_and_decrypt_it():
def test_bob_can_retreive_the_treasure_map_and_decrypt_it(enacted_policy_group, ursulas):
"""
Above, we showed that the TreasureMap saved on the network is the correct one for Bob. Here, we show
that Bob can retrieve it with only the information about which he is privy pursuant to the PolicyGroup.
"""
treasure_map_as_set_on_network, signature, policy_group = test_alice_sets_treasure_map_on_network()
networky_stuff = MockNetworkyStuff(URSULAS)
bob = enacted_policy_group.bob
networky_stuff = MockNetworkyStuff(ursulas)
# Of course, in the real world, Bob has sufficient information to reconstitute a PolicyGroup, gleaned, we presume,
# through a side-channel with Alice.
treasure_map_from_wire = BOB.get_treasure_map(policy_group, signature)
treasure_map_from_wire = bob.get_treasure_map(enacted_policy_group)
assert policy_group.treasure_map == treasure_map_from_wire
assert enacted_policy_group.treasure_map == treasure_map_from_wire
def test_treaure_map_is_legit():
def test_treaure_map_is_legit(enacted_policy_group):
"""
Sure, the TreasureMap can get to Bob, but we also need to know that each Ursula in the TreasureMap is on the network.
"""
treasure_map_as_set_on_network, signature, policy_group = test_alice_sets_treasure_map_on_network()
for ursula_interface_id in policy_group.treasure_map:
getter = ALICE.server.get(ursula_interface_id)
alice = enacted_policy_group.alice
for ursula_interface_id in enacted_policy_group.treasure_map:
getter = alice.server.get(ursula_interface_id)
loop = asyncio.get_event_loop()
value = loop.run_until_complete(getter)
signature, ursula_pubkey_sig, hrac, interface_info = dht_value_splitter(value.lstrip(b"uaddr-"), return_remainder=True)
signature, ursula_pubkey_sig, hrac, interface_info = dht_value_splitter(value.lstrip(b"uaddr-"),
return_remainder=True)
port = msgpack.loads(interface_info)[0]
assert port in URSULA_PORTS
legal_ports = range(NUMBER_OF_URSULAS_IN_NETWORK, NUMBER_OF_URSULAS_IN_NETWORK + URSULA_PORT)
assert port in legal_ports

View File

@ -1,97 +0,0 @@
import asyncio
# Kademlia emits a bunch of useful logging info; uncomment below to see it.
import logging
from nkms.network.server import NuCypherSeedOnlyDHTServer, NuCypherDHTServer
logging.basicConfig(level=logging.DEBUG)
import pytest
@pytest.mark.skip(reason="Strange. This appeared to be fixed in ab6cbaead69c9e0073de13c36078b09997d2a6ff, but still sometimes fails.")
def test_seed_only_node_does_not_store_anything():
"""
Shows that when we set up two nodes, a "full" node and a "seed-only" node,
that the "seed-only" node can set key-value pairs that the "full" node will store,
but not vice-versa.
"""
# First, let's set up two servers:
# A full node...
event_loop = asyncio.new_event_loop()
asyncio.set_event_loop(event_loop)
full_server = NuCypherDHTServer()
full_server.listen(8468)
event_loop.run_until_complete(full_server.bootstrap([("127.0.0.1", 8468)]))
# ...and a seed-only node.
seed_only_server = NuCypherSeedOnlyDHTServer()
seed_only_server.listen(8471)
event_loop.run_until_complete(seed_only_server.bootstrap([("127.0.0.1", 8468)]))
# The seed-only node is able to set a key...
key_to_store = "llamas"
value_to_store = "tons_of_things_keyed_llamas"
setter = seed_only_server.set(key_to_store, value_to_store)
event_loop.run_until_complete(setter)
# ...and retrieve it again.
getter = seed_only_server.get(key_to_store)
value = event_loop.run_until_complete(getter)
assert value == value_to_store
# The item is stored on the full server.
full_server_stored_items = list(full_server.storage.items())
assert len(full_server_stored_items) == 1
assert full_server_stored_items[0][1] == value_to_store
# ...but nothing is stored on the seed-only server.
seed_only_server_stored_items = list(seed_only_server.storage.items())
assert len(seed_only_server_stored_items) == 0
# If the full server tries to store something...
key_that_is_not_stored = b"european_swallow"
value_that_is_not_stored = b"grip_it_by_the_husk"
setter = full_server.set(key_that_is_not_stored, value_that_is_not_stored)
event_loop.run_until_complete(setter)
# ...it is *not* stored on the seed-only server.
assert len(list(seed_only_server.storage.items())) == 0
# annnnd stop.
seed_only_server.stop()
full_server.stop()
event_loop.close()
@pytest.mark.skip(reason="Strange. This appeared to be fixed in ab6cbaead69c9e0073de13c36078b09997d2a6ff, but still sometimes fails.")
def test_full_node_does_not_try_to_store_on_seed_only_node():
"""
A full node is able to determine that a seed-only node does not have the capability
to store. It doesn't waste its time trying.
"""
event_loop = asyncio.new_event_loop()
asyncio.set_event_loop(event_loop)
full_server = NuCypherDHTServer()
full_server.listen(8468)
event_loop.run_until_complete(full_server.bootstrap([("127.0.0.1", 8468)]))
seed_only_server = NuCypherSeedOnlyDHTServer()
seed_only_server.listen(8471)
event_loop.run_until_complete(seed_only_server.bootstrap([("127.0.0.1", 8468)]))
key_that_is_not_stored = b"european_swallow"
value_that_is_not_stored = b"grip_it_by_the_husk"
setter = full_server.set(key_that_is_not_stored, value_that_is_not_stored)
# Here's the interesting part.
result = event_loop.run_until_complete(setter)
assert not result
assert full_server.digests_set == 0
# annnnd stop.
seed_only_server.stop()
full_server.stop()
event_loop.close()

View File

@ -1,11 +1,17 @@
from tests.network.test_network_actors import test_alice_sets_treasure_map_on_network, BOB, URSULAS
from tests.utilities import EVENT_LOOP
def test_bob_can_follow_treasure_map():
def test_bob_can_follow_treasure_map(enacted_policy_group, ursulas):
"""
Upon receiving a TreasureMap, Bob populates his list of Ursulas with the correct number.
"""
assert len(BOB._ursulas) == 0
_treasure_map_as_set_on_network, _signature, policy_group = test_alice_sets_treasure_map_on_network()
BOB.follow_treasure_map(policy_group.treasure_map)
assert len(BOB._ursulas) == len(URSULAS)
alice = enacted_policy_group.alice
bob = enacted_policy_group.bob
assert len(bob._ursulas) == 0
setter, encrypted_treasure_map, packed_encrypted_treasure_map, signature_for_bob, signature_for_ursula = alice.publish_treasure_map(
enacted_policy_group)
_set_event = EVENT_LOOP.run_until_complete(setter)
bob.follow_treasure_map(enacted_policy_group.treasure_map)
assert len(bob._ursulas) == len(ursulas)

View File

@ -1,21 +1,38 @@
import asyncio
from nkms.characters import Ursula
from apistar.test import TestClient
from sqlalchemy.engine import create_engine
from nkms.characters import Ursula, Alice, Bob
from nkms.keystore import keystore
from nkms.keystore.db import Base
from nkms.network.node import NetworkyStuff
def make_fake_ursulas(how_many_ursulas: int, ursula_starting_port: int) -> list:
NUMBER_OF_URSULAS_IN_NETWORK = 6
EVENT_LOOP = asyncio.get_event_loop()
asyncio.set_event_loop(EVENT_LOOP)
URSULA_PORT = 7468
NUMBER_OF_URSULAS_IN_NETWORK = 6
def make_ursulas(how_many_ursulas: int, ursula_starting_port: int) -> list:
"""
:param how_many: How many Ursulas to create.
:param how_many_ursulas: How many Ursulas to create.
:param ursula_starting_port: The port of the first created Ursula; subsequent Ursulas will increment the port number by 1.
:return: A list of created Ursulas
"""
event_loop = asyncio.get_event_loop()
URSULAS = []
for _u in range(how_many_ursulas):
_URSULA = Ursula()
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
ursulas_keystore = keystore.KeyStore(engine)
_URSULA = Ursula(urulsas_keystore=ursulas_keystore)
_URSULA.attach_server()
_URSULA.listen(ursula_starting_port + _u, "127.0.0.1")
@ -26,7 +43,7 @@ def make_fake_ursulas(how_many_ursulas: int, ursula_starting_port: int) -> list:
ursula.server.bootstrap([("127.0.0.1", ursula_starting_port + _c) for _c in range(how_many_ursulas)]))
ursula.publish_interface_information()
return URSULAS, range(ursula_starting_port, ursula_starting_port + len(URSULAS))
return URSULAS # , range(ursula_starting_port, ursula_starting_port + len(URSULAS))
class MockPolicyOfferResponse(object):
@ -34,7 +51,6 @@ class MockPolicyOfferResponse(object):
class MockNetworkyStuff(NetworkyStuff):
def __init__(self, ursulas):
self.ursulas = iter(ursulas)
@ -50,5 +66,7 @@ class MockNetworkyStuff(NetworkyStuff):
else:
return super().find_ursula(id)
def animate_policy(self, ursula, payload):
def enact_policy(self, ursula, hrac, payload):
mock_client = TestClient(ursula.rest_app)
response = mock_client.post('http://localhost/kFrag/{}'.format(hrac.hex()), payload)
return True, ursula.interface_dht_key()