Compare commits
1157 Commits
v1.0.3.23
...
v1.0.3.129
Author | SHA1 | Date | |
---|---|---|---|
3a87dc2223 | |||
67d3875c98 | |||
77d0f3d85c | |||
0798b95c6b | |||
c247e275f6 | |||
f17a359893 | |||
8e15707dc7 | |||
d890753ee2 | |||
00b82ad07a | |||
a21948cf16 | |||
eb583ba628 | |||
a4b61f8aab | |||
7208e63155 | |||
8f464b0838 | |||
233b799a46 | |||
d99beb9811 | |||
fefc45854e | |||
0047a5388d | |||
66064bd2eb | |||
6bd601137a | |||
eae913f809 | |||
bc8e7ce888 | |||
1ec342da1e | |||
a169179061 | |||
57b436417c | |||
0229b560e7 | |||
3c51bd3b23 | |||
b7ba97d86f | |||
0eb58e9a91 | |||
f257f9f91d | |||
8971dbc2f9 | |||
5b4e78f8d1 | |||
27f20386df | |||
9154e4264d | |||
7457e99451 | |||
c5227d9996 | |||
1447b5e8be | |||
efdb131c33 | |||
d9a0db3efc | |||
cb8c077c1e | |||
9688798a4a | |||
9a9e31c759 | |||
55c0c0ea6f | |||
43ee22f965 | |||
989a7b863e | |||
709ee54ac2 | |||
664b920a39 | |||
7ea3312534 | |||
3e9bee2d44 | |||
a571f77a40 | |||
13f2be7811 | |||
3d00611ddf | |||
576734b5cb | |||
6cd60732b5 | |||
1635e1e3fb | |||
b29b46bbc7 | |||
e45f1afd51 | |||
288dc9b626 | |||
81c6a76ea2 | |||
182f9b3cf6 | |||
e71fd4950f | |||
72d519bb45 | |||
e743b2e457 | |||
f932a34581 | |||
3543d9bd60 | |||
d387834c6c | |||
6ea15411b6 | |||
63df6ac5eb | |||
039bee5b65 | |||
be5597085b | |||
6b355cbe1b | |||
dec5d19a2f | |||
ff533994d8 | |||
221e2c7898 | |||
fb77fddcc3 | |||
c37086e000 | |||
3d6783b743 | |||
c479e6aae5 | |||
59a770e0d7 | |||
140259e737 | |||
59a391dcc9 | |||
3a1cdefa09 | |||
7be104f486 | |||
d90a65975c | |||
4e53f59a9c | |||
8e58fc128d | |||
756b6e9692 | |||
23d546c559 | |||
6d4ea6a951 | |||
f9b5dcd4a6 | |||
eab679cb2b | |||
ddf8b20091 | |||
f1457582fe | |||
7841f79f31 | |||
56e5acfb65 | |||
6b777878e3 | |||
428c7c5444 | |||
f8427eb801 | |||
2a53c056ca | |||
21d555ee6b | |||
d79fda166f | |||
c8025ebaac | |||
42d7ad02b0 | |||
21556d4c07 | |||
89a7166c1b | |||
5d6c28c997 | |||
717cadc64b | |||
3dac7ef3f3 | |||
056cb60d5d | |||
bb4e92ec50 | |||
9218fb6463 | |||
d9baea4c38 | |||
6df6537cf9 | |||
72d199f390 | |||
233bce578b | |||
63472d54d7 | |||
db57b5ae80 | |||
8896d89908 | |||
8e07bf3ffb | |||
6194d0ad44 | |||
138532d3d4 | |||
4716b704d4 | |||
109e576811 | |||
631c878722 | |||
4cbcdb8af5 | |||
d24628a386 | |||
7e714bdfa2 | |||
e3283fb29b | |||
be0285155f | |||
1c055a7282 | |||
8d3cdd39ca | |||
010ba4d5b6 | |||
d176a16caa | |||
fd4a27c1a3 | |||
ae73858e23 | |||
1427e5458b | |||
8853cf9f83 | |||
de7f22bcbc | |||
b8b2fa29d7 | |||
476a241936 | |||
dc97982fad | |||
e488f93b17 | |||
e6e9668bbb | |||
56976898bd | |||
221ff05c49 | |||
8f719d3e33 | |||
67c2abca2d | |||
36046f08f7 | |||
3c4455c23c | |||
e3db2e2b76 | |||
5567a26b33 | |||
5387c3dd97 | |||
d14eef979c | |||
c7069f4fd9 | |||
b40239f93b | |||
2958175add | |||
719ad8f4d4 | |||
4055eda757 | |||
442df56629 | |||
477ab67fe9 | |||
64c60741a0 | |||
9e354d7703 | |||
1932c1cd7c | |||
11670d0c0f | |||
6cab02cd99 | |||
fc1d781272 | |||
a58ecfd35a | |||
645516ee1b | |||
f570de5086 | |||
81ccfa1e6c | |||
b808aa4971 | |||
d1f1bc93b3 | |||
faf433f644 | |||
ba4660a03a | |||
03aa3693d0 | |||
ecae976993 | |||
307c8980e0 | |||
e53d0eda47 | |||
369b15b20b | |||
ff8bbcd88a | |||
c52d22dc30 | |||
4fa6c9dc3d | |||
a958d10dd9 | |||
ff86ce64b4 | |||
f31d8aa9d7 | |||
3cf7406123 | |||
5d8bf196a8 | |||
019bd26c51 | |||
0e1f924fc3 | |||
15c3893aab | |||
deeab7c238 | |||
e5ba7b9e69 | |||
ca5be7e38d | |||
fb530f2b34 | |||
29cbf63346 | |||
13c03cc0c2 | |||
281280d3ec | |||
410be51951 | |||
eefe8289b3 | |||
a53a5944f8 | |||
cd009466b6 | |||
f0c106de75 | |||
fcf1b679e6 | |||
03ba57cd46 | |||
bea08e5cfd | |||
01787e2662 | |||
ac76220349 | |||
796954c6e3 | |||
292c188182 | |||
1f7097ef89 | |||
b97e083017 | |||
8ffd182b98 | |||
1e77546251 | |||
8711960e74 | |||
8e2bcef824 | |||
d418cf7b07 | |||
864bcbb675 | |||
0b257b98f5 | |||
daab68d0b8 | |||
ab0511aa1d | |||
12494c3ac6 | |||
621533e050 | |||
dc334d230a | |||
b848595378 | |||
ae4b2ab1fd | |||
2ca8cc6ca3 | |||
3b57e2684e | |||
898c672193 | |||
18a7bc9278 | |||
bb29ee10c5 | |||
5441ae537a | |||
0a0ddafd67 | |||
a3b914d8b4 | |||
39f75d3742 | |||
3dd77a4f2c | |||
6782e82972 | |||
120fce0288 | |||
aa57531ed7 | |||
8f76bc0bcb | |||
189280e602 | |||
78ca26cf78 | |||
0c5c6233c7 | |||
4fe480ee55 | |||
be6560e08c | |||
0f58f6da36 | |||
dcaf0463a7 | |||
5c6643270b | |||
7b337bde49 | |||
7056aae301 | |||
1b6eb9cab0 | |||
80e23beda9 | |||
d70e120acc | |||
c877937fdf | |||
8379b07de0 | |||
c8c33245b8 | |||
0faf2fe83e | |||
19bc511f39 | |||
916323bb3b | |||
0e568e2af5 | |||
dde841383a | |||
81dae7d350 | |||
d3e3c31b0c | |||
90852fe951 | |||
a2251d245f | |||
112f9c4241 | |||
b300404bc7 | |||
19161b52f5 | |||
429170520e | |||
5571413a78 | |||
512ee16620 | |||
15dc0d60db | |||
d86cc9192e | |||
25b08b21fa | |||
ef9c2e8af1 | |||
9bee48c601 | |||
961942ff6a | |||
de1c2b0150 | |||
5a73358bca | |||
1812ea90b5 | |||
d98a416ed9 | |||
b947749382 | |||
c4d0b061c9 | |||
3bada5d443 | |||
06a35787aa | |||
88c931ec13 | |||
3d436c3b0e | |||
b4bb44d3e6 | |||
39157e6883 | |||
9b6b9e6113 | |||
87df34e064 | |||
55a48ff84a | |||
aed98f16bb | |||
2926865c1b | |||
20fb7fc188 | |||
461462eafc | |||
7aa6d1a8d7 | |||
d914fe2f48 | |||
e100edce24 | |||
a68915d6cf | |||
210d680b21 | |||
8dc4acdc34 | |||
eb54a18fcd | |||
cf436e11ae | |||
e22b7f74c7 | |||
f8fca7434c | |||
66d303c4ba | |||
186ed8beb2 | |||
fac546cc0b | |||
9d2d2d0d64 | |||
f58043b07f | |||
289c6fa10e | |||
00e24ab249 | |||
7b69e334d7 | |||
12507b6743 | |||
3750842833 | |||
1dcec3e1fb | |||
d8e1edd6d3 | |||
a1f1e90626 | |||
522d745883 | |||
8ffb81cdf3 | |||
ae5254c65e | |||
9d53888524 | |||
cd6dd78759 | |||
27fd49e61c | |||
a3a259556f | |||
803da75636 | |||
d1556eb6cd | |||
a7edbfe5e9 | |||
663b5beac1 | |||
7e164d2ec3 | |||
f9fb0bb477 | |||
702c7f2c30 | |||
8b348ade75 | |||
bf37f44795 | |||
698033b0cf | |||
10496363f5 | |||
14647d5778 | |||
560dde3396 | |||
7f9c2439c4 | |||
6de5d0bce8 | |||
c705a11aa7 | |||
45a196b407 | |||
07cb6adb69 | |||
5358f81ce0 | |||
5b7988be79 | |||
e6c794d68f | |||
de73fedd1b | |||
2719849a54 | |||
3011fecf0f | |||
6da0a9a201 | |||
572fe3eacb | |||
ff82f15246 | |||
b214e3f6df | |||
cb9130fdf9 | |||
925dc869a2 | |||
5f1aa619cd | |||
541c748ecb | |||
e853bddbc8 | |||
79d26b5d95 | |||
840f52a75b | |||
f955302c74 | |||
95e7d3dfc4 | |||
75f2749b19 | |||
01e5b319d1 | |||
e504163bc7 | |||
aba3f7d6bd | |||
8d74023d30 | |||
602625fc17 | |||
bbeb2d5009 | |||
51faa39636 | |||
f37bfbf9f9 | |||
ba9928831e | |||
2b6bd3d751 | |||
e96ca21c89 | |||
6ee10fe98b | |||
a567c19759 | |||
bb3a087d39 | |||
5a92fe736f | |||
88390402a4 | |||
538eb66672 | |||
0b6dfe0fd3 | |||
d5579ef2b5 | |||
836c3a5b3a | |||
f2da64adad | |||
e5704abfb3 | |||
3bf4eea1fe | |||
aa23222339 | |||
68c1670c70 | |||
914eaaaa51 | |||
5831ba2143 | |||
c167a24f09 | |||
a539d27c62 | |||
d7fc079376 | |||
3a05f7e294 | |||
03713f9bd8 | |||
2a145f4350 | |||
d049da696c | |||
5a46d0e80d | |||
926250a967 | |||
139b588795 | |||
909f18f9c7 | |||
f598495198 | |||
95d746504d | |||
9a2e1d43ea | |||
be844978c1 | |||
60a361f963 | |||
93f50451e6 | |||
0936812df0 | |||
50351f56f8 | |||
232ceed8b0 | |||
b6c37a73b1 | |||
5967666df6 | |||
bf035333cf | |||
f93d1173e2 | |||
08bf4faeee | |||
e2b2cf0175 | |||
d32a24004e | |||
1f04e4e6be | |||
778dcf97b1 | |||
957fbdb907 | |||
e169b851ee | |||
7fadb4c5ad | |||
a20db7f341 | |||
b5f4739ae5 | |||
4bc03fbf06 | |||
1d3ff143d2 | |||
6918b8a291 | |||
3cd37682d3 | |||
19a990b095 | |||
87a4f02f18 | |||
8a99fc0505 | |||
bac99deb6c | |||
e65850b1eb | |||
77338c6054 | |||
a6e52ed3df | |||
4a9eadf71a | |||
b8f6cf4f23 | |||
e8abc1137b | |||
8507688c50 | |||
5718096224 | |||
d76e61e6f4 | |||
232817c00d | |||
86af585df3 | |||
9e770ea484 | |||
9670f11554 | |||
dc369d52cb | |||
33c755fc54 | |||
c5adc0eb71 | |||
fcb1de8a86 | |||
6df83ad148 | |||
857a436677 | |||
c6091750b0 | |||
64e7324285 | |||
d5bd0ee781 | |||
3b91b38014 | |||
165d4e2732 | |||
098dfacce8 | |||
44d1419af9 | |||
d0d077642d | |||
dc04839fab | |||
4ce0cb4b35 | |||
5100c36c06 | |||
b184360eb7 | |||
02d79de17c | |||
cf27c66132 | |||
53d9ed5adb | |||
3fe5051098 | |||
f7c8a989b6 | |||
65dcfd3549 | |||
6976fc54ca | |||
0e077ff5c4 | |||
c2f171a729 | |||
fea38758e4 | |||
444733565b | |||
96d28f00cc | |||
70cc79a77f | |||
8d10186fdf | |||
6f7e0205f8 | |||
7ef11817c1 | |||
c387c84861 | |||
ae7ad9f667 | |||
c55f1185e6 | |||
1619666bef | |||
bf784f6fd7 | |||
13e330fa65 | |||
827b133534 | |||
4067d4b00f | |||
359d8c5c6a | |||
265b7364e8 | |||
dc2b8c9e4c | |||
37869fd049 | |||
d7ada4d493 | |||
f093f85dbf | |||
1cf17872ab | |||
c79751829b | |||
7a21c03896 | |||
54f07139db | |||
d78990fbd5 | |||
9ed7dbc838 | |||
9b12c7bc57 | |||
8973c75bbc | |||
f425df7b6d | |||
a44b600c5e | |||
7f0a42c2d5 | |||
60cd864226 | |||
71cf02915e | |||
327d2298fb | |||
2ca11ed692 | |||
0224815a60 | |||
df824c36d2 | |||
66e7777b1a | |||
7ff85a86bf | |||
7b3700c2c6 | |||
04679aefd6 | |||
5190639b77 | |||
0bf73abb39 | |||
7e0211924d | |||
a8a857a7ce | |||
1d18965a26 | |||
e020b86a3f | |||
1b80b90609 | |||
efc3512994 | |||
acb8ca982f | |||
adc42cbba4 | |||
7edcb7ef5f | |||
656017c6df | |||
35db6d4a8b | |||
2741187546 | |||
c3a7ab647c | |||
92da0ec2d2 | |||
c767a49f2d | |||
ea8196b532 | |||
58f138e854 | |||
b4b6939498 | |||
bc97c07670 | |||
cf27fe5a53 | |||
449066449b | |||
eb5e32a07f | |||
708cdbe23f | |||
333de52c33 | |||
6b9932fa14 | |||
6c45689e6a | |||
1e3307c84c | |||
d0eed9857d | |||
4221763f48 | |||
184c797b0e | |||
4853e15d8a | |||
6b4b903669 | |||
05da63f2a5 | |||
5b4b073fc8 | |||
4723a83dbb | |||
78350db62d | |||
e8b71f36b2 | |||
6db9061dd1 | |||
320826a4b9 | |||
ad0edb5f4c | |||
2856c10bc3 | |||
24aa18e9ed | |||
767eca97cb | |||
73d5415ea9 | |||
e5a26cfca8 | |||
e40cd1fc0c | |||
978b7d930e | |||
0f2e3ef957 | |||
275b590e80 | |||
5d9da82d8e | |||
1a122726b7 | |||
0bd02a9272 | |||
3cce7b8b35 | |||
e3ab1f5228 | |||
4c875d9c7c | |||
e79334a6f6 | |||
a09c6d51e6 | |||
312c7b7193 | |||
ee733fee28 | |||
4d7e9d3f8a | |||
873c0a183a | |||
ea53ae8f20 | |||
686bc3380d | |||
67da20bcea | |||
561644f75b | |||
1abc89858f | |||
91c63a8ee6 | |||
563882d30b | |||
9a5eeee794 | |||
0578a692db | |||
f74f06338a | |||
1281f348bf | |||
5e76d4bfc1 | |||
2a302ea346 | |||
be90172840 | |||
b85ee895f5 | |||
93de408e07 | |||
d3662ae734 | |||
132d7795ea | |||
bf5a624209 | |||
abbdbda03a | |||
8a8593437a | |||
e203cada54 | |||
00c11c7ee9 | |||
82126b85d2 | |||
4f428c8ed1 | |||
9868af4db8 | |||
0a5d7c5efa | |||
c2754b324d | |||
5c618233cb | |||
9e91259b9e | |||
014d08f38a | |||
7998ea142b | |||
a4051dac72 | |||
e3a8892d24 | |||
ea02d77e69 | |||
4f582a6712 | |||
4769b1d452 | |||
17b18d820f | |||
26f34e75c2 | |||
6f50ac50ec | |||
5261cfcdd3 | |||
675920697f | |||
24699bf2ba | |||
5ab92ed794 | |||
8e83f0faa1 | |||
30d5add2ea | |||
6e47babf45 | |||
9b95fa1f20 | |||
c67aa14a87 | |||
23f296ef34 | |||
c6ce676ad3 | |||
fafb02b0dc | |||
53cecc8c8a | |||
db0e9ee8f8 | |||
2fac794d96 | |||
ffcd716906 | |||
85f50724db | |||
808a995741 | |||
4deb853914 | |||
470ec3354e | |||
053c2da9f1 | |||
c0e28ce66e | |||
08dd94e267 | |||
7497865d1f | |||
1888e4fe2b | |||
6746a5cbd5 | |||
baecb7bb0c | |||
28bf4b42bb | |||
c73dc425ad | |||
2138b7dcb8 | |||
8b6c4a9383 | |||
344755cbd0 | |||
63a975267c | |||
3c7d93e88d | |||
75974037bc | |||
e8a346182b | |||
e96d34f741 | |||
7dad814f19 | |||
7e67ca1413 | |||
603263549b | |||
a82b971ce7 | |||
b58c8ef2f0 | |||
274533bfdf | |||
cd6ce401e1 | |||
0c0809101d | |||
4b342376a8 | |||
fd963b9ad0 | |||
06406c0695 | |||
2b567de5c1 | |||
ef46d03760 | |||
b174f299fa | |||
09837966b9 | |||
465dce1d02 | |||
067dbad546 | |||
522970fdb9 | |||
e67aa499a6 | |||
3b68d81507 | |||
051248f2fc | |||
9a239f99f4 | |||
86c431d66e | |||
b35fe0e8e3 | |||
54905f5ceb | |||
1c9b05d992 | |||
a89c71df38 | |||
3db1f2af12 | |||
5399ff2751 | |||
bcea6027e9 | |||
a9722df7e4 | |||
474be6f7be | |||
ada9a7264b | |||
e991b302d0 | |||
eef301c6ec | |||
3fdfd0adfd | |||
358f1ffc43 | |||
349c3409df | |||
0263a2950c | |||
0364a57cae | |||
e232dd7d7e | |||
fee936b569 | |||
420115c54d | |||
312e961098 | |||
223213857f | |||
c0da81557b | |||
81945c0737 | |||
9664e3d6a1 | |||
0a8bd38e76 | |||
013054fb82 | |||
d898f716d1 | |||
1d3f144d21 | |||
de29d87487 | |||
ebef085a9c | |||
2c1f159d72 | |||
1ef59e05a5 | |||
5e09992637 | |||
30448233b1 | |||
a1601a17aa | |||
7522f7d0f7 | |||
d04b9c4c09 | |||
1a24ff9a49 | |||
13d72de82d | |||
3728fdab3f | |||
2317e3d50c | |||
5f15976c02 | |||
7f592639c5 | |||
a98402af12 | |||
316ffa91d1 | |||
c24953b57e | |||
7a1b1b7e5e | |||
70f71f64c4 | |||
5bccd07d7d | |||
d818baa6d1 | |||
249b8abf03 | |||
c134277514 | |||
f5d366cf7f | |||
ad25a2ed08 | |||
1e7a2ffe97 | |||
dd52075ff1 | |||
0253e42bd5 | |||
d99774f8d9 | |||
d563a2ec89 | |||
b4b4523193 | |||
fbcb69f447 | |||
8ae5a9c1f7 | |||
3ef5bfb6eb | |||
4016ded584 | |||
5b0b4adb1c | |||
f1ec3b0c75 | |||
b5d55a2066 | |||
0d2c9fe377 | |||
2c7cc9a796 | |||
2e1d623755 | |||
52fee8f842 | |||
6ba17e8e30 | |||
ac3432920a | |||
63c88be533 | |||
3cb577e6ba | |||
1e0d64c548 | |||
bc1b9ff59c | |||
7d73bed3be | |||
126fbdfd60 | |||
15094436fd | |||
010c653995 | |||
119f82fd4e | |||
3bbf4de5d2 | |||
0807f3b87b | |||
4e9b3b40aa | |||
cc444811db | |||
50c8525012 | |||
aedad497e8 | |||
b1b231e645 | |||
dc46fd225a | |||
6226de7cff | |||
37327ec674 | |||
c071c81403 | |||
85d75a013a | |||
3816b36131 | |||
dc7965267b | |||
ce9a6bced7 | |||
85325dc710 | |||
ac4050df70 | |||
a16a53167b | |||
afab3cf847 | |||
8fdaeb7bac | |||
7e0f9f6e0d | |||
5b1bf6cd88 | |||
b1584c352b | |||
b06b83503c | |||
b03d89c190 | |||
f53548d10f | |||
5ec2f54d7f | |||
db588ff961 | |||
2b7006a14c | |||
8f5f07882f | |||
0eee8e7464 | |||
3725a5b644 | |||
c84c0ac64d | |||
098e07988c | |||
66bb702aca | |||
03ff2fedf0 | |||
c707f47b11 | |||
585efa3ff5 | |||
07d0b98a23 | |||
c7c0f01010 | |||
cf6b17250a | |||
90503a490c | |||
ebdd53b99b | |||
51a5d2e812 | |||
2ad509d56a | |||
1a98bfba36 | |||
d05bb6c60e | |||
ed81b6a6aa | |||
264914588f | |||
05df43b426 | |||
0334a4e176 | |||
38dca425da | |||
82d4a79dd4 | |||
6725be8145 | |||
f5b693f01b | |||
f09f23e570 | |||
4f4d05b8cd | |||
0c5b5ff49c | |||
a815fad3f1 | |||
d8b1c7c10a | |||
02e1aea80c | |||
1892f7e0f4 | |||
b7b50349a7 | |||
02d227ee02 | |||
47f8938b89 | |||
4945a640a7 | |||
0136977359 | |||
0acd3e20b0 | |||
30bdfeee37 | |||
7ea665d884 | |||
073edcfb12 | |||
a645366a25 | |||
12aa0b7abd | |||
3f98a50410 | |||
24c8c076d5 | |||
37e6931d33 | |||
86493568e9 | |||
bb51436ae3 | |||
854a55ac1a | |||
cfb4b080d3 | |||
00aa2e4e17 | |||
69c67d99f6 | |||
65596ec8c1 | |||
49643cb00e | |||
35b0faee57 | |||
88ef4d69b2 | |||
575b6ca222 | |||
b5a0e844d2 | |||
2642e11ce2 | |||
b4fe655efe | |||
ffb761909a | |||
b443e1ac6e | |||
a4792f54a7 | |||
686ae029e0 | |||
f3fd2e7d0f | |||
7efd9ba0a5 | |||
1c2a6bb8a1 | |||
7bcf1cbdd5 | |||
2aaa2544bd | |||
d85f03ba20 | |||
cfb51a6be4 | |||
c9d778c94b | |||
fd62f882de | |||
adc050f190 | |||
2d551b9fc5 | |||
884acdde32 | |||
8f896de794 | |||
5e4e26d2fd | |||
ae688e6615 | |||
c4c812bdf6 | |||
e620fc0283 | |||
c333902468 | |||
4c83ecd06a | |||
b28a547dc4 | |||
6bc17e05bd | |||
0903350d30 | |||
6c0f19b457 | |||
e119dc823f | |||
43295c9c57 | |||
ded8b54042 | |||
50a3178d51 | |||
393c226032 | |||
f2630df387 | |||
abcd2c1750 | |||
cc95f3b5b5 | |||
a08ee93b43 | |||
4b90f873d5 | |||
419ab8e0b1 | |||
c95ef27998 | |||
63dfd93834 | |||
57610881de | |||
7469faf296 | |||
55a884a559 | |||
ee2b3c3d10 | |||
e5819a260b | |||
a3ecf48702 | |||
1c0b904cd2 | |||
072d8a1728 | |||
964e541c32 | |||
78fec4ed22 | |||
ef111d36c9 | |||
4f64193e85 | |||
89bb6d1268 | |||
9f4226bf0f | |||
a87c2a3374 | |||
d7294ba5a0 | |||
82d286dc6f | |||
1fa18ab997 | |||
afc90f32c9 | |||
e9cfb7c21e | |||
1af8ea3769 | |||
9f7af190f1 | |||
9c703fe94d | |||
a7a11a4f13 | |||
c32c3bb62b | |||
e29d1480a6 | |||
8f299d7791 | |||
65fb2e992e | |||
41f5d677d5 | |||
a2b78b8cd9 | |||
c93f217033 | |||
82c47b6e9a | |||
94fb738c67 | |||
89071e40fc | |||
95a90c410e | |||
59fc371cd5 | |||
9b404e330d | |||
1667f9b2ef | |||
caadfc8641 | |||
bffc2e70c1 | |||
8b686f0b12 | |||
def8d1e0cb | |||
ca28c34be0 | |||
196bc3ea00 | |||
b15267be4d | |||
5c074f6f5f | |||
04cba61888 | |||
a41e2e1ceb | |||
d1d03c98ba | |||
679942159e | |||
3e48a54ab5 | |||
f6e389ff62 | |||
63c309bd12 | |||
561ec57cc8 | |||
3cefd7bd1e | |||
c63feb488c | |||
12c418d84d | |||
4b982f815c | |||
d4d3346b6d | |||
6010a103e0 | |||
5dc1da2af0 | |||
f2ccc4d963 | |||
a92d48efdd | |||
b633206b45 | |||
b6f3d2af5e | |||
5fd77d9fcc | |||
5ca4494eed | |||
de7e419ef4 | |||
20a6b3fc33 | |||
540414d8f5 | |||
abcdb8ced0 | |||
5076d73695 | |||
d88735f84e | |||
2244f0ab76 | |||
40c85d6104 | |||
42892e24f4 | |||
e6357d2ac8 | |||
1eecd85ceb | |||
c27557826b | |||
88150b6535 | |||
d63176da19 | |||
887da5aa9a | |||
6e7f1151bc | |||
b2aebcc5d3 | |||
ae9ad0fa65 | |||
fb6d852827 | |||
ba17612461 | |||
a15c7a0213 | |||
7e321d4016 | |||
a05cd5678b | |||
2ccf007b9a | |||
895b8c2c80 | |||
0f175174f6 | |||
493466683c | |||
761c342c51 | |||
5341da28d9 | |||
7768f41849 | |||
fa8993191e | |||
239ce28575 | |||
c52a49f747 | |||
e4b9895ba7 | |||
92a2bb4d32 | |||
bfec722312 | |||
5a3f7b5b70 | |||
2aa097be46 | |||
8a646d85c6 | |||
890b3eaa00 | |||
cda28ebf15 | |||
2245027ca3 | |||
3dc250f801 | |||
66e786a1b0 | |||
1e26926350 | |||
8bd7ea5bbc | |||
6eb36abe2e | |||
6fced3fab2 | |||
774e456e54 | |||
519859e1c5 | |||
26f0c488e5 | |||
1b0b53fbd0 | |||
35f4ea29f9 | |||
fff39d9879 | |||
444e761d41 | |||
68a3def35a | |||
d9426d301d | |||
8bcf7109a3 | |||
3effdf0f4d | |||
3c122bcf53 | |||
037ff52f4f | |||
b11f8acba1 | |||
ef9a633aa4 | |||
c7e2f979dd | |||
e97bb9c933 | |||
fa506b5bf8 | |||
e3193a92d0 | |||
d76dabdca6 | |||
d219f50912 | |||
e08710a19c | |||
4e167b35be | |||
16873384a8 | |||
f87339f9fa | |||
5f5e5e3211 | |||
f724db8226 | |||
c7e90cd7df | |||
8c5b00b1a3 | |||
a3b79fbcd8 | |||
9db77e6351 | |||
5bc1eaec9f | |||
81c9ce7284 | |||
caa6978d80 | |||
af22d6a4e3 | |||
0eabb3c37c | |||
2b84791391 | |||
6f896cb096 | |||
9a488c60f2 | |||
9cb50446f4 | |||
8c00a2359e | |||
d1ff34d16d | |||
8e8615dab8 | |||
a63ed4d3b4 | |||
968c820702 | |||
3061b4dfd2 | |||
ed4de612dd | |||
d4bdd5fd9c | |||
8b71556425 | |||
ae6e1bfd85 | |||
6d1f3b73ef | |||
0dcaf80c7f | |||
fc9cd5bdf0 | |||
a434c45196 | |||
87b316ec23 | |||
9c99ffae57 | |||
30a3a84ec9 | |||
d0f585df9d | |||
bac2db5cda | |||
c35bf2f483 | |||
2e04c5e39c | |||
9dcf16e819 | |||
361d494cde | |||
4d7015294e | |||
5f16fb4668 | |||
4bf2228675 | |||
2ba823f192 | |||
27fa2d5b69 | |||
47ef7661d8 | |||
3f6ff25322 | |||
f56c23009a | |||
e80593fb7b | |||
57324345ac | |||
73e280157d | |||
cfaa5766ed | |||
8b08db308b | |||
3e2ff55954 | |||
70d1d0d230 | |||
94e0048a3b | |||
a34d1641b3 | |||
40c645e433 | |||
b2e5415a35 | |||
365ee4cf0b | |||
2b4603a234 | |||
ec23eae21d | |||
7a9229628a | |||
9db5c0f375 | |||
27bde55f54 | |||
2bb24282d2 | |||
998472e463 | |||
63ff46a768 | |||
660f43e3b7 | |||
0ba96aa4b8 | |||
d85247d2ad | |||
9ca85ed365 | |||
93113fd871 | |||
b5d360594a | |||
d5ae79c38c | |||
7cf07b27e3 | |||
bb0f986b0c | |||
2c2a85327f | |||
7bf03e497b | |||
7a4dee3d38 | |||
7b27d6f0bb | |||
83dc95a0a7 | |||
d60889f952 | |||
8c9952973d | |||
00673bdb7f | |||
d039890a9b | |||
41e88c07fe | |||
67c5027b16 | |||
a341d4f800 | |||
e3833914b3 | |||
49cdec6961 | |||
3ad1834439 | |||
4b492eae85 | |||
f0ff47af8d | |||
991826b686 | |||
22d59a1ed7 | |||
475ea68696 | |||
864e84706a | |||
9c93e76eeb | |||
7fa1b65af0 | |||
c00c95efcf | |||
94be2b46d5 | |||
4b4d0d2d19 | |||
0d06cf63b7 | |||
7b24c02d51 | |||
becf488714 | |||
e89e8226e4 | |||
a533a96598 | |||
27321c0919 | |||
058472d325 | |||
b5c9a03052 | |||
07dad3affa | |||
8afc103ae7 | |||
591d7b4b80 | |||
2162afc78e | |||
25e226d219 | |||
8472bfe90d | |||
93645b2fbe | |||
d53c987f2e | |||
682693a9f0 | |||
e836faf792 | |||
6e27233be8 | |||
9209984a2f | |||
1477630c78 | |||
ab670080c7 | |||
8198f98376 | |||
65b4697229 | |||
e75a1a8b70 | |||
580494fea7 |
@ -1,32 +1,41 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
machine:
|
||||
docker_layer_caching: true
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
test:
|
||||
machine: true
|
||||
fast_tests:
|
||||
machine:
|
||||
docker_layer_caching: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
lsb_release -a
|
||||
wget -q https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb
|
||||
sudo dpkg -i packages-microsoft-prod.deb
|
||||
sudo apt-get install apt-transport-https
|
||||
sudo apt-get update
|
||||
sudo apt-get install dotnet-sdk-2.1
|
||||
dotnet --info
|
||||
dotnet build /p:TreatWarningsAsErrors=true
|
||||
cd BTCPayServer.Tests
|
||||
dotnet test --filter Fast=Fast
|
||||
docker-compose up -d dev
|
||||
dotnet test --filter Integration=Integration
|
||||
cd .circleci && ./run-tests.sh "Fast=Fast"
|
||||
selenium_tests:
|
||||
machine:
|
||||
docker_layer_caching: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
cd .circleci && ./run-tests.sh "Selenium=Selenium"
|
||||
integration_tests:
|
||||
machine:
|
||||
docker_layer_caching: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
cd .circleci && ./run-tests.sh "Integration=Integration"
|
||||
external_tests:
|
||||
machine:
|
||||
docker_layer_caching: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
cd .circleci && ./run-tests.sh "ExternalIntegration=ExternalIntegration"
|
||||
|
||||
|
||||
# publish jobs require $DOCKERHUB_REPO, $DOCKERHUB_USER, $DOCKERHUB_PASS defined
|
||||
publish_docker_linuxamd64:
|
||||
amd64:
|
||||
machine:
|
||||
docker_layer_caching: true
|
||||
steps:
|
||||
@ -35,11 +44,11 @@ jobs:
|
||||
command: |
|
||||
LATEST_TAG=${CIRCLE_TAG:1} #trim v from tag
|
||||
#
|
||||
sudo docker build --pull -t $DOCKERHUB_REPO:$LATEST_TAG-amd64 -f Dockerfile.linuxamd64 .
|
||||
sudo docker build --pull -t $DOCKERHUB_REPO:$LATEST_TAG-amd64 -f amd64.Dockerfile .
|
||||
sudo docker login --username=$DOCKERHUB_USER --password=$DOCKERHUB_PASS
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-amd64
|
||||
|
||||
publish_docker_linuxarm:
|
||||
arm32v7:
|
||||
machine:
|
||||
docker_layer_caching: true
|
||||
steps:
|
||||
@ -49,11 +58,11 @@ jobs:
|
||||
sudo docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
LATEST_TAG=${CIRCLE_TAG:1} #trim v from tag
|
||||
#
|
||||
sudo docker build --pull -t $DOCKERHUB_REPO:$LATEST_TAG-arm32v7 -f Dockerfile.linuxarm32v7 .
|
||||
sudo docker build --pull -t $DOCKERHUB_REPO:$LATEST_TAG-arm32v7 -f arm32v7.Dockerfile .
|
||||
sudo docker login --username=$DOCKERHUB_USER --password=$DOCKERHUB_PASS
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-arm32v7
|
||||
|
||||
publish_docker_multiarch:
|
||||
multiarch:
|
||||
machine:
|
||||
enabled: true
|
||||
image: circleci/classic:201808-01
|
||||
@ -76,11 +85,17 @@ workflows:
|
||||
version: 2
|
||||
build_and_test:
|
||||
jobs:
|
||||
- test
|
||||
- fast_tests
|
||||
- selenium_tests
|
||||
- integration_tests
|
||||
- external_tests:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
|
||||
publish:
|
||||
jobs:
|
||||
- publish_docker_linuxamd64:
|
||||
- amd64:
|
||||
filters:
|
||||
# ignore any commit on any branch by default
|
||||
branches:
|
||||
@ -88,16 +103,16 @@ workflows:
|
||||
# only act on version tags
|
||||
tags:
|
||||
only: /v[1-9]+(\.[0-9]+)*/
|
||||
- publish_docker_linuxarm:
|
||||
- arm32v7:
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: /v[1-9]+(\.[0-9]+)*/
|
||||
- publish_docker_multiarch:
|
||||
- multiarch:
|
||||
requires:
|
||||
- publish_docker_linuxamd64
|
||||
- publish_docker_linuxarm
|
||||
- amd64
|
||||
- arm32v7
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
|
9
.circleci/run-tests.sh
Executable file
9
.circleci/run-tests.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
cd ../BTCPayServer.Tests
|
||||
docker-compose -v
|
||||
docker-compose down --v
|
||||
docker-compose pull
|
||||
docker-compose build
|
||||
docker-compose run -e "TEST_FILTERS=$1" tests
|
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
name: Report a problem
|
||||
about: File a technical problem or report a bug
|
||||
---
|
||||
|
||||
**Describe the problem/bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Your environment**
|
||||
* Version of BTCPay Server:
|
||||
* Deployment method:
|
||||
* Other relevant environment details:
|
||||
|
||||
**Logs (if applicable)**
|
||||
Basic logs can be found in Server Settings > Logs.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Actual behavior**
|
||||
Tell us what happens instead
|
||||
|
||||
**Screenshots/Links**
|
||||
If applicable, add screenshots or links to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Ideas and feature requests
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Provide examples**
|
||||
If applicable provide examples, wireframes, sketches or images to better explain your idea.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
@ -3,13 +3,18 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public enum DerivationType
|
||||
{
|
||||
Legacy,
|
||||
SegwitP2SH,
|
||||
Segwit
|
||||
}
|
||||
public class BTCPayDefaultSettings
|
||||
{
|
||||
static BTCPayDefaultSettings()
|
||||
@ -38,13 +43,69 @@ namespace BTCPayServer
|
||||
public string DefaultConfigurationFile { get; set; }
|
||||
public int DefaultPort { get; set; }
|
||||
}
|
||||
public class BTCPayNetwork
|
||||
|
||||
public class BTCPayNetwork:BTCPayNetworkBase
|
||||
{
|
||||
public Network NBitcoinNetwork { get; set; }
|
||||
public NBXplorer.NBXplorerNetwork NBXplorerNetwork { get; set; }
|
||||
public bool SupportRBF { get; internal set; }
|
||||
public string LightningImagePath { get; set; }
|
||||
public BTCPayDefaultSettings DefaultSettings { get; set; }
|
||||
public KeyPath CoinType { get; internal set; }
|
||||
public Dictionary<uint, DerivationType> ElectrumMapping = new Dictionary<uint, DerivationType>();
|
||||
|
||||
|
||||
public KeyPath GetRootKeyPath(DerivationType type)
|
||||
{
|
||||
KeyPath baseKey;
|
||||
if (!NBitcoinNetwork.Consensus.SupportSegwit)
|
||||
{
|
||||
baseKey = new KeyPath("44'");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DerivationType.Legacy:
|
||||
baseKey = new KeyPath("44'");
|
||||
break;
|
||||
case DerivationType.SegwitP2SH:
|
||||
baseKey = new KeyPath("49'");
|
||||
break;
|
||||
case DerivationType.Segwit:
|
||||
baseKey = new KeyPath("84'");
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||
}
|
||||
}
|
||||
return baseKey
|
||||
.Derive(CoinType);
|
||||
}
|
||||
|
||||
public KeyPath GetRootKeyPath()
|
||||
{
|
||||
return new KeyPath(NBitcoinNetwork.Consensus.SupportSegwit ? "49'" : "44'")
|
||||
.Derive(CoinType);
|
||||
}
|
||||
|
||||
public override T ToObject<T>(string json)
|
||||
{
|
||||
return NBXplorerNetwork.Serializer.ToObject<T>(json);
|
||||
}
|
||||
|
||||
public override string ToString<T>(T obj)
|
||||
{
|
||||
return NBXplorerNetwork.Serializer.ToString(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class BTCPayNetworkBase
|
||||
{
|
||||
|
||||
public string CryptoCode { get; internal set; }
|
||||
public string BlockExplorerLink { get; internal set; }
|
||||
public string UriScheme { get; internal set; }
|
||||
public Money MinFee { get; internal set; }
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
[Obsolete("Should not be needed")]
|
||||
@ -57,23 +118,22 @@ namespace BTCPayServer
|
||||
}
|
||||
|
||||
public string CryptoImagePath { get; set; }
|
||||
public string LightningImagePath { get; set; }
|
||||
public NBXplorer.NBXplorerNetwork NBXplorerNetwork { get; set; }
|
||||
|
||||
public BTCPayDefaultSettings DefaultSettings { get; set; }
|
||||
public KeyPath CoinType { get; internal set; }
|
||||
public int MaxTrackedConfirmation { get; internal set; } = 6;
|
||||
public string[] DefaultRateRules { get; internal set; } = Array.Empty<string>();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return CryptoCode;
|
||||
}
|
||||
|
||||
internal KeyPath GetRootKeyPath()
|
||||
public virtual T ToObject<T>(string json)
|
||||
{
|
||||
return new KeyPath(NBitcoinNetwork.Consensus.SupportSegwit ? "49'" : "44'")
|
||||
.Derive(CoinType);
|
||||
return JsonConvert.DeserializeObject<T>(json);
|
||||
}
|
||||
|
||||
public virtual string ToString<T>(T obj)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj);
|
||||
}
|
||||
}
|
||||
}
|
45
BTCPayServer.Common/BTCPayNetworkProvider.Bitcoin.cs
Normal file
45
BTCPayServer.Common/BTCPayNetworkProvider.Bitcoin.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitBitcoin()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTC");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Bitcoin",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://blockstream.info/tx/{0}" : "https://blockstream.info/testnet/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "bitcoin",
|
||||
CryptoImagePath = "imlegacy/bitcoin.svg",
|
||||
LightningImagePath = "imlegacy/bitcoin-lightning.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("0'") : new KeyPath("1'"),
|
||||
SupportRBF = true,
|
||||
//https://github.com/spesmilo/electrum/blob/11733d6bc271646a00b69ff07657119598874da4/electrum/constants.py
|
||||
ElectrumMapping = NetworkType == NetworkType.Mainnet
|
||||
? new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x0488b21eU, DerivationType.Legacy }, // xpub
|
||||
{0x049d7cb2U, DerivationType.SegwitP2SH }, // ypub
|
||||
{0x4b24746U, DerivationType.Segwit }, //zpub
|
||||
}
|
||||
: new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x043587cfU, DerivationType.Legacy},
|
||||
{0x044a5262U, DerivationType.SegwitP2SH},
|
||||
{0x045f1cf6U, DerivationType.Segwit}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -2,30 +2,32 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBitpayClient;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitBitcoin()
|
||||
public void InitBitcoinplus()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTC");
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("XBC");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Bitcoin",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://www.smartbit.com.au/tx/{0}" : "https://testnet.smartbit.com.au/tx/{0}",
|
||||
DisplayName = "Bitcoinplus",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://chainz.cryptoid.info/xbc/tx.dws?{0}" : "https://chainz.cryptoid.info/xbc/tx.dws?{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "bitcoin",
|
||||
CryptoImagePath = "imlegacy/bitcoin.svg",
|
||||
LightningImagePath = "imlegacy/bitcoin-lightning.svg",
|
||||
UriScheme = "bitcoinplus",
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"XBC_X = XBC_BTC * BTC_X",
|
||||
"XBC_BTC = cryptopia(XBC_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/bitcoinplus.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("0'") : new KeyPath("1'")
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("65'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
@ -24,7 +23,7 @@ namespace BTCPayServer
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"BTX_X = BTX_BTC * BTC_X",
|
||||
"BTX_BTC = cryptopia(BTX_BTC)"
|
||||
"BTX_BTC = hitbtc(BTX_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/bitcore.svg",
|
||||
LightningImagePath = "imlegacy/bitcore-lightning.svg",
|
@ -27,8 +27,7 @@ namespace BTCPayServer
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
//https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("5'")
|
||||
: new KeyPath("1'"),
|
||||
MinFee = Money.Satoshis(1m)
|
||||
: new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
@ -28,8 +27,7 @@ namespace BTCPayServer
|
||||
},
|
||||
CryptoImagePath = "imlegacy/dogecoin.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("3'") : new KeyPath("1'"),
|
||||
MinFee = Money.Coins(1m)
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("3'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
@ -10,23 +10,24 @@ namespace BTCPayServer
|
||||
{
|
||||
public void InitGroestlcoin()
|
||||
{
|
||||
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("GRS");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Groestlcoin",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://chainz.cryptoid.info/grs/tx.dws?{0}.htm" : "https://chainz.cryptoid.info/grs-test/tx.dws?{0}.htm",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet
|
||||
? "https://chainz.cryptoid.info/grs/tx.dws?{0}.htm"
|
||||
: "https://chainz.cryptoid.info/grs-test/tx.dws?{0}.htm",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "groestlcoin",
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"GRS_X = GRS_BTC * BTC_X",
|
||||
"GRS_BTC = bittrex(GRS_BTC)"
|
||||
"GRS_X = GRS_BTC * BTC_X",
|
||||
"GRS_BTC = bittrex(GRS_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/groestlcoin.png",
|
||||
LightningImagePath = "imlegacy/groestlcoin-lightning.png",
|
||||
LightningImagePath = "imlegacy/groestlcoin-lightning.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("17'") : new KeyPath("1'")
|
||||
});
|
@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
@ -17,14 +16,30 @@ namespace BTCPayServer
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Litecoin",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://live.blockcypher.com/ltc/tx/{0}/" : "http://explorer.litecointools.com/tx/{0}",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet
|
||||
? "https://live.blockcypher.com/ltc/tx/{0}/"
|
||||
: "http://explorer.litecointools.com/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "litecoin",
|
||||
CryptoImagePath = "imlegacy/litecoin.svg",
|
||||
LightningImagePath = "imlegacy/litecoin-lightning.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("2'") : new KeyPath("1'")
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("2'") : new KeyPath("1'"),
|
||||
//https://github.com/pooler/electrum-ltc/blob/0d6989a9d2fb2edbea421c116e49d1015c7c5a91/electrum_ltc/constants.py
|
||||
ElectrumMapping = NetworkType == NetworkType.Mainnet
|
||||
? new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x0488b21eU, DerivationType.Legacy },
|
||||
{0x049d7cb2U, DerivationType.SegwitP2SH },
|
||||
{0x04b24746U, DerivationType.Segwit },
|
||||
}
|
||||
: new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x043587cfU, DerivationType.Legacy },
|
||||
{0x044a5262U, DerivationType.SegwitP2SH },
|
||||
{0x045f1cf6U, DerivationType.Segwit }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
@ -3,17 +3,14 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using NBitcoin;
|
||||
using NBitpayClient;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
Dictionary<string, BTCPayNetwork> _Networks = new Dictionary<string, BTCPayNetwork>();
|
||||
Dictionary<string, BTCPayNetworkBase> _Networks = new Dictionary<string, BTCPayNetworkBase>();
|
||||
|
||||
|
||||
private readonly NBXplorerNetworkProvider _NBXplorerNetworkProvider;
|
||||
@ -25,13 +22,14 @@ namespace BTCPayServer
|
||||
}
|
||||
}
|
||||
|
||||
BTCPayNetworkProvider(BTCPayNetworkProvider filtered, string[] cryptoCodes)
|
||||
BTCPayNetworkProvider(BTCPayNetworkProvider unfiltered, string[] cryptoCodes)
|
||||
{
|
||||
NetworkType = filtered.NetworkType;
|
||||
_NBXplorerNetworkProvider = new NBXplorerNetworkProvider(filtered.NetworkType);
|
||||
_Networks = new Dictionary<string, BTCPayNetwork>();
|
||||
UnfilteredNetworks = unfiltered.UnfilteredNetworks ?? unfiltered;
|
||||
NetworkType = unfiltered.NetworkType;
|
||||
_NBXplorerNetworkProvider = new NBXplorerNetworkProvider(unfiltered.NetworkType);
|
||||
_Networks = new Dictionary<string, BTCPayNetworkBase>();
|
||||
cryptoCodes = cryptoCodes.Select(c => c.ToUpperInvariant()).ToArray();
|
||||
foreach (var network in filtered._Networks)
|
||||
foreach (var network in unfiltered._Networks)
|
||||
{
|
||||
if(cryptoCodes.Contains(network.Key))
|
||||
{
|
||||
@ -40,9 +38,12 @@ namespace BTCPayServer
|
||||
}
|
||||
}
|
||||
|
||||
public BTCPayNetworkProvider UnfilteredNetworks { get; }
|
||||
|
||||
public NetworkType NetworkType { get; private set; }
|
||||
public BTCPayNetworkProvider(NetworkType networkType)
|
||||
{
|
||||
UnfilteredNetworks = this;
|
||||
_NBXplorerNetworkProvider = new NBXplorerNetworkProvider(networkType);
|
||||
NetworkType = networkType;
|
||||
InitBitcoin();
|
||||
@ -52,10 +53,28 @@ namespace BTCPayServer
|
||||
InitBitcoinGold();
|
||||
InitMonacoin();
|
||||
InitDash();
|
||||
InitPolis();
|
||||
InitFeathercoin();
|
||||
InitGroestlcoin();
|
||||
InitViacoin();
|
||||
// Assume that electrum mappings are same as BTC if not specified
|
||||
foreach (var network in _Networks.Values.OfType<BTCPayNetwork>())
|
||||
{
|
||||
if(network.ElectrumMapping.Count == 0)
|
||||
{
|
||||
network.ElectrumMapping = GetNetwork<BTCPayNetwork>("BTC").ElectrumMapping;
|
||||
if (!network.NBitcoinNetwork.Consensus.SupportSegwit)
|
||||
{
|
||||
network.ElectrumMapping =
|
||||
network.ElectrumMapping
|
||||
.Where(kv => kv.Value == DerivationType.Legacy)
|
||||
.ToDictionary(k => k.Key, k => k.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disabled because of https://twitter.com/Cryptopia_NZ/status/1085084168852291586
|
||||
//InitPolis();
|
||||
//InitBitcoinplus();
|
||||
//InitUfo();
|
||||
}
|
||||
|
||||
@ -70,20 +89,14 @@ namespace BTCPayServer
|
||||
}
|
||||
|
||||
[Obsolete("To use only for legacy stuff")]
|
||||
public BTCPayNetwork BTC
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetNetwork("BTC");
|
||||
}
|
||||
}
|
||||
public BTCPayNetwork BTC => GetNetwork<BTCPayNetwork>("BTC");
|
||||
|
||||
public void Add(BTCPayNetwork network)
|
||||
public void Add(BTCPayNetworkBase network)
|
||||
{
|
||||
_Networks.Add(network.CryptoCode.ToUpperInvariant(), network);
|
||||
}
|
||||
|
||||
public IEnumerable<BTCPayNetwork> GetAll()
|
||||
public IEnumerable<BTCPayNetworkBase> GetAll()
|
||||
{
|
||||
return _Networks.Values.ToArray();
|
||||
}
|
||||
@ -92,15 +105,20 @@ namespace BTCPayServer
|
||||
{
|
||||
return _Networks.ContainsKey(cryptoCode.ToUpperInvariant());
|
||||
}
|
||||
|
||||
public BTCPayNetwork GetNetwork(string cryptoCode)
|
||||
public BTCPayNetworkBase GetNetwork(string cryptoCode)
|
||||
{
|
||||
if(!_Networks.TryGetValue(cryptoCode.ToUpperInvariant(), out BTCPayNetwork network))
|
||||
return GetNetwork<BTCPayNetworkBase>(cryptoCode);
|
||||
}
|
||||
public T GetNetwork<T>(string cryptoCode) where T: BTCPayNetworkBase
|
||||
{
|
||||
if (cryptoCode == null)
|
||||
throw new ArgumentNullException(nameof(cryptoCode));
|
||||
if(!_Networks.TryGetValue(cryptoCode.ToUpperInvariant(), out BTCPayNetworkBase network))
|
||||
{
|
||||
if (cryptoCode == "XBT")
|
||||
return GetNetwork("BTC");
|
||||
return GetNetwork<T>("BTC");
|
||||
}
|
||||
return network;
|
||||
return network as T;
|
||||
}
|
||||
}
|
||||
}
|
10
BTCPayServer.Common/BTCPayServer.Common.csproj
Normal file
10
BTCPayServer.Common/BTCPayServer.Common.csproj
Normal file
@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.9" />
|
||||
<PackageReference Include="NBitcoin" Version="4.2.4" />
|
||||
<PackageReference Include="NBXplorer.Client" Version="2.0.0.19" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
class CustomThreadPool : IDisposable
|
||||
public class CustomThreadPool : IDisposable
|
||||
{
|
||||
CancellationTokenSource _Cancel = new CancellationTokenSource();
|
||||
TaskCompletionSource<bool> _Exited;
|
17
BTCPayServer.Common/Extensions.cs
Normal file
17
BTCPayServer.Common/Extensions.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public static class UtilitiesExtensions
|
||||
{
|
||||
public static void AddRange<T>(this HashSet<T> hashSet, IEnumerable<T> items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
hashSet.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ using System.Text;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
class ZipUtils
|
||||
public class ZipUtils
|
||||
{
|
||||
public static byte[] Zip(string unzipped)
|
||||
{
|
11
BTCPayServer.Data/BTCPayServer.Data.csproj
Normal file
11
BTCPayServer.Data/BTCPayServer.Data.csproj
Normal file
@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.1.2" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.1.2" />
|
||||
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
36
BTCPayServer.Data/Data/AddressInvoiceData.cs
Normal file
36
BTCPayServer.Data/Data/AddressInvoiceData.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class AddressInvoiceData
|
||||
{
|
||||
/// <summary>
|
||||
/// Some crypto currencies share same address prefix
|
||||
/// For not having exceptions thrown by two address on different network, we suffix by "#CRYPTOCODE"
|
||||
/// </summary>
|
||||
[Obsolete("Use GetHash instead")]
|
||||
public string Address
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public InvoiceData InvoiceData
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string InvoiceDataId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public DateTimeOffset? CreatedTime
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ namespace BTCPayServer.Data
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public bool TagAllInvoices { get; set; }
|
||||
public string Settings { get; set; }
|
||||
|
||||
public T GetSettings<T>() where T : class, new()
|
@ -1,12 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using BTCPayServer.Models;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using OpenIddict.EntityFrameworkCore.Models;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
@ -54,6 +51,14 @@ namespace BTCPayServer.Data
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public DbSet<PaymentRequestData> PaymentRequests
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public DbSet<WalletData> Wallets { get; set; }
|
||||
public DbSet<WalletTransactionData> WalletTransactions { get; set; }
|
||||
|
||||
public DbSet<StoreData> Stores
|
||||
{
|
||||
@ -87,10 +92,18 @@ namespace BTCPayServer.Data
|
||||
}
|
||||
|
||||
public DbSet<APIKeyData> ApiKeys
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public DbSet<StoredFile> Files
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
|
||||
public DbSet<U2FDevice> U2FDevices { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
var isConfigured = optionsBuilder.Options.Extensions.OfType<RelationalOptionsExtension>().Any();
|
||||
@ -204,6 +217,34 @@ namespace BTCPayServer.Data
|
||||
o.UniqueId
|
||||
#pragma warning restore CS0618
|
||||
});
|
||||
|
||||
|
||||
builder.Entity<PaymentRequestData>()
|
||||
.HasOne(o => o.StoreData)
|
||||
.WithMany(i => i.PaymentRequests)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
builder.Entity<PaymentRequestData>()
|
||||
.Property(e => e.Created)
|
||||
.HasDefaultValue(new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero));
|
||||
|
||||
builder.Entity<PaymentRequestData>()
|
||||
.HasIndex(o => o.Status);
|
||||
|
||||
builder.Entity<WalletTransactionData>()
|
||||
.HasKey(o => new
|
||||
{
|
||||
o.WalletDataId,
|
||||
#pragma warning disable CS0618
|
||||
o.TransactionId
|
||||
#pragma warning restore CS0618
|
||||
});
|
||||
builder.Entity<WalletTransactionData>()
|
||||
.HasOne(o => o.WalletData)
|
||||
.WithMany(w => w.WalletTransactions).OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.UseOpenIddict<BTCPayOpenIdClient, BTCPayOpenIdAuthorization, OpenIddictScope<string>, BTCPayOpenIdToken, string>();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -3,8 +3,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Hangfire.MemoryStorage;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;
|
||||
using JetBrains.Annotations;
|
||||
@ -90,23 +88,13 @@ namespace BTCPayServer.Data
|
||||
public void ConfigureBuilder(DbContextOptionsBuilder builder)
|
||||
{
|
||||
if (_Type == DatabaseType.Sqlite)
|
||||
builder.UseSqlite(_ConnectionString);
|
||||
builder.UseSqlite(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data"));
|
||||
else if (_Type == DatabaseType.Postgres)
|
||||
builder
|
||||
.UseNpgsql(_ConnectionString)
|
||||
.UseNpgsql(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data"))
|
||||
.ReplaceService<IMigrationsSqlGenerator, CustomNpgsqlMigrationsSqlGenerator>();
|
||||
else if (_Type == DatabaseType.MySQL)
|
||||
builder.UseMySql(_ConnectionString);
|
||||
}
|
||||
|
||||
public void ConfigureHangfireBuilder(IGlobalConfiguration builder)
|
||||
{
|
||||
builder.UseMemoryStorage();
|
||||
//We always use memory storage because of incompatibilities with the latest postgres in 2.1
|
||||
//if (_Type == DatabaseType.Sqlite)
|
||||
// builder.UseMemoryStorage(); //Sqlite provider does not support multiple workers
|
||||
//else if (_Type == DatabaseType.Postgres)
|
||||
// builder.UsePostgreSqlStorage(_ConnectionString);
|
||||
builder.UseMySql(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data"));
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using BTCPayServer.Data;
|
||||
|
||||
namespace BTCPayServer.Models
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
// Add profile data for application users by adding properties to the ApplicationUser class
|
||||
public class ApplicationUser : IdentityUser
|
||||
@ -20,5 +20,15 @@ namespace BTCPayServer.Models
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<BTCPayOpenIdClient> OpenIdClients { get; set; }
|
||||
|
||||
public List<StoredFile> StoredFiles
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public List<U2FDevice> U2FDevices { get; set; }
|
||||
}
|
||||
}
|
6
BTCPayServer.Data/Data/BTCPayOpenIdAuthorization.cs
Normal file
6
BTCPayServer.Data/Data/BTCPayOpenIdAuthorization.cs
Normal file
@ -0,0 +1,6 @@
|
||||
using OpenIddict.EntityFrameworkCore.Models;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class BTCPayOpenIdAuthorization : OpenIddictAuthorization<string, BTCPayOpenIdClient, BTCPayOpenIdToken> { }
|
||||
}
|
10
BTCPayServer.Data/Data/BTCPayOpenIdClient.cs
Normal file
10
BTCPayServer.Data/Data/BTCPayOpenIdClient.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using OpenIddict.EntityFrameworkCore.Models;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class BTCPayOpenIdClient: OpenIddictApplication<string, BTCPayOpenIdAuthorization, BTCPayOpenIdToken>
|
||||
{
|
||||
public string ApplicationUserId { get; set; }
|
||||
public ApplicationUser ApplicationUser { get; set; }
|
||||
}
|
||||
}
|
6
BTCPayServer.Data/Data/BTCPayOpenIdToken.cs
Normal file
6
BTCPayServer.Data/Data/BTCPayOpenIdToken.cs
Normal file
@ -0,0 +1,6 @@
|
||||
using OpenIddict.EntityFrameworkCore.Models;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class BTCPayOpenIdToken : OpenIddictToken<string, BTCPayOpenIdClient, BTCPayOpenIdAuthorization> { }
|
||||
}
|
@ -31,29 +31,6 @@ namespace BTCPayServer.Data
|
||||
[Obsolete("Use GetCryptoCode instead")]
|
||||
public string CryptoCode { get; set; }
|
||||
|
||||
#pragma warning disable CS0618
|
||||
public Payments.PaymentMethodId GetPaymentMethodId()
|
||||
{
|
||||
return string.IsNullOrEmpty(CryptoCode) ? new Payments.PaymentMethodId("BTC", Payments.PaymentTypes.BTCLike)
|
||||
: Payments.PaymentMethodId.Parse(CryptoCode);
|
||||
}
|
||||
public string GetAddress()
|
||||
{
|
||||
if (Address == null)
|
||||
return null;
|
||||
var index = Address.IndexOf("#", StringComparison.InvariantCulture);
|
||||
if (index == -1)
|
||||
return Address;
|
||||
return Address.Substring(0, index);
|
||||
}
|
||||
public HistoricalAddressInvoiceData SetAddress(string depositAddress, string cryptoCode)
|
||||
{
|
||||
Address = depositAddress + "#" + cryptoCode;
|
||||
CryptoCode = cryptoCode;
|
||||
return this;
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
|
||||
public DateTimeOffset Assigned
|
||||
{
|
||||
get; set;
|
@ -1,5 +1,4 @@
|
||||
using BTCPayServer.Models;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
@ -15,7 +15,7 @@ namespace BTCPayServer.Data
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string UniqueId { get; internal set; }
|
||||
public string UniqueId { get; set; }
|
||||
public DateTimeOffset Timestamp
|
||||
{
|
||||
get; set;
|
@ -12,11 +12,6 @@ namespace BTCPayServer.Data
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string Facade
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string StoreDataId
|
||||
{
|
||||
get; set;
|
@ -11,7 +11,7 @@ namespace BTCPayServer.Data
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
[Obsolete("Unused")]
|
||||
public string Facade
|
||||
{
|
||||
get; set;
|
45
BTCPayServer.Data/Data/PaymentRequestData.cs
Normal file
45
BTCPayServer.Data/Data/PaymentRequestData.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class PaymentRequestData
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public DateTimeOffset Created
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string StoreDataId { get; set; }
|
||||
|
||||
public StoreData StoreData { get; set; }
|
||||
|
||||
public PaymentRequestStatus Status { get; set; }
|
||||
|
||||
public byte[] Blob { get; set; }
|
||||
|
||||
public class PaymentRequestBlob
|
||||
{
|
||||
public decimal Amount { get; set; }
|
||||
public string Currency { get; set; }
|
||||
|
||||
public DateTime? ExpiryDate { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Email { get; set; }
|
||||
|
||||
public string EmbeddedCSS { get; set; }
|
||||
public string CustomCSSLink { get; set; }
|
||||
public bool AllowCustomPaymentAmounts { get; set; }
|
||||
}
|
||||
|
||||
public enum PaymentRequestStatus
|
||||
{
|
||||
Pending = 0,
|
||||
Completed = 1,
|
||||
Expired = 2
|
||||
}
|
||||
}
|
||||
}
|
102
BTCPayServer.Data/Data/StoreData.cs
Normal file
102
BTCPayServer.Data/Data/StoreData.cs
Normal file
@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public enum SpeedPolicy
|
||||
{
|
||||
HighSpeed = 0,
|
||||
MediumSpeed = 1,
|
||||
LowSpeed = 2,
|
||||
LowMediumSpeed = 3
|
||||
}
|
||||
public class StoreData
|
||||
{
|
||||
public string Id
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public List<UserStore> UserStores
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public List<AppData> Apps
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<PaymentRequestData> PaymentRequests
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<InvoiceData> Invoices { get; set; }
|
||||
|
||||
[Obsolete("Use GetDerivationStrategies instead")]
|
||||
public string DerivationStrategy
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
[Obsolete("Use GetDerivationStrategies instead")]
|
||||
public string DerivationStrategies
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string StoreName
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public SpeedPolicy SpeedPolicy
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string StoreWebsite
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public byte[] StoreCertificate
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
[NotMapped]
|
||||
[Obsolete]
|
||||
public string Role
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public byte[] StoreBlob
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
[Obsolete("Use GetDefaultPaymentId instead")]
|
||||
public string DefaultCrypto { get; set; }
|
||||
public List<PairedSINData> PairedSINs { get; set; }
|
||||
public IEnumerable<APIKeyData> APIKeys { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public List<Claim> AdditionalClaims { get; set; } = new List<Claim>();
|
||||
}
|
||||
|
||||
public enum NetworkFeeMode
|
||||
{
|
||||
MultiplePaymentsOnly,
|
||||
Always,
|
||||
Never
|
||||
}
|
||||
}
|
20
BTCPayServer.Data/Data/StoredFile.cs
Normal file
20
BTCPayServer.Data/Data/StoredFile.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class StoredFile
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public string Id { get; set; }
|
||||
|
||||
public string FileName { get; set; }
|
||||
public string StorageFileName { get; set; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
public string ApplicationUserId { get; set; }
|
||||
public ApplicationUser ApplicationUser
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
}
|
23
BTCPayServer.Data/Data/U2FDevice.cs
Normal file
23
BTCPayServer.Data/Data/U2FDevice.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class U2FDevice
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required] public byte[] KeyHandle { get; set; }
|
||||
|
||||
[Required] public byte[] PublicKey { get; set; }
|
||||
|
||||
[Required] public byte[] AttestationCert { get; set; }
|
||||
|
||||
[Required] public int Counter { get; set; }
|
||||
|
||||
public string ApplicationUserId { get; set; }
|
||||
public ApplicationUser ApplicationUser { get; set; }
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using BTCPayServer.Models;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
84
BTCPayServer.Data/Data/WalletData.cs
Normal file
84
BTCPayServer.Data/Data/WalletData.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class WalletData
|
||||
{
|
||||
[System.ComponentModel.DataAnnotations.Key]
|
||||
public string Id { get; set; }
|
||||
|
||||
public List<WalletTransactionData> WalletTransactions { get; set; }
|
||||
|
||||
public byte[] Blob { get; set; }
|
||||
}
|
||||
|
||||
public class Label
|
||||
{
|
||||
public Label(string value, string color)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
if (color == null)
|
||||
throw new ArgumentNullException(nameof(color));
|
||||
Value = value;
|
||||
Color = color;
|
||||
}
|
||||
|
||||
public string Value { get; }
|
||||
public string Color { get; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
Label item = obj as Label;
|
||||
if (item == null)
|
||||
return false;
|
||||
return Value.Equals(item.Value, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
public static bool operator ==(Label a, Label b)
|
||||
{
|
||||
if (System.Object.ReferenceEquals(a, b))
|
||||
return true;
|
||||
if (((object)a == null) || ((object)b == null))
|
||||
return false;
|
||||
return a.Value == b.Value;
|
||||
}
|
||||
|
||||
public static bool operator !=(Label a, Label b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Value.GetHashCode(StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
public class WalletBlobInfo
|
||||
{
|
||||
public Dictionary<string, string> LabelColors { get; set; } = new Dictionary<string, string>();
|
||||
|
||||
public IEnumerable<Label> GetLabels(WalletTransactionInfo transactionInfo)
|
||||
{
|
||||
foreach (var label in transactionInfo.Labels)
|
||||
{
|
||||
if (LabelColors.TryGetValue(label, out var color))
|
||||
{
|
||||
yield return new Label(label, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Label> GetLabels()
|
||||
{
|
||||
foreach (var kv in LabelColors)
|
||||
{
|
||||
yield return new Label(kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
BTCPayServer.Data/Data/WalletTransactionData.cs
Normal file
24
BTCPayServer.Data/Data/WalletTransactionData.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class WalletTransactionData
|
||||
{
|
||||
public string WalletDataId { get; set; }
|
||||
public WalletData WalletData { get; set; }
|
||||
public string TransactionId { get; set; }
|
||||
public string Labels { get; set; }
|
||||
public byte[] Blob { get; set; }
|
||||
}
|
||||
|
||||
public class WalletTransactionInfo
|
||||
{
|
||||
public string Comment { get; set; } = string.Empty;
|
||||
[JsonIgnore]
|
||||
public HashSet<string> Labels { get; set; } = new HashSet<string>();
|
||||
}
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20170913143004_Init")]
|
||||
public partial class Init : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20170926073744_Settings")]
|
||||
public partial class Settings : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20170926084408_RequiresEmailConfirmation")]
|
||||
public partial class RequiresEmailConfirmation : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20171006013443_AddressMapping")]
|
||||
public partial class AddressMapping : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20171010082424_Tokens")]
|
||||
public partial class Tokens : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20171012020112_PendingInvoices")]
|
||||
public partial class PendingInvoices : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20171023101754_StoreBlob")]
|
||||
public partial class StoreBlob : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20171024163354_RenewUsedAddresses")]
|
||||
public partial class RenewUsedAddresses : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20171105235734_PaymentAccounted")]
|
||||
public partial class PaymentAccounted : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20171221054550_AltcoinSupport")]
|
||||
public partial class AltcoinSupport : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20180106095215_DerivationStrategies")]
|
||||
public partial class DerivationStrategies : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20180109021122_defaultcrypto")]
|
||||
public partial class defaultcrypto : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20180114123253_events")]
|
||||
public partial class events : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20180402095640_appdata")]
|
||||
public partial class appdata : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,9 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20180429083930_legacyapikey")]
|
||||
public partial class legacyapikey : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -1,7 +1,11 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20180719095626_CanDeleteStores")]
|
||||
public partial class CanDeleteStores : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20190121133309_AddPaymentRequests")]
|
||||
public partial class AddPaymentRequests : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PaymentRequests",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
StoreDataId = table.Column<string>(nullable: true),
|
||||
Status = table.Column<int>(nullable: false),
|
||||
Blob = table.Column<byte[]>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PaymentRequests", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_PaymentRequests_Stores_StoreDataId",
|
||||
column: x => x.StoreDataId,
|
||||
principalTable: "Stores",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PaymentRequests_Status",
|
||||
table: "PaymentRequests",
|
||||
column: "Status");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PaymentRequests_StoreDataId",
|
||||
table: "PaymentRequests",
|
||||
column: "StoreDataId");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "PaymentRequests");
|
||||
}
|
||||
}
|
||||
}
|
27
BTCPayServer.Data/Migrations/20190219032533_AppsTagging.cs
Normal file
27
BTCPayServer.Data/Migrations/20190219032533_AppsTagging.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20190219032533_AppsTagging")]
|
||||
public partial class AppsTagging : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "TagAllInvoices",
|
||||
table: "Apps",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TagAllInvoices",
|
||||
table: "Apps");
|
||||
}
|
||||
}
|
||||
}
|
171
BTCPayServer.Data/Migrations/20190225091644_AddOpenIddict.cs
Normal file
171
BTCPayServer.Data/Migrations/20190225091644_AddOpenIddict.cs
Normal file
@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20190225091644_AddOpenIddict")]
|
||||
public partial class AddOpenIddict : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OpenIddictApplications",
|
||||
columns: table => new
|
||||
{
|
||||
ClientId = table.Column<string>(maxLength: 100, nullable: false),
|
||||
ClientSecret = table.Column<string>(nullable: true),
|
||||
ConcurrencyToken = table.Column<string>(maxLength: 50, nullable: true),
|
||||
ConsentType = table.Column<string>(nullable: true),
|
||||
DisplayName = table.Column<string>(nullable: true),
|
||||
Id = table.Column<string>(nullable: false),
|
||||
Permissions = table.Column<string>(nullable: true),
|
||||
PostLogoutRedirectUris = table.Column<string>(nullable: true),
|
||||
Properties = table.Column<string>(nullable: true),
|
||||
RedirectUris = table.Column<string>(nullable: true),
|
||||
Type = table.Column<string>(maxLength: 25, nullable: false),
|
||||
ApplicationUserId = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OpenIddictApplications", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_OpenIddictApplications_AspNetUsers_ApplicationUserId",
|
||||
column: x => x.ApplicationUserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OpenIddictScopes",
|
||||
columns: table => new
|
||||
{
|
||||
ConcurrencyToken = table.Column<string>(maxLength: 50, nullable: true),
|
||||
Description = table.Column<string>(nullable: true),
|
||||
DisplayName = table.Column<string>(nullable: true),
|
||||
Id = table.Column<string>(nullable: false),
|
||||
Name = table.Column<string>(maxLength: 200, nullable: false),
|
||||
Properties = table.Column<string>(nullable: true),
|
||||
Resources = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OpenIddictScopes", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OpenIddictAuthorizations",
|
||||
columns: table => new
|
||||
{
|
||||
ApplicationId = table.Column<string>(nullable: true),
|
||||
ConcurrencyToken = table.Column<string>(maxLength: 50, nullable: true),
|
||||
Id = table.Column<string>(nullable: false),
|
||||
Properties = table.Column<string>(nullable: true),
|
||||
Scopes = table.Column<string>(nullable: true),
|
||||
Status = table.Column<string>(maxLength: 25, nullable: false),
|
||||
Subject = table.Column<string>(maxLength: 450, nullable: false),
|
||||
Type = table.Column<string>(maxLength: 25, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OpenIddictAuthorizations", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_OpenIddictAuthorizations_OpenIddictApplications_ApplicationId",
|
||||
column: x => x.ApplicationId,
|
||||
principalTable: "OpenIddictApplications",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OpenIddictTokens",
|
||||
columns: table => new
|
||||
{
|
||||
ApplicationId = table.Column<string>(nullable: true),
|
||||
AuthorizationId = table.Column<string>(nullable: true),
|
||||
ConcurrencyToken = table.Column<string>(maxLength: 50, nullable: true),
|
||||
CreationDate = table.Column<DateTimeOffset>(nullable: true),
|
||||
ExpirationDate = table.Column<DateTimeOffset>(nullable: true),
|
||||
Id = table.Column<string>(nullable: false),
|
||||
Payload = table.Column<string>(nullable: true),
|
||||
Properties = table.Column<string>(nullable: true),
|
||||
ReferenceId = table.Column<string>(maxLength: 100, nullable: true),
|
||||
Status = table.Column<string>(maxLength: 25, nullable: false),
|
||||
Subject = table.Column<string>(maxLength: 450, nullable: false),
|
||||
Type = table.Column<string>(maxLength: 25, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OpenIddictTokens", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_OpenIddictTokens_OpenIddictApplications_ApplicationId",
|
||||
column: x => x.ApplicationId,
|
||||
principalTable: "OpenIddictApplications",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
table.ForeignKey(
|
||||
name: "FK_OpenIddictTokens_OpenIddictAuthorizations_AuthorizationId",
|
||||
column: x => x.AuthorizationId,
|
||||
principalTable: "OpenIddictAuthorizations",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OpenIddictApplications_ApplicationUserId",
|
||||
table: "OpenIddictApplications",
|
||||
column: "ApplicationUserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OpenIddictApplications_ClientId",
|
||||
table: "OpenIddictApplications",
|
||||
column: "ClientId",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OpenIddictAuthorizations_ApplicationId_Status_Subject_Type",
|
||||
table: "OpenIddictAuthorizations",
|
||||
columns: new[] { "ApplicationId", "Status", "Subject", "Type" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OpenIddictScopes_Name",
|
||||
table: "OpenIddictScopes",
|
||||
column: "Name",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OpenIddictTokens_AuthorizationId",
|
||||
table: "OpenIddictTokens",
|
||||
column: "AuthorizationId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OpenIddictTokens_ReferenceId",
|
||||
table: "OpenIddictTokens",
|
||||
column: "ReferenceId",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OpenIddictTokens_ApplicationId_Status_Subject_Type",
|
||||
table: "OpenIddictTokens",
|
||||
columns: new[] { "ApplicationId", "Status", "Subject", "Type" });
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "OpenIddictScopes");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "OpenIddictTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "OpenIddictAuthorizations");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "OpenIddictApplications");
|
||||
}
|
||||
}
|
||||
}
|
47
BTCPayServer.Data/Migrations/20190324141717_AddFiles.cs
Normal file
47
BTCPayServer.Data/Migrations/20190324141717_AddFiles.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20190324141717_AddFiles")]
|
||||
public partial class AddFiles : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Files",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
FileName = table.Column<string>(nullable: true),
|
||||
StorageFileName = table.Column<string>(nullable: true),
|
||||
Timestamp = table.Column<DateTime>(nullable: false),
|
||||
ApplicationUserId = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Files", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Files_AspNetUsers_ApplicationUserId",
|
||||
column: x => x.ApplicationUserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Files_ApplicationUserId",
|
||||
table: "Files",
|
||||
column: "ApplicationUserId");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Files");
|
||||
}
|
||||
}
|
||||
}
|
64
BTCPayServer.Data/Migrations/20190425081749_AddU2fDevices.cs
Normal file
64
BTCPayServer.Data/Migrations/20190425081749_AddU2fDevices.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20190425081749_AddU2fDevices")]
|
||||
public partial class AddU2fDevices : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
if (this.SupportDropColumn(migrationBuilder.ActiveProvider))
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Facade",
|
||||
table: "PairedSINData");
|
||||
}
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "U2FDevices",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
Name = table.Column<string>(nullable: true),
|
||||
KeyHandle = table.Column<byte[]>(nullable: false),
|
||||
PublicKey = table.Column<byte[]>(nullable: false),
|
||||
AttestationCert = table.Column<byte[]>(nullable: false),
|
||||
Counter = table.Column<int>(nullable: false),
|
||||
ApplicationUserId = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_U2FDevices", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_U2FDevices_AspNetUsers_ApplicationUserId",
|
||||
column: x => x.ApplicationUserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_U2FDevices_ApplicationUserId",
|
||||
table: "U2FDevices",
|
||||
column: "ApplicationUserId");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "U2FDevices");
|
||||
//if it did not support dropping it, then it is still here and re-adding it would throw
|
||||
if (this.SupportDropColumn(migrationBuilder.ActiveProvider))
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Facade",
|
||||
table: "PairedSINData",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20190701082105_sort_paymentrequests")]
|
||||
public partial class sort_paymentrequests : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||
name: "Created",
|
||||
table: "PaymentRequests",
|
||||
nullable: false,
|
||||
defaultValue: new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)));
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Created",
|
||||
table: "PaymentRequests");
|
||||
}
|
||||
}
|
||||
}
|
56
BTCPayServer.Data/Migrations/20190802142637_WalletData.cs
Normal file
56
BTCPayServer.Data/Migrations/20190802142637_WalletData.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20190802142637_WalletData")]
|
||||
public partial class WalletData : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Wallets",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
Blob = table.Column<byte[]>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Wallets", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "WalletTransactions",
|
||||
columns: table => new
|
||||
{
|
||||
WalletDataId = table.Column<string>(nullable: false),
|
||||
TransactionId = table.Column<string>(nullable: false),
|
||||
Labels = table.Column<string>(nullable: true),
|
||||
Blob = table.Column<byte[]>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_WalletTransactions", x => new { x.WalletDataId, x.TransactionId });
|
||||
table.ForeignKey(
|
||||
name: "FK_WalletTransactions_Wallets_WalletDataId",
|
||||
column: x => x.WalletDataId,
|
||||
principalTable: "Wallets",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "WalletTransactions");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Wallets");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,883 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.11-servicing-32099");
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.AddressInvoiceData", b =>
|
||||
{
|
||||
b.Property<string>("Address")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTimeOffset?>("CreatedTime");
|
||||
|
||||
b.Property<string>("InvoiceDataId");
|
||||
|
||||
b.HasKey("Address");
|
||||
|
||||
b.HasIndex("InvoiceDataId");
|
||||
|
||||
b.ToTable("AddressInvoices");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.APIKeyData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("StoreId")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("StoreId");
|
||||
|
||||
b.ToTable("ApiKeys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.AppData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("AppType");
|
||||
|
||||
b.Property<DateTimeOffset>("Created");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Settings");
|
||||
|
||||
b.Property<string>("StoreDataId");
|
||||
|
||||
b.Property<bool>("TagAllInvoices");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("StoreDataId");
|
||||
|
||||
b.ToTable("Apps");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<bool>("RequiresEmailConfirmation");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.BTCPayOpenIdAuthorization", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationId");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("Properties");
|
||||
|
||||
b.Property<string>("Scopes");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasMaxLength(25);
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.IsRequired()
|
||||
.HasMaxLength(450);
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasMaxLength(25);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApplicationId", "Status", "Subject", "Type");
|
||||
|
||||
b.ToTable("OpenIddictAuthorizations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.BTCPayOpenIdClient", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationUserId");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("ClientSecret");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("ConsentType");
|
||||
|
||||
b.Property<string>("DisplayName");
|
||||
|
||||
b.Property<string>("Permissions");
|
||||
|
||||
b.Property<string>("PostLogoutRedirectUris");
|
||||
|
||||
b.Property<string>("Properties");
|
||||
|
||||
b.Property<string>("RedirectUris");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasMaxLength(25);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApplicationUserId");
|
||||
|
||||
b.HasIndex("ClientId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("OpenIddictApplications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.BTCPayOpenIdToken", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationId");
|
||||
|
||||
b.Property<string>("AuthorizationId");
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<DateTimeOffset?>("CreationDate");
|
||||
|
||||
b.Property<DateTimeOffset?>("ExpirationDate");
|
||||
|
||||
b.Property<string>("Payload");
|
||||
|
||||
b.Property<string>("Properties");
|
||||
|
||||
b.Property<string>("ReferenceId")
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasMaxLength(25);
|
||||
|
||||
b.Property<string>("Subject")
|
||||
.IsRequired()
|
||||
.HasMaxLength(450);
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasMaxLength(25);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AuthorizationId");
|
||||
|
||||
b.HasIndex("ReferenceId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("ApplicationId", "Status", "Subject", "Type");
|
||||
|
||||
b.ToTable("OpenIddictTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.HistoricalAddressInvoiceData", b =>
|
||||
{
|
||||
b.Property<string>("InvoiceDataId");
|
||||
|
||||
b.Property<string>("Address");
|
||||
|
||||
b.Property<DateTimeOffset>("Assigned");
|
||||
|
||||
b.Property<string>("CryptoCode");
|
||||
|
||||
b.Property<DateTimeOffset?>("UnAssigned");
|
||||
|
||||
b.HasKey("InvoiceDataId", "Address");
|
||||
|
||||
b.ToTable("HistoricalAddressInvoices");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.InvoiceData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<byte[]>("Blob");
|
||||
|
||||
b.Property<DateTimeOffset>("Created");
|
||||
|
||||
b.Property<string>("CustomerEmail");
|
||||
|
||||
b.Property<string>("ExceptionStatus");
|
||||
|
||||
b.Property<string>("ItemCode");
|
||||
|
||||
b.Property<string>("OrderId");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<string>("StoreDataId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("StoreDataId");
|
||||
|
||||
b.ToTable("Invoices");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.InvoiceEventData", b =>
|
||||
{
|
||||
b.Property<string>("InvoiceDataId");
|
||||
|
||||
b.Property<string>("UniqueId");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<DateTimeOffset>("Timestamp");
|
||||
|
||||
b.HasKey("InvoiceDataId", "UniqueId");
|
||||
|
||||
b.ToTable("InvoiceEvents");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.PairedSINData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Label");
|
||||
|
||||
b.Property<DateTimeOffset>("PairingTime");
|
||||
|
||||
b.Property<string>("SIN");
|
||||
|
||||
b.Property<string>("StoreDataId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SIN");
|
||||
|
||||
b.HasIndex("StoreDataId");
|
||||
|
||||
b.ToTable("PairedSINData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.PairingCodeData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("DateCreated");
|
||||
|
||||
b.Property<DateTimeOffset>("Expiration");
|
||||
|
||||
b.Property<string>("Facade");
|
||||
|
||||
b.Property<string>("Label");
|
||||
|
||||
b.Property<string>("SIN");
|
||||
|
||||
b.Property<string>("StoreDataId");
|
||||
|
||||
b.Property<string>("TokenValue");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PairingCodes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.PaymentData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Accounted");
|
||||
|
||||
b.Property<byte[]>("Blob");
|
||||
|
||||
b.Property<string>("InvoiceDataId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("InvoiceDataId");
|
||||
|
||||
b.ToTable("Payments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.PaymentRequestData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<byte[]>("Blob");
|
||||
|
||||
b.Property<DateTimeOffset>("Created")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValue(new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)));
|
||||
|
||||
b.Property<int>("Status");
|
||||
|
||||
b.Property<string>("StoreDataId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Status");
|
||||
|
||||
b.HasIndex("StoreDataId");
|
||||
|
||||
b.ToTable("PaymentRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.PendingInvoiceData", b =>
|
||||
{
|
||||
b.Property<string>("Id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PendingInvoices");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.RefundAddressesData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<byte[]>("Blob");
|
||||
|
||||
b.Property<string>("InvoiceDataId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("InvoiceDataId");
|
||||
|
||||
b.ToTable("RefundAddresses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.SettingData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.StoreData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("DefaultCrypto");
|
||||
|
||||
b.Property<string>("DerivationStrategies");
|
||||
|
||||
b.Property<string>("DerivationStrategy");
|
||||
|
||||
b.Property<int>("SpeedPolicy");
|
||||
|
||||
b.Property<byte[]>("StoreBlob");
|
||||
|
||||
b.Property<byte[]>("StoreCertificate");
|
||||
|
||||
b.Property<string>("StoreName");
|
||||
|
||||
b.Property<string>("StoreWebsite");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Stores");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.StoredFile", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationUserId");
|
||||
|
||||
b.Property<string>("FileName");
|
||||
|
||||
b.Property<string>("StorageFileName");
|
||||
|
||||
b.Property<DateTime>("Timestamp");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApplicationUserId");
|
||||
|
||||
b.ToTable("Files");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.U2FDevice", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApplicationUserId");
|
||||
|
||||
b.Property<byte[]>("AttestationCert")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<int>("Counter");
|
||||
|
||||
b.Property<byte[]>("KeyHandle")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<byte[]>("PublicKey")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApplicationUserId");
|
||||
|
||||
b.ToTable("U2FDevices");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.UserStore", b =>
|
||||
{
|
||||
b.Property<string>("ApplicationUserId");
|
||||
|
||||
b.Property<string>("StoreDataId");
|
||||
|
||||
b.Property<string>("Role");
|
||||
|
||||
b.HasKey("ApplicationUserId", "StoreDataId");
|
||||
|
||||
b.HasIndex("StoreDataId");
|
||||
|
||||
b.ToTable("UserStore");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.WalletData", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<byte[]>("Blob");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Wallets");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.WalletTransactionData", b =>
|
||||
{
|
||||
b.Property<string>("WalletDataId");
|
||||
|
||||
b.Property<string>("TransactionId");
|
||||
|
||||
b.Property<byte[]>("Blob");
|
||||
|
||||
b.Property<string>("Labels");
|
||||
|
||||
b.HasKey("WalletDataId", "TransactionId");
|
||||
|
||||
b.ToTable("WalletTransactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictScope<string>", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyToken")
|
||||
.IsConcurrencyToken()
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("DisplayName");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.Property<string>("Properties");
|
||||
|
||||
b.Property<string>("Resources");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Name")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("OpenIddictScopes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.AddressInvoiceData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
||||
.WithMany("AddressInvoices")
|
||||
.HasForeignKey("InvoiceDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.APIKeyData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.StoreData", "StoreData")
|
||||
.WithMany("APIKeys")
|
||||
.HasForeignKey("StoreId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.AppData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.StoreData", "StoreData")
|
||||
.WithMany("Apps")
|
||||
.HasForeignKey("StoreDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.BTCPayOpenIdAuthorization", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.BTCPayOpenIdClient", "Application")
|
||||
.WithMany("Authorizations")
|
||||
.HasForeignKey("ApplicationId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.BTCPayOpenIdClient", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.ApplicationUser", "ApplicationUser")
|
||||
.WithMany("OpenIdClients")
|
||||
.HasForeignKey("ApplicationUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.BTCPayOpenIdToken", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.BTCPayOpenIdClient", "Application")
|
||||
.WithMany("Tokens")
|
||||
.HasForeignKey("ApplicationId");
|
||||
|
||||
b.HasOne("BTCPayServer.Data.BTCPayOpenIdAuthorization", "Authorization")
|
||||
.WithMany("Tokens")
|
||||
.HasForeignKey("AuthorizationId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.HistoricalAddressInvoiceData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
||||
.WithMany("HistoricalAddressInvoices")
|
||||
.HasForeignKey("InvoiceDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.InvoiceData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.StoreData", "StoreData")
|
||||
.WithMany("Invoices")
|
||||
.HasForeignKey("StoreDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.InvoiceEventData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
||||
.WithMany("Events")
|
||||
.HasForeignKey("InvoiceDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.PairedSINData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.StoreData", "StoreData")
|
||||
.WithMany("PairedSINs")
|
||||
.HasForeignKey("StoreDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.PaymentData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
||||
.WithMany("Payments")
|
||||
.HasForeignKey("InvoiceDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.PaymentRequestData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.StoreData", "StoreData")
|
||||
.WithMany("PaymentRequests")
|
||||
.HasForeignKey("StoreDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.PendingInvoiceData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
||||
.WithMany("PendingInvoices")
|
||||
.HasForeignKey("Id")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.RefundAddressesData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
||||
.WithMany("RefundAddresses")
|
||||
.HasForeignKey("InvoiceDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.StoredFile", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.ApplicationUser", "ApplicationUser")
|
||||
.WithMany("StoredFiles")
|
||||
.HasForeignKey("ApplicationUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.U2FDevice", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.ApplicationUser", "ApplicationUser")
|
||||
.WithMany("U2FDevices")
|
||||
.HasForeignKey("ApplicationUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.UserStore", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.ApplicationUser", "ApplicationUser")
|
||||
.WithMany("UserStores")
|
||||
.HasForeignKey("ApplicationUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("BTCPayServer.Data.StoreData", "StoreData")
|
||||
.WithMany("UserStores")
|
||||
.HasForeignKey("StoreDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BTCPayServer.Data.WalletTransactionData", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.WalletData", "WalletData")
|
||||
.WithMany("WalletTransactions")
|
||||
.HasForeignKey("WalletDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("BTCPayServer.Data.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("BTCPayServer.Data.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
24
BTCPayServer.Data/MigrationsExtensions.cs
Normal file
24
BTCPayServer.Data/MigrationsExtensions.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
public static class MigrationsExtensions
|
||||
{
|
||||
public static bool SupportDropColumn(this Microsoft.EntityFrameworkCore.Migrations.Migration migration, string activeProvider)
|
||||
{
|
||||
return activeProvider != "Microsoft.EntityFrameworkCore.Sqlite";
|
||||
}
|
||||
|
||||
public static bool SupportDropForeignKey(this Microsoft.EntityFrameworkCore.Migrations.Migration migration, string activeProvider)
|
||||
{
|
||||
return activeProvider != "Microsoft.EntityFrameworkCore.Sqlite";
|
||||
}
|
||||
public static bool SupportDropForeignKey(this DatabaseFacade facade)
|
||||
{
|
||||
return facade.ProviderName != "Microsoft.EntityFrameworkCore.Sqlite";
|
||||
}
|
||||
}
|
||||
}
|
23
BTCPayServer.Rating/BTCPayServer.Rating.csproj
Normal file
23
BTCPayServer.Rating/BTCPayServer.Rating.csproj
Normal file
@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Providers\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.9" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="DigitalRuby.ExchangeSharp" Version="0.5.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BTCPayServer.Common\BTCPayServer.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -53,7 +53,7 @@ namespace BTCPayServer.Rating
|
||||
for (int i = 3; i < 5; i++)
|
||||
{
|
||||
var potentialCryptoName = currencyPair.Substring(0, i);
|
||||
var network = _NetworkProvider.GetNetwork(potentialCryptoName);
|
||||
var network = _NetworkProvider.GetNetwork<BTCPayNetworkBase>(potentialCryptoName);
|
||||
if (network != null)
|
||||
{
|
||||
value = new CurrencyPair(network.CryptoCode, currencyPair.Substring(i));
|
@ -4,9 +4,10 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Rating;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using BTCPayServer.Logging;
|
||||
|
||||
namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
@ -16,6 +17,7 @@ namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
public ExchangeRates Latest;
|
||||
public DateTimeOffset NextRefresh;
|
||||
public TimeSpan Backoff = TimeSpan.FromSeconds(5.0);
|
||||
public DateTimeOffset Expiration;
|
||||
public Exception Exception;
|
||||
public string ExchangeName;
|
||||
@ -37,6 +39,7 @@ namespace BTCPayServer.Services.Rates
|
||||
}
|
||||
|
||||
IRateProvider _Inner;
|
||||
|
||||
public BackgroundFetcherRateProvider(IRateProvider inner)
|
||||
{
|
||||
if (inner == null)
|
||||
@ -90,14 +93,15 @@ namespace BTCPayServer.Services.Rates
|
||||
}
|
||||
|
||||
public bool DoNotAutoFetchIfExpired { get; set; }
|
||||
readonly static TimeSpan MaxBackoff = TimeSpan.FromMinutes(5.0);
|
||||
|
||||
public async Task<LatestFetch> UpdateIfNecessary()
|
||||
public async Task<LatestFetch> UpdateIfNecessary(CancellationToken cancellationToken)
|
||||
{
|
||||
if (NextUpdate <= DateTimeOffset.UtcNow)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Fetch();
|
||||
await Fetch(cancellationToken);
|
||||
}
|
||||
catch { } // Exception is inside _Latest
|
||||
return _Latest;
|
||||
@ -106,7 +110,7 @@ namespace BTCPayServer.Services.Rates
|
||||
}
|
||||
|
||||
LatestFetch _Latest;
|
||||
public async Task<ExchangeRates> GetRatesAsync()
|
||||
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var latest = _Latest;
|
||||
if (!DoNotAutoFetchIfExpired && latest != null && latest.Expiration <= DateTimeOffset.UtcNow + TimeSpan.FromSeconds(1.0))
|
||||
@ -114,7 +118,7 @@ namespace BTCPayServer.Services.Rates
|
||||
Logs.PayServer.LogWarning($"GetRatesAsync was called on {GetExchangeName()} when the rate is outdated. It should never happen, let BTCPayServer developers know about this.");
|
||||
latest = null;
|
||||
}
|
||||
return (latest ?? (await Fetch())).GetResult();
|
||||
return (latest ?? (await Fetch(cancellationToken))).GetResult();
|
||||
}
|
||||
|
||||
private string GetExchangeName()
|
||||
@ -124,14 +128,14 @@ namespace BTCPayServer.Services.Rates
|
||||
return "???";
|
||||
}
|
||||
|
||||
private async Task<LatestFetch> Fetch()
|
||||
private async Task<LatestFetch> Fetch(CancellationToken cancellationToken)
|
||||
{
|
||||
var previous = _Latest;
|
||||
var fetch = new LatestFetch();
|
||||
fetch.ExchangeName = GetExchangeName();
|
||||
try
|
||||
{
|
||||
var rates = await _Inner.GetRatesAsync();
|
||||
var rates = await _Inner.GetRatesAsync(cancellationToken);
|
||||
fetch.Latest = rates;
|
||||
fetch.Expiration = DateTimeOffset.UtcNow + ValidatyTime;
|
||||
fetch.NextRefresh = DateTimeOffset.UtcNow + RefreshRate;
|
||||
@ -142,12 +146,15 @@ namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
fetch.Latest = previous.Latest;
|
||||
fetch.Expiration = previous.Expiration;
|
||||
fetch.Backoff = previous.Backoff * 2;
|
||||
if (fetch.Backoff > MaxBackoff)
|
||||
fetch.Backoff = MaxBackoff;
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch.Expiration = DateTimeOffset.UtcNow;
|
||||
}
|
||||
fetch.NextRefresh = DateTimeOffset.UtcNow;
|
||||
fetch.NextRefresh = DateTimeOffset.UtcNow + fetch.Backoff;
|
||||
fetch.Exception = ex;
|
||||
}
|
||||
_Latest = fetch;
|
40
BTCPayServer.Rating/Providers/BitbankRateProvider.cs
Normal file
40
BTCPayServer.Rating/Providers/BitbankRateProvider.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
public class BitbankRateProvider : IRateProvider, IHasExchangeName
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
public BitbankRateProvider(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
public string ExchangeName => "bitbank";
|
||||
|
||||
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _httpClient.GetAsync("https://public.bitbank.cc/prices", cancellationToken);
|
||||
var jobj = await response.Content.ReadAsAsync<JObject>(cancellationToken);
|
||||
return new ExchangeRates(((jobj["data"] as JObject) ?? new JObject())
|
||||
.Properties()
|
||||
.Select(p => new ExchangeRate(ExchangeName, CurrencyPair.Parse(p.Name), CreateBidAsk(p)))
|
||||
.ToArray());
|
||||
|
||||
}
|
||||
|
||||
private static BidAsk CreateBidAsk(JProperty p)
|
||||
{
|
||||
var buy = p.Value["buy"].Value<decimal>();
|
||||
var sell = p.Value["sell"].Value<decimal>();
|
||||
// Bug from their API (https://github.com/btcpayserver/btcpayserver/issues/741)
|
||||
return buy < sell ? new BidAsk(buy, sell) : new BidAsk(sell, buy);
|
||||
}
|
||||
}
|
||||
}
|
35
BTCPayServer.Rating/Providers/BitpayRateProvider.cs
Normal file
35
BTCPayServer.Rating/Providers/BitpayRateProvider.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using System.Threading;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
public class BitpayRateProvider : IRateProvider, IHasExchangeName
|
||||
{
|
||||
public const string BitpayName = "bitpay";
|
||||
private readonly HttpClient _httpClient;
|
||||
public BitpayRateProvider(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
|
||||
public string ExchangeName => BitpayName;
|
||||
|
||||
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _httpClient.GetAsync("https://bitpay.com/rates", cancellationToken);
|
||||
var jarray = (JArray)(await response.Content.ReadAsAsync<JObject>(cancellationToken))["data"];
|
||||
return new ExchangeRates(jarray
|
||||
.Children<JObject>()
|
||||
.Select(jobj => new ExchangeRate(ExchangeName, new CurrencyPair("BTC", jobj["code"].Value<string>()), new BidAsk(jobj["rate"].Value<decimal>())))
|
||||
.Where(o => o.CurrencyPair.Right != "BTC")
|
||||
.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
29
BTCPayServer.Rating/Providers/ByllsRateProvider.cs
Normal file
29
BTCPayServer.Rating/Providers/ByllsRateProvider.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
public class ByllsRateProvider : IRateProvider, IHasExchangeName
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
public ByllsRateProvider(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
public string ExchangeName => "bylls";
|
||||
|
||||
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _httpClient.GetAsync("https://bylls.com/api/price?from_currency=BTC&to_currency=CAD", cancellationToken);
|
||||
var jobj = await response.Content.ReadAsAsync<JObject>(cancellationToken);
|
||||
var value = jobj["public_price"]["to_price"].Value<decimal>();
|
||||
return new ExchangeRates(new[] { new ExchangeRate(ExchangeName, new CurrencyPair("BTC", "CAD"), new BidAsk(value)) });
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using BTCPayServer.Services.Rates;
|
||||
@ -40,12 +41,12 @@ namespace BTCPayServer.Services.Rates
|
||||
} = TimeSpan.FromMinutes(1.0);
|
||||
public IMemoryCache MemoryCache { get => _MemoryCache; set => _MemoryCache = value; }
|
||||
|
||||
public Task<ExchangeRates> GetRatesAsync()
|
||||
public Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return MemoryCache.GetOrCreateAsync("EXCHANGE_RATES_" + ExchangeName, (ICacheEntry entry) =>
|
||||
{
|
||||
entry.AbsoluteExpiration = DateTimeOffset.UtcNow + CacheSpan;
|
||||
return _Inner.GetRatesAsync();
|
||||
return _Inner.GetRatesAsync(cancellationToken);
|
||||
});
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.ComponentModel;
|
||||
using BTCPayServer.Rating;
|
||||
using System.Threading;
|
||||
|
||||
namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
@ -65,7 +66,7 @@ namespace BTCPayServer.Services.Rates
|
||||
}
|
||||
set
|
||||
{
|
||||
_LocalClient = null;
|
||||
_LocalClient = value;
|
||||
}
|
||||
}
|
||||
HttpClient _LocalClient;
|
||||
@ -111,7 +112,7 @@ namespace BTCPayServer.Services.Rates
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ExchangeRates> GetRatesAsync()
|
||||
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
string url = Exchange == CoinAverageName ? $"https://apiv2.bitcoinaverage.com/indices/{Market}/ticker/short"
|
||||
: $"https://apiv2.bitcoinaverage.com/exchanges/{Exchange}";
|
||||
@ -122,7 +123,7 @@ namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
await auth.AddHeader(request);
|
||||
}
|
||||
var resp = await HttpClient.SendAsync(request);
|
||||
var resp = await HttpClient.SendAsync(request, cancellationToken);
|
||||
using (resp)
|
||||
{
|
||||
|
@ -23,20 +23,18 @@ namespace BTCPayServer.Services.Rates
|
||||
|
||||
public class CoinAverageExchange
|
||||
{
|
||||
public CoinAverageExchange(string name, string display)
|
||||
public CoinAverageExchange(string name, string display, string url)
|
||||
{
|
||||
Name = name;
|
||||
Display = display;
|
||||
Url = url;
|
||||
}
|
||||
public string Name { get; set; }
|
||||
public string Display { get; set; }
|
||||
public string Url
|
||||
{
|
||||
get
|
||||
{
|
||||
return Name == CoinAverageRateProvider.CoinAverageName ? $"https://apiv2.bitcoinaverage.com/indices/global/ticker/short"
|
||||
: $"https://apiv2.bitcoinaverage.com/exchanges/{Name}";
|
||||
}
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
public class CoinAverageExchanges : Dictionary<string, CoinAverageExchange>
|
||||
@ -47,7 +45,11 @@ namespace BTCPayServer.Services.Rates
|
||||
|
||||
public void Add(CoinAverageExchange exchange)
|
||||
{
|
||||
TryAdd(exchange.Name, exchange);
|
||||
if (!TryAdd(exchange.Name, exchange))
|
||||
{
|
||||
this.Remove(exchange.Name);
|
||||
this.Add(exchange.Name, exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class CoinAverageSettings : ICoinAverageAuthenticator
|
||||
@ -68,62 +70,73 @@ namespace BTCPayServer.Services.Rates
|
||||
//}
|
||||
//b.AppendLine("}.ToArray()");
|
||||
AvailableExchanges = new CoinAverageExchanges();
|
||||
foreach(var item in
|
||||
foreach (var item in
|
||||
new[] {
|
||||
(DisplayName: "BitBargain", Name: "bitbargain"),
|
||||
(DisplayName: "Tidex", Name: "tidex"),
|
||||
(DisplayName: "LocalBitcoins", Name: "localbitcoins"),
|
||||
(DisplayName: "EtherDelta", Name: "etherdelta"),
|
||||
(DisplayName: "Kraken", Name: "kraken"),
|
||||
(DisplayName: "BitBay", Name: "bitbay"),
|
||||
(DisplayName: "Independent Reserve", Name: "independentreserve"),
|
||||
(DisplayName: "Exmoney", Name: "exmoney"),
|
||||
(DisplayName: "Bitcoin.co.id", Name: "bitcoin_co_id"),
|
||||
(DisplayName: "Huobi", Name: "huobi"),
|
||||
(DisplayName: "GDAX", Name: "gdax"),
|
||||
(DisplayName: "Coincheck", Name: "coincheck"),
|
||||
(DisplayName: "Bittylicious", Name: "bittylicious"),
|
||||
(DisplayName: "Gemini", Name: "gemini"),
|
||||
(DisplayName: "QuadrigaCX", Name: "quadrigacx"),
|
||||
(DisplayName: "Bit2C", Name: "bit2c"),
|
||||
(DisplayName: "Luno", Name: "luno"),
|
||||
(DisplayName: "Negocie Coins", Name: "negociecoins"),
|
||||
(DisplayName: "FYB-SE", Name: "fybse"),
|
||||
(DisplayName: "Hitbtc", Name: "hitbtc"),
|
||||
(DisplayName: "Bitex.la", Name: "bitex"),
|
||||
(DisplayName: "Korbit", Name: "korbit"),
|
||||
(DisplayName: "itBit", Name: "itbit"),
|
||||
(DisplayName: "Okex", Name: "okex"),
|
||||
(DisplayName: "Bitsquare", Name: "bitsquare"),
|
||||
(DisplayName: "Bitfinex", Name: "bitfinex"),
|
||||
(DisplayName: "CoinMate", Name: "coinmate"),
|
||||
(DisplayName: "Bitstamp", Name: "bitstamp"),
|
||||
(DisplayName: "Cryptonit", Name: "cryptonit"),
|
||||
(DisplayName: "Foxbit", Name: "foxbit"),
|
||||
(DisplayName: "QuickBitcoin", Name: "quickbitcoin"),
|
||||
(DisplayName: "Poloniex", Name: "poloniex"),
|
||||
(DisplayName: "Bit-Z", Name: "bitz"),
|
||||
(DisplayName: "Liqui", Name: "liqui"),
|
||||
(DisplayName: "BitKonan", Name: "bitkonan"),
|
||||
(DisplayName: "Kucoin", Name: "kucoin"),
|
||||
(DisplayName: "Binance", Name: "binance"),
|
||||
(DisplayName: "Rock Trading", Name: "rocktrading"),
|
||||
(DisplayName: "Mercado Bitcoin", Name: "mercado"),
|
||||
(DisplayName: "Coinsecure", Name: "coinsecure"),
|
||||
(DisplayName: "Idex", Name: "idex"),
|
||||
(DisplayName: "Coinfloor", Name: "coinfloor"),
|
||||
(DisplayName: "bitFlyer", Name: "bitflyer"),
|
||||
(DisplayName: "BTCTurk", Name: "btcturk"),
|
||||
(DisplayName: "Bittrex", Name: "bittrex"),
|
||||
(DisplayName: "CampBX", Name: "campbx"),
|
||||
(DisplayName: "Zaif", Name: "zaif"),
|
||||
(DisplayName: "FYB-SG", Name: "fybsg"),
|
||||
(DisplayName: "Quoine", Name: "quoine"),
|
||||
(DisplayName: "Okex", Name: "okex"),
|
||||
(DisplayName: "Bitfinex", Name: "bitfinex"),
|
||||
(DisplayName: "Bittylicious", Name: "bittylicious"),
|
||||
(DisplayName: "BTC Markets", Name: "btcmarkets"),
|
||||
(DisplayName: "Kucoin", Name: "kucoin"),
|
||||
(DisplayName: "IDAX", Name: "idax"),
|
||||
(DisplayName: "Kraken", Name: "kraken"),
|
||||
(DisplayName: "Bit2C", Name: "bit2c"),
|
||||
(DisplayName: "Mercado Bitcoin", Name: "mercado"),
|
||||
(DisplayName: "CEX.IO", Name: "cex"),
|
||||
(DisplayName: "Bitex.la", Name: "bitex"),
|
||||
(DisplayName: "Quoine", Name: "quoine"),
|
||||
(DisplayName: "Stex", Name: "stex"),
|
||||
(DisplayName: "CoinTiger", Name: "cointiger"),
|
||||
(DisplayName: "Poloniex", Name: "poloniex"),
|
||||
(DisplayName: "Zaif", Name: "zaif"),
|
||||
(DisplayName: "Huobi", Name: "huobi"),
|
||||
(DisplayName: "QuickBitcoin", Name: "quickbitcoin"),
|
||||
(DisplayName: "Tidex", Name: "tidex"),
|
||||
(DisplayName: "Tokenomy", Name: "tokenomy"),
|
||||
(DisplayName: "Bitcoin.co.id", Name: "bitcoin_co_id"),
|
||||
(DisplayName: "Kryptono", Name: "kryptono"),
|
||||
(DisplayName: "Bitso", Name: "bitso"),
|
||||
(DisplayName: "Korbit", Name: "korbit"),
|
||||
(DisplayName: "Yobit", Name: "yobit"),
|
||||
(DisplayName: "BitBargain", Name: "bitbargain"),
|
||||
(DisplayName: "Livecoin", Name: "livecoin"),
|
||||
(DisplayName: "Hotbit", Name: "hotbit"),
|
||||
(DisplayName: "Coincheck", Name: "coincheck"),
|
||||
(DisplayName: "Binance", Name: "binance"),
|
||||
(DisplayName: "Bit-Z", Name: "bitz"),
|
||||
(DisplayName: "Coinbase Pro", Name: "coinbasepro"),
|
||||
(DisplayName: "Rock Trading", Name: "rocktrading"),
|
||||
(DisplayName: "Bittrex", Name: "bittrex"),
|
||||
(DisplayName: "BitBay", Name: "bitbay"),
|
||||
(DisplayName: "Tokenize", Name: "tokenize"),
|
||||
(DisplayName: "Hitbtc", Name: "hitbtc"),
|
||||
(DisplayName: "Upbit", Name: "upbit"),
|
||||
(DisplayName: "Bitstamp", Name: "bitstamp"),
|
||||
(DisplayName: "Luno", Name: "luno"),
|
||||
(DisplayName: "Trade.io", Name: "tradeio"),
|
||||
(DisplayName: "LocalBitcoins", Name: "localbitcoins"),
|
||||
(DisplayName: "Independent Reserve", Name: "independentreserve"),
|
||||
(DisplayName: "Coinsquare", Name: "coinsquare"),
|
||||
(DisplayName: "Exmoney", Name: "exmoney"),
|
||||
(DisplayName: "Coinegg", Name: "coinegg"),
|
||||
(DisplayName: "FYB-SG", Name: "fybsg"),
|
||||
(DisplayName: "Cryptonit", Name: "cryptonit"),
|
||||
(DisplayName: "BTCTurk", Name: "btcturk"),
|
||||
(DisplayName: "bitFlyer", Name: "bitflyer"),
|
||||
(DisplayName: "Negocie Coins", Name: "negociecoins"),
|
||||
(DisplayName: "OasisDEX", Name: "oasisdex"),
|
||||
(DisplayName: "CoinMate", Name: "coinmate"),
|
||||
(DisplayName: "BitForex", Name: "bitforex"),
|
||||
(DisplayName: "Bitsquare", Name: "bitsquare"),
|
||||
(DisplayName: "FYB-SE", Name: "fybse"),
|
||||
(DisplayName: "itBit", Name: "itbit"),
|
||||
})
|
||||
{
|
||||
AvailableExchanges.TryAdd(item.Name, new CoinAverageExchange(item.Name, item.DisplayName));
|
||||
AvailableExchanges.TryAdd(item.Name, new CoinAverageExchange(item.Name, item.DisplayName, $"https://apiv2.bitcoinaverage.com/exchanges/{item.Name}"));
|
||||
}
|
||||
// Keep back-compat
|
||||
AvailableExchanges.Add(new CoinAverageExchange("gdax", string.Empty, $"https://apiv2.bitcoinaverage.com/exchanges/coinbasepro"));
|
||||
}
|
||||
|
||||
public Task AddHeader(HttpRequestMessage message)
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using ExchangeSharp;
|
||||
@ -31,14 +32,16 @@ namespace BTCPayServer.Services.Rates
|
||||
|
||||
public string ExchangeName => _ExchangeName;
|
||||
|
||||
public async Task<ExchangeRates> GetRatesAsync()
|
||||
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await new SynchronizationContextRemover();
|
||||
var rates = await _ExchangeAPI.GetTickersAsync();
|
||||
lock (notFoundSymbols)
|
||||
{
|
||||
var exchangeRates =
|
||||
rates.Select(t => CreateExchangeRate(t))
|
||||
rates
|
||||
.Where(t => t.Value.Ask != 0m && t.Value.Bid != 0m)
|
||||
.Select(t => CreateExchangeRate(t))
|
||||
.Where(t => t != null)
|
||||
.ToArray();
|
||||
return new ExchangeRates(exchangeRates);
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
|
||||
@ -16,13 +17,17 @@ namespace BTCPayServer.Services.Rates
|
||||
_Providers = providers;
|
||||
}
|
||||
|
||||
public async Task<ExchangeRates> GetRatesAsync()
|
||||
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (var p in _Providers)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await p.GetRatesAsync().ConfigureAwait(false);
|
||||
return await p.GetRatesAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch when (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch(Exception ex) { Exceptions.Add(ex); }
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
|
||||
@ -8,6 +9,6 @@ namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
public interface IRateProvider
|
||||
{
|
||||
Task<ExchangeRates> GetRatesAsync();
|
||||
Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using ExchangeSharp;
|
||||
@ -28,7 +29,7 @@ namespace BTCPayServer.Services.Rates
|
||||
}
|
||||
set
|
||||
{
|
||||
_LocalClient = null;
|
||||
_LocalClient = value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +39,37 @@ namespace BTCPayServer.Services.Rates
|
||||
static HttpClient _Client = new HttpClient();
|
||||
|
||||
// ExchangeSymbolToGlobalSymbol throws exception which would kill perf
|
||||
ConcurrentDictionary<string, string> notFoundSymbols = new ConcurrentDictionary<string, string>();
|
||||
ConcurrentDictionary<string, string> notFoundSymbols = new ConcurrentDictionary<string, string>(new Dictionary<string, string>()
|
||||
{
|
||||
{"ADAXBT","ADAXBT"},
|
||||
{ "BSVUSD","BSVUSD"},
|
||||
{ "QTUMEUR","QTUMEUR"},
|
||||
{ "QTUMXBT","QTUMXBT"},
|
||||
{ "EOSUSD","EOSUSD"},
|
||||
{ "XTZUSD","XTZUSD"},
|
||||
{ "XREPZUSD","XREPZUSD"},
|
||||
{ "ADAEUR","ADAEUR"},
|
||||
{ "ADAUSD","ADAUSD"},
|
||||
{ "GNOEUR","GNOEUR"},
|
||||
{ "XTZETH","XTZETH"},
|
||||
{ "XXRPZJPY","XXRPZJPY"},
|
||||
{ "XXRPZCAD","XXRPZCAD"},
|
||||
{ "XTZEUR","XTZEUR"},
|
||||
{ "QTUMETH","QTUMETH"},
|
||||
{ "XXLMZUSD","XXLMZUSD"},
|
||||
{ "QTUMCAD","QTUMCAD"},
|
||||
{ "QTUMUSD","QTUMUSD"},
|
||||
{ "XTZXBT","XTZXBT"},
|
||||
{ "GNOUSD","GNOUSD"},
|
||||
{ "ADAETH","ADAETH"},
|
||||
{ "ADACAD","ADACAD"},
|
||||
{ "XTZCAD","XTZCAD"},
|
||||
{ "BSVEUR","BSVEUR"},
|
||||
{ "XZECZJPY","XZECZJPY"},
|
||||
{ "XXLMZEUR","XXLMZEUR"},
|
||||
{"EOSEUR","EOSEUR"},
|
||||
{"BSVXBT","BSVXBT"}
|
||||
});
|
||||
string[] _Symbols = Array.Empty<string>();
|
||||
DateTimeOffset? _LastSymbolUpdate = null;
|
||||
|
||||
@ -55,7 +86,7 @@ namespace BTCPayServer.Services.Rates
|
||||
{ "ZCAD", "CAD" },
|
||||
};
|
||||
|
||||
public async Task<ExchangeRates> GetRatesAsync()
|
||||
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new ExchangeRates();
|
||||
var symbols = await GetSymbolsAsync();
|
||||
@ -135,7 +166,7 @@ namespace BTCPayServer.Services.Rates
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<T> MakeJsonRequestAsync<T>(string url, string baseUrl = null, Dictionary<string, object> payload = null, string requestMethod = null)
|
||||
private async Task<T> MakeJsonRequestAsync<T>(string url, string baseUrl = null, Dictionary<string, object> payload = null, string requestMethod = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("https://api.kraken.com");
|
||||
@ -147,7 +178,7 @@ namespace BTCPayServer.Services.Rates
|
||||
sb.Append(String.Join('&', payload.Select(kv => $"{kv.Key}={kv.Value}").OfType<object>().ToArray()));
|
||||
}
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, sb.ToString());
|
||||
var response = await HttpClient.SendAsync(request);
|
||||
var response = await HttpClient.SendAsync(request, cancellationToken);
|
||||
string stringResult = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<T>(stringResult);
|
||||
if (result is JToken json)
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
|
||||
@ -20,7 +21,7 @@ namespace BTCPayServer.Services.Rates
|
||||
return _Instance;
|
||||
}
|
||||
}
|
||||
public Task<ExchangeRates> GetRatesAsync()
|
||||
public Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new ExchangeRates());
|
||||
}
|
@ -3,6 +3,7 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using ExchangeSharp;
|
||||
@ -38,12 +39,12 @@ namespace BTCPayServer.Services.Rates
|
||||
|
||||
public RateProviderFactory RateProviderFactory => _rateProviderFactory;
|
||||
|
||||
public async Task<RateResult> FetchRate(CurrencyPair pair, RateRules rules)
|
||||
public async Task<RateResult> FetchRate(CurrencyPair pair, RateRules rules, CancellationToken cancellationToken)
|
||||
{
|
||||
return await FetchRates(new HashSet<CurrencyPair>(new[] { pair }), rules).First().Value;
|
||||
return await FetchRates(new HashSet<CurrencyPair>(new[] { pair }), rules, cancellationToken).First().Value;
|
||||
}
|
||||
|
||||
public Dictionary<CurrencyPair, Task<RateResult>> FetchRates(HashSet<CurrencyPair> pairs, RateRules rules)
|
||||
public Dictionary<CurrencyPair, Task<RateResult>> FetchRates(HashSet<CurrencyPair> pairs, RateRules rules, CancellationToken cancellationToken)
|
||||
{
|
||||
if (rules == null)
|
||||
throw new ArgumentNullException(nameof(rules));
|
||||
@ -59,7 +60,7 @@ namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
if (!fetchingExchanges.TryGetValue(requiredExchange.Exchange, out var fetching))
|
||||
{
|
||||
fetching = _rateProviderFactory.QueryRates(requiredExchange.Exchange);
|
||||
fetching = _rateProviderFactory.QueryRates(requiredExchange.Exchange, cancellationToken);
|
||||
fetchingExchanges.Add(requiredExchange.Exchange, fetching);
|
||||
}
|
||||
dependentQueries.Add(fetching);
|
@ -2,10 +2,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using ExchangeSharp;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace BTCPayServer.Services.Rates
|
||||
@ -21,12 +23,12 @@ namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
_inner = inner;
|
||||
}
|
||||
public async Task<ExchangeRates> GetRatesAsync()
|
||||
public async Task<ExchangeRates> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
DateTimeOffset now = DateTimeOffset.UtcNow;
|
||||
try
|
||||
{
|
||||
return await _inner.GetRatesAsync();
|
||||
return await _inner.GetRatesAsync(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -104,15 +106,17 @@ namespace BTCPayServer.Services.Rates
|
||||
Providers.Add("hitbtc", new ExchangeSharpRateProvider("hitbtc", new ExchangeHitbtcAPI(), false));
|
||||
|
||||
// Cryptopia is often not available
|
||||
Providers.Add("cryptopia", new ExchangeSharpRateProvider("cryptopia", new ExchangeCryptopiaAPI(), false));
|
||||
// Disabled because of https://twitter.com/Cryptopia_NZ/status/1085084168852291586
|
||||
// Providers.Add("cryptopia", new ExchangeSharpRateProvider("cryptopia", new ExchangeCryptopiaAPI(), false));
|
||||
|
||||
// Handmade providers
|
||||
Providers.Add(QuadrigacxRateProvider.QuadrigacxName, new QuadrigacxRateProvider());
|
||||
Providers.Add(CoinAverageRateProvider.CoinAverageName, new CoinAverageRateProvider() { Exchange = CoinAverageRateProvider.CoinAverageName, HttpClient = _httpClientFactory?.CreateClient(), Authenticator = _CoinAverageSettings });
|
||||
Providers.Add("kraken", new KrakenExchangeRateProvider() { HttpClient = _httpClientFactory?.CreateClient() });
|
||||
Providers.Add(CoinAverageRateProvider.CoinAverageName, new CoinAverageRateProvider() { Exchange = CoinAverageRateProvider.CoinAverageName, HttpClient = _httpClientFactory?.CreateClient("EXCHANGE_COINAVERAGE"), Authenticator = _CoinAverageSettings });
|
||||
Providers.Add("kraken", new KrakenExchangeRateProvider() { HttpClient = _httpClientFactory?.CreateClient("EXCHANGE_KRAKEN") });
|
||||
Providers.Add("bylls", new ByllsRateProvider(_httpClientFactory?.CreateClient("EXCHANGE_BYLLS")));
|
||||
Providers.Add("bitbank", new BitbankRateProvider(_httpClientFactory?.CreateClient("EXCHANGE_BITBANK")));
|
||||
Providers.Add("bitpay", new BitpayRateProvider(_httpClientFactory?.CreateClient("EXCHANGE_BITPAY")));
|
||||
|
||||
// Those exchanges make multiple requests when calling GetTickers so we remove them
|
||||
//DirectProviders.Add("gdax", new ExchangeSharpRateProvider("gdax", new ExchangeGdaxAPI()));
|
||||
//DirectProviders.Add("gemini", new ExchangeSharpRateProvider("gemini", new ExchangeGeminiAPI()));
|
||||
//DirectProviders.Add("bitfinex", new ExchangeSharpRateProvider("bitfinex", new ExchangeBitfinexAPI()));
|
||||
//DirectProviders.Add("okex", new ExchangeSharpRateProvider("okex", new ExchangeOkexAPI()));
|
||||
@ -165,19 +169,20 @@ namespace BTCPayServer.Services.Rates
|
||||
}
|
||||
|
||||
// Add other exchanges supported here
|
||||
exchanges.Add(new CoinAverageExchange(CoinAverageRateProvider.CoinAverageName, "Coin Average"));
|
||||
exchanges.Add(new CoinAverageExchange("cryptopia", "Cryptopia"));
|
||||
exchanges.Add(new CoinAverageExchange(CoinAverageRateProvider.CoinAverageName, "Coin Average", $"https://apiv2.bitcoinaverage.com/indices/global/ticker/short"));
|
||||
exchanges.Add(new CoinAverageExchange("bylls", "Bylls", "https://bylls.com/api/price?from_currency=BTC&to_currency=CAD"));
|
||||
exchanges.Add(new CoinAverageExchange("bitbank", "Bitbank", "https://public.bitbank.cc/prices"));
|
||||
|
||||
return exchanges;
|
||||
}
|
||||
|
||||
public async Task<QueryRateResult> QueryRates(string exchangeName)
|
||||
public async Task<QueryRateResult> QueryRates(string exchangeName, CancellationToken cancellationToken)
|
||||
{
|
||||
Providers.TryGetValue(exchangeName, out var directProvider);
|
||||
directProvider = directProvider ?? NullRateProvider.Instance;
|
||||
|
||||
var wrapper = new WrapperRateProvider(directProvider);
|
||||
var value = await wrapper.GetRatesAsync();
|
||||
var value = await wrapper.GetRatesAsync(cancellationToken);
|
||||
return new QueryRateResult()
|
||||
{
|
||||
Latency = wrapper.Latency,
|
385
BTCPayServer.Tests/AuthenticationTests.cs
Normal file
385
BTCPayServer.Tests/AuthenticationTests.cs
Normal file
@ -0,0 +1,385 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using AspNet.Security.OpenIdConnect.Primitives;
|
||||
using BTCPayServer.Tests.Logging;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using BTCPayServer.Data;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OpenIddict.Abstractions;
|
||||
using OpenQA.Selenium;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
public class AuthenticationTests
|
||||
{
|
||||
public AuthenticationTests(ITestOutputHelper helper)
|
||||
{
|
||||
Logs.Tester = new XUnitLog(helper) {Name = "Tests"};
|
||||
Logs.LogProvider = new XUnitLogProvider(helper);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task GetRedirectedToLoginPathOnChallenge()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var client = tester.PayTester.HttpClient;
|
||||
//Wallets endpoint is protected
|
||||
var response = await client.GetAsync("wallets");
|
||||
var urlPath = response.RequestMessage.RequestUri.ToString()
|
||||
.Replace(tester.PayTester.ServerUri.ToString(), "");
|
||||
//Cookie Challenge redirects you to login page
|
||||
Assert.StartsWith("Account/Login", urlPath, StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
var queryString = response.RequestMessage.RequestUri.ParseQueryString();
|
||||
|
||||
Assert.NotNull(queryString["ReturnUrl"]);
|
||||
Assert.Equal("/wallets", queryString["ReturnUrl"]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanGetOpenIdConfiguration()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
using (var response =
|
||||
await tester.PayTester.HttpClient.GetAsync("/.well-known/openid-configuration"))
|
||||
{
|
||||
using (var streamToReadFrom = new StreamReader(await response.Content.ReadAsStreamAsync()))
|
||||
{
|
||||
var json = await streamToReadFrom.ReadToEndAsync();
|
||||
Assert.NotNull(json);
|
||||
var configuration = OpenIdConnectConfiguration.Create(json);
|
||||
Assert.NotNull(configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanUseNonInteractiveFlows()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
var token = await RegisterPasswordClientAndGetAccessToken(user, null, tester);
|
||||
await TestApiAgainstAccessToken(token, tester, user);
|
||||
token = await RegisterPasswordClientAndGetAccessToken(user, "secret", tester);
|
||||
await TestApiAgainstAccessToken(token, tester, user);
|
||||
token = await RegisterClientCredentialsFlowAndGetAccessToken(user, "secret", tester);
|
||||
await TestApiAgainstAccessToken(token, tester, user);
|
||||
}
|
||||
}
|
||||
|
||||
[Trait("Selenium", "Selenium")]
|
||||
[Fact]
|
||||
public async Task CanUseImplicitFlow()
|
||||
{
|
||||
using (var s = SeleniumTester.Create())
|
||||
{
|
||||
s.Start();
|
||||
var tester = s.Server;
|
||||
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
var id = Guid.NewGuid().ToString();
|
||||
var redirecturi = new Uri("http://127.0.0.1/oidc-callback");
|
||||
var openIdClient = await user.RegisterOpenIdClient(
|
||||
new OpenIddictApplicationDescriptor()
|
||||
{
|
||||
ClientId = id,
|
||||
DisplayName = id,
|
||||
Permissions = {OpenIddictConstants.Permissions.GrantTypes.Implicit},
|
||||
RedirectUris = {redirecturi}
|
||||
});
|
||||
var implicitAuthorizeUrl = new Uri(tester.PayTester.ServerUri,
|
||||
$"connect/authorize?response_type=token&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid&nonce={Guid.NewGuid().ToString()}");
|
||||
s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl);
|
||||
s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
|
||||
s.Driver.FindElement(By.Id("consent-yes")).Click();
|
||||
var url = s.Driver.Url;
|
||||
var results = url.Split("#").Last().Split("&")
|
||||
.ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
|
||||
await TestApiAgainstAccessToken(results["access_token"], tester, user);
|
||||
//in Implicit mode, you renew your token by hitting the same endpoint but adding prompt=none. If you are still logged in on the site, you will receive a fresh token.
|
||||
var implicitAuthorizeUrlSilentModel = new Uri($"{implicitAuthorizeUrl.OriginalString}&prompt=none");
|
||||
s.Driver.Navigate().GoToUrl(implicitAuthorizeUrlSilentModel);
|
||||
url = s.Driver.Url;
|
||||
results = url.Split("#").Last().Split("&").ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
|
||||
await TestApiAgainstAccessToken(results["access_token"], tester, user);
|
||||
|
||||
LogoutFlow(tester, id, s);
|
||||
|
||||
s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl);
|
||||
s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
|
||||
|
||||
Assert.Throws<NoSuchElementException>(() => s.Driver.FindElement(By.Id("consent-yes")));
|
||||
results = url.Split("#").Last().Split("&")
|
||||
.ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
|
||||
await TestApiAgainstAccessToken(results["access_token"], tester, user);
|
||||
}
|
||||
}
|
||||
|
||||
void LogoutFlow(ServerTester tester, string clientId, SeleniumTester seleniumTester)
|
||||
{
|
||||
var logoutUrl = new Uri(tester.PayTester.ServerUri,
|
||||
$"connect/logout?response_type=token&client_id={clientId}");
|
||||
seleniumTester.Driver.Navigate().GoToUrl(logoutUrl);
|
||||
seleniumTester.GoToHome();
|
||||
Assert.Throws<NoSuchElementException>(() => seleniumTester.Driver.FindElement(By.Id("Logout")));
|
||||
|
||||
}
|
||||
|
||||
[Trait("Selenium", "Selenium")]
|
||||
[Fact]
|
||||
public async Task CanUseCodeFlow()
|
||||
{
|
||||
using (var s = SeleniumTester.Create())
|
||||
{
|
||||
s.Start();
|
||||
var tester = s.Server;
|
||||
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
var id = Guid.NewGuid().ToString();
|
||||
var redirecturi = new Uri("http://127.0.0.1/oidc-callback");
|
||||
var secret = "secret";
|
||||
var openIdClient = await user.RegisterOpenIdClient(
|
||||
new OpenIddictApplicationDescriptor()
|
||||
{
|
||||
ClientId = id,
|
||||
DisplayName = id,
|
||||
Permissions =
|
||||
{
|
||||
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
|
||||
OpenIddictConstants.Permissions.GrantTypes.RefreshToken
|
||||
},
|
||||
RedirectUris = {redirecturi}
|
||||
}, secret);
|
||||
var authorizeUrl = new Uri(tester.PayTester.ServerUri,
|
||||
$"connect/authorize?response_type=code&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid offline_access&state={Guid.NewGuid().ToString()}");
|
||||
s.Driver.Navigate().GoToUrl(authorizeUrl);
|
||||
s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
|
||||
s.Driver.FindElement(By.Id("consent-yes")).Click();
|
||||
var url = s.Driver.Url;
|
||||
var results = url.Split("?").Last().Split("&")
|
||||
.ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
|
||||
|
||||
var httpClient = tester.PayTester.HttpClient;
|
||||
|
||||
var httpRequest = new HttpRequestMessage(HttpMethod.Post,
|
||||
new Uri(tester.PayTester.ServerUri, "/connect/token"))
|
||||
{
|
||||
Content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>()
|
||||
{
|
||||
new KeyValuePair<string, string>("grant_type",
|
||||
OpenIddictConstants.GrantTypes.AuthorizationCode),
|
||||
new KeyValuePair<string, string>("client_id", openIdClient.ClientId),
|
||||
new KeyValuePair<string, string>("client_secret", secret),
|
||||
new KeyValuePair<string, string>("code", results["code"]),
|
||||
new KeyValuePair<string, string>("redirect_uri", redirecturi.AbsoluteUri)
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
var response = await httpClient.SendAsync(httpRequest);
|
||||
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
var result = JObject.Parse(content).ToObject<OpenIdConnectResponse>();
|
||||
|
||||
await TestApiAgainstAccessToken(result.AccessToken, tester, user);
|
||||
|
||||
var refreshedAccessToken = await RefreshAnAccessToken(result.RefreshToken, httpClient, id, secret);
|
||||
|
||||
await TestApiAgainstAccessToken(refreshedAccessToken, tester, user);
|
||||
|
||||
LogoutFlow(tester, id, s);
|
||||
s.Driver.Navigate().GoToUrl(authorizeUrl);
|
||||
s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
|
||||
|
||||
Assert.Throws<NoSuchElementException>(() => s.Driver.FindElement(By.Id("consent-yes")));
|
||||
results = url.Split("?").Last().Split("&")
|
||||
.ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]);
|
||||
Assert.True(results.ContainsKey("code"));
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<string> RefreshAnAccessToken(string refreshToken, HttpClient client, string clientId,
|
||||
string clientSecret = null)
|
||||
{
|
||||
var httpRequest = new HttpRequestMessage(HttpMethod.Post,
|
||||
new Uri(client.BaseAddress, "/connect/token"))
|
||||
{
|
||||
Content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>()
|
||||
{
|
||||
new KeyValuePair<string, string>("grant_type",
|
||||
OpenIddictConstants.GrantTypes.RefreshToken),
|
||||
new KeyValuePair<string, string>("client_id", clientId),
|
||||
new KeyValuePair<string, string>("client_secret", clientSecret),
|
||||
new KeyValuePair<string, string>("refresh_token", refreshToken)
|
||||
})
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(httpRequest);
|
||||
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
var result = JObject.Parse(content).ToObject<OpenIdConnectResponse>();
|
||||
Assert.NotEmpty(result.AccessToken);
|
||||
Assert.Null(result.Error);
|
||||
return result.AccessToken;
|
||||
}
|
||||
|
||||
private static async Task<string> RegisterClientCredentialsFlowAndGetAccessToken(TestAccount user,
|
||||
string secret,
|
||||
ServerTester tester)
|
||||
{
|
||||
var id = Guid.NewGuid().ToString();
|
||||
var openIdClient = await user.RegisterOpenIdClient(
|
||||
new OpenIddictApplicationDescriptor()
|
||||
{
|
||||
ClientId = id,
|
||||
DisplayName = id,
|
||||
Permissions = {OpenIddictConstants.Permissions.GrantTypes.ClientCredentials}
|
||||
}, secret);
|
||||
|
||||
|
||||
var httpClient = tester.PayTester.HttpClient;
|
||||
|
||||
var httpRequest = new HttpRequestMessage(HttpMethod.Post,
|
||||
new Uri(tester.PayTester.ServerUri, "/connect/token"))
|
||||
{
|
||||
Content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>()
|
||||
{
|
||||
new KeyValuePair<string, string>("grant_type",
|
||||
OpenIddictConstants.GrantTypes.ClientCredentials),
|
||||
new KeyValuePair<string, string>("client_id", openIdClient.ClientId),
|
||||
new KeyValuePair<string, string>("client_secret", secret)
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
var response = await httpClient.SendAsync(httpRequest);
|
||||
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
var result = JObject.Parse(content).ToObject<OpenIdConnectResponse>();
|
||||
Assert.NotEmpty(result.AccessToken);
|
||||
Assert.Null(result.Error);
|
||||
return result.AccessToken;
|
||||
}
|
||||
|
||||
private static async Task<string> RegisterPasswordClientAndGetAccessToken(TestAccount user, string secret,
|
||||
ServerTester tester)
|
||||
{
|
||||
var id = Guid.NewGuid().ToString();
|
||||
var openIdClient = await user.RegisterOpenIdClient(
|
||||
new OpenIddictApplicationDescriptor()
|
||||
{
|
||||
ClientId = id,
|
||||
DisplayName = id,
|
||||
Permissions = {OpenIddictConstants.Permissions.GrantTypes.Password}
|
||||
}, secret);
|
||||
|
||||
|
||||
var httpClient = tester.PayTester.HttpClient;
|
||||
|
||||
var httpRequest = new HttpRequestMessage(HttpMethod.Post,
|
||||
new Uri(tester.PayTester.ServerUri, "/connect/token"))
|
||||
{
|
||||
Content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>()
|
||||
{
|
||||
new KeyValuePair<string, string>("grant_type", OpenIddictConstants.GrantTypes.Password),
|
||||
new KeyValuePair<string, string>("username", user.RegisterDetails.Email),
|
||||
new KeyValuePair<string, string>("password", user.RegisterDetails.Password),
|
||||
new KeyValuePair<string, string>("client_id", openIdClient.ClientId),
|
||||
new KeyValuePair<string, string>("client_secret", secret)
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
var response = await httpClient.SendAsync(httpRequest);
|
||||
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
var result = JObject.Parse(content).ToObject<OpenIdConnectResponse>();
|
||||
Assert.NotEmpty(result.AccessToken);
|
||||
Assert.Null(result.Error);
|
||||
return result.AccessToken;
|
||||
}
|
||||
|
||||
async Task TestApiAgainstAccessToken(string accessToken, ServerTester tester, TestAccount testAccount)
|
||||
{
|
||||
var resultUser =
|
||||
await TestApiAgainstAccessToken<string>(accessToken, "api/test/me/id",
|
||||
tester.PayTester.HttpClient);
|
||||
Assert.Equal(testAccount.UserId, resultUser);
|
||||
|
||||
var secondUser = tester.NewAccount();
|
||||
secondUser.GrantAccess();
|
||||
|
||||
var resultStores =
|
||||
await TestApiAgainstAccessToken<StoreData[]>(accessToken, "api/test/me/stores",
|
||||
tester.PayTester.HttpClient);
|
||||
Assert.Contains(resultStores,
|
||||
data => data.Id.Equals(testAccount.StoreId, StringComparison.InvariantCultureIgnoreCase));
|
||||
Assert.DoesNotContain(resultStores,
|
||||
data => data.Id.Equals(secondUser.StoreId, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
Assert.True(await TestApiAgainstAccessToken<bool>(accessToken,
|
||||
$"api/test/me/stores/{testAccount.StoreId}/can-edit",
|
||||
tester.PayTester.HttpClient));
|
||||
|
||||
|
||||
Assert.Equal(testAccount.RegisterDetails.IsAdmin, await TestApiAgainstAccessToken<bool>(accessToken,
|
||||
$"api/test/me/is-admin",
|
||||
tester.PayTester.HttpClient));
|
||||
|
||||
await Assert.ThrowsAnyAsync<HttpRequestException>(async () =>
|
||||
{
|
||||
await TestApiAgainstAccessToken<bool>(accessToken, $"api/test/me/stores/{secondUser.StoreId}/can-edit",
|
||||
tester.PayTester.HttpClient);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<T> TestApiAgainstAccessToken<T>(string accessToken, string url, HttpClient client)
|
||||
{
|
||||
var httpRequest = new HttpRequestMessage(HttpMethod.Get,
|
||||
new Uri(client.BaseAddress, url));
|
||||
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
|
||||
var result = await client.SendAsync(httpRequest);
|
||||
result.EnsureSuccessStatusCode();
|
||||
|
||||
var rawJson = await result.Content.ReadAsStringAsync();
|
||||
if (typeof(T).IsPrimitive || typeof(T) == typeof(string))
|
||||
{
|
||||
return (T)Convert.ChangeType(rawJson, typeof(T));
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<T>(rawJson);
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
|
||||
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="76.0.3809.6801" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@ -31,6 +33,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BTCPayServer.Rating\BTCPayServer.Rating.csproj" />
|
||||
<ProjectReference Include="..\BTCPayServer\BTCPayServer.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,4 +1,4 @@
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Configuration;
|
||||
using System.Linq;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Hosting;
|
||||
@ -33,7 +33,12 @@ using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using AspNet.Security.OpenIdConnect.Primitives;
|
||||
using Xunit;
|
||||
using BTCPayServer.Services;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
@ -100,15 +105,18 @@ namespace BTCPayServer.Tests
|
||||
|
||||
StringBuilder config = new StringBuilder();
|
||||
config.AppendLine($"{chain.ToLowerInvariant()}=1");
|
||||
if (InContainer)
|
||||
{
|
||||
config.AppendLine($"bind=0.0.0.0");
|
||||
}
|
||||
config.AppendLine($"port={Port}");
|
||||
config.AppendLine($"chains=btc,ltc");
|
||||
|
||||
config.AppendLine($"btc.explorer.url={NBXplorerUri.AbsoluteUri}");
|
||||
config.AppendLine($"btc.explorer.cookiefile=0");
|
||||
|
||||
config.AppendLine("allow-admin-registration=1");
|
||||
config.AppendLine($"ltc.explorer.url={LTCNBXplorerUri.AbsoluteUri}");
|
||||
config.AppendLine($"ltc.explorer.cookiefile=0");
|
||||
|
||||
config.AppendLine($"btc.lightning={IntegratedLightning.AbsoluteUri}");
|
||||
|
||||
if (TestDatabase == TestDatabases.MySQL && !String.IsNullOrEmpty(MySQL))
|
||||
@ -119,15 +127,18 @@ namespace BTCPayServer.Tests
|
||||
File.WriteAllText(confPath, config.ToString());
|
||||
|
||||
ServerUri = new Uri("http://" + HostName + ":" + Port + "/");
|
||||
|
||||
HttpClient = new HttpClient();
|
||||
HttpClient.BaseAddress = ServerUri;
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
|
||||
var conf = new DefaultConfiguration() { Logger = Logs.LogProvider.CreateLogger("Console") }.CreateConfiguration(new[] { "--datadir", _Directory, "--conf", confPath });
|
||||
var conf = new DefaultConfiguration() { Logger = Logs.LogProvider.CreateLogger("Console") }.CreateConfiguration(new[] { "--datadir", _Directory, "--conf", confPath, "--disable-registration", "false" });
|
||||
_Host = new WebHostBuilder()
|
||||
.UseConfiguration(conf)
|
||||
.UseContentRoot(FindBTCPayServerDirectory())
|
||||
.ConfigureServices(s =>
|
||||
{
|
||||
s.AddLogging(l =>
|
||||
{
|
||||
l.AddFilter("System.Net.Http.HttpClient", LogLevel.Critical);
|
||||
l.SetMinimumLevel(LogLevel.Information)
|
||||
.AddFilter("Microsoft", LogLevel.Error)
|
||||
.AddFilter("Hangfire", LogLevel.Error)
|
||||
@ -137,14 +148,18 @@ namespace BTCPayServer.Tests
|
||||
.UseKestrel()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
_Host.Start();
|
||||
_Host.StartWithTasksAsync().GetAwaiter().GetResult();
|
||||
|
||||
var urls = _Host.ServerFeatures.Get<IServerAddressesFeature>().Addresses;
|
||||
foreach (var url in urls)
|
||||
{
|
||||
Logs.Tester.LogInformation("Listening on " + url);
|
||||
}
|
||||
Logs.Tester.LogInformation("Server URI " + ServerUri);
|
||||
|
||||
InvoiceRepository = (InvoiceRepository)_Host.Services.GetService(typeof(InvoiceRepository));
|
||||
StoreRepository = (StoreRepository)_Host.Services.GetService(typeof(StoreRepository));
|
||||
var dashBoard = (NBXplorerDashboard)_Host.Services.GetService(typeof(NBXplorerDashboard));
|
||||
while(!dashBoard.IsFullySynched())
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
Networks = (BTCPayNetworkProvider)_Host.Services.GetService(typeof(BTCPayNetworkProvider));
|
||||
|
||||
if (MockRates)
|
||||
{
|
||||
@ -205,8 +220,50 @@ namespace BTCPayServer.Tests
|
||||
});
|
||||
rateProvider.Providers.Add("bittrex", bittrex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
WaitSiteIsOperational().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private async Task WaitSiteIsOperational()
|
||||
{
|
||||
using (var cts = new CancellationTokenSource(10_000))
|
||||
{
|
||||
var synching = WaitIsFullySynched(cts.Token);
|
||||
var accessingHomepage = WaitCanAccessHomepage(cts.Token);
|
||||
await Task.WhenAll(synching, accessingHomepage).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task WaitCanAccessHomepage(CancellationToken cancellationToken)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var resp = await HttpClient.GetAsync("/", cancellationToken).ConfigureAwait(false);
|
||||
if (resp.StatusCode == HttpStatusCode.OK)
|
||||
break;
|
||||
await Task.Delay(10, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task WaitIsFullySynched(CancellationToken cancellationToken)
|
||||
{
|
||||
var dashBoard = GetService<NBXplorerDashboard>();
|
||||
while (!dashBoard.IsFullySynched())
|
||||
{
|
||||
await Task.Delay(10, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private string FindBTCPayServerDirectory()
|
||||
{
|
||||
var solutionDirectory = LanguageService.TryGetSolutionDirectoryInfo(Directory.GetCurrentDirectory());
|
||||
return Path.Combine(solutionDirectory.FullName, "BTCPayServer");
|
||||
}
|
||||
|
||||
public HttpClient HttpClient { get; set; }
|
||||
|
||||
public string HostName
|
||||
{
|
||||
get;
|
||||
@ -214,6 +271,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
public InvoiceRepository InvoiceRepository { get; private set; }
|
||||
public StoreRepository StoreRepository { get; private set; }
|
||||
public BTCPayNetworkProvider Networks { get; private set; }
|
||||
public Uri IntegratedLightning { get; internal set; }
|
||||
public bool InContainer { get; internal set; }
|
||||
|
||||
@ -222,6 +280,8 @@ namespace BTCPayServer.Tests
|
||||
return _Host.Services.GetRequiredService<T>();
|
||||
}
|
||||
|
||||
public IServiceProvider ServiceProvider => _Host.Services;
|
||||
|
||||
public T GetController<T>(string userId = null, string storeId = null, Claim[] additionalClaims = null) where T : Controller
|
||||
{
|
||||
var context = new DefaultHttpContext();
|
||||
@ -231,7 +291,7 @@ namespace BTCPayServer.Tests
|
||||
if (userId != null)
|
||||
{
|
||||
List<Claim> claims = new List<Claim>();
|
||||
claims.Add(new Claim(ClaimTypes.NameIdentifier, userId));
|
||||
claims.Add(new Claim(OpenIdConnectConstants.Claims.Subject, userId));
|
||||
if (additionalClaims != null)
|
||||
claims.AddRange(additionalClaims);
|
||||
context.User = new ClaimsPrincipal(new ClaimsIdentity(claims.ToArray(), Policies.CookieAuthentication));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user