mirror of https://github.com/nucypher/nucypher.git
Merge pull request #130 from jMyles/mypy
Various type hints and other mypy-inspired fixes.pull/131/head
commit
f106235a65
12
Pipfile
12
Pipfile
|
@ -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 = "*"
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
# TODO: Turn these into classes?
|
||||
PUBKEY_SIG_LENGTH = 64
|
||||
HASH_DIGEST_LENGTH = 32
|
||||
|
||||
NOT_SIGNED = 445
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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::]
|
|
@ -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)
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
_ursulas_on_blockchain = []
|
||||
|
||||
def list_all_ursulas():
|
||||
return _ursulas_on_blockchain
|
||||
_ursulas_on_blockchain = []
|
|
@ -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))
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
Loading…
Reference in New Issue