mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-30 23:31:14 +03:00
Compare commits
2043 Commits
1.9.1
...
refactorin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74c55edc0c | ||
|
|
3458ed78d7 | ||
|
|
4bc571f609 | ||
|
|
758b25947c | ||
|
|
b036c38981 | ||
|
|
eab2b8e45a | ||
|
|
dfdec2bf4b | ||
|
|
843156cf1b | ||
|
|
01413e5a4c | ||
|
|
743304c359 | ||
|
|
6c5d590169 | ||
|
|
a1e68f5506 | ||
|
|
424315b17f | ||
|
|
8fefae0325 | ||
|
|
ede633ea03 | ||
|
|
b4469064a2 | ||
|
|
393e289784 | ||
|
|
d18423ee8c | ||
|
|
3fc9edd346 | ||
|
|
1a1f75d873 | ||
|
|
df02e0bf78 | ||
|
|
264d77463d | ||
|
|
0a37ffd5e3 | ||
|
|
1343d10aa7 | ||
|
|
6f96ebd8bf | ||
|
|
cb531dacb3 | ||
|
|
dfd0b4d0e5 | ||
|
|
f978f55e7f | ||
|
|
73516c28af | ||
|
|
dc85a99e08 | ||
|
|
ef06fcb4f4 | ||
|
|
ffe2314d47 | ||
|
|
4e970322d0 | ||
|
|
8dee0d27cf | ||
|
|
c520f9a2a4 | ||
|
|
003c3a23c4 | ||
|
|
1754a82f67 | ||
|
|
3384008277 | ||
|
|
af22115706 | ||
|
|
4b114fd3b6 | ||
|
|
9d531f5d74 | ||
|
|
a5564148f5 | ||
|
|
196f7778fc | ||
|
|
de20add857 | ||
|
|
c59216b58a | ||
|
|
acf7fa261a | ||
|
|
c3eddc92bd | ||
|
|
18c74f4b02 | ||
|
|
3f90ee915d | ||
|
|
401ad0db0e | ||
|
|
5945133d30 | ||
|
|
ff4fbde0b0 | ||
|
|
74ae4f3e67 | ||
|
|
ae4b33d042 | ||
|
|
53fa280037 | ||
|
|
8ecde90bc7 | ||
|
|
34a583f272 | ||
|
|
5de4b8eeb8 | ||
|
|
aae420e469 | ||
|
|
0612f70c06 | ||
|
|
d0c82efa1c | ||
|
|
cf8492240e | ||
|
|
2bceb9f7ba | ||
|
|
760f935965 | ||
|
|
eeeb2805c5 | ||
|
|
9a592d67ad | ||
|
|
ea6618b2f6 | ||
|
|
7b092e73ad | ||
|
|
b2e25c42c7 | ||
|
|
c8dd38ac31 | ||
|
|
563ee4703f | ||
|
|
beceed81de | ||
|
|
3bf96253db | ||
|
|
da2d0ec203 | ||
|
|
008b858203 | ||
|
|
130fc8277d | ||
|
|
468d3357b8 | ||
|
|
f1271da527 | ||
|
|
249a7c7ca3 | ||
|
|
0094d0ebc4 | ||
|
|
834b504dff | ||
|
|
a516d0e757 | ||
|
|
afdfbdbc59 | ||
|
|
ef712b7054 | ||
|
|
c22f9ff08a | ||
|
|
04fb1825d5 | ||
|
|
4f8f873682 | ||
|
|
9fe75c6120 | ||
|
|
bb7e8f46cb | ||
|
|
5db0c281ee | ||
|
|
aac9bfcea6 | ||
|
|
e6ee9085a2 | ||
|
|
d62ade58a5 | ||
|
|
d8020878d5 | ||
|
|
b027fff103 | ||
|
|
a0c06048cd | ||
|
|
53746f2f66 | ||
|
|
2649dba4ad | ||
|
|
6a1e3c07b1 | ||
|
|
a365eff76f | ||
|
|
8f9acd9367 | ||
|
|
53fdf5f70d | ||
|
|
9be13ea465 | ||
|
|
871aced1d1 | ||
|
|
2254bfc128 | ||
|
|
b71dcb8dd0 | ||
|
|
33d1518fd2 | ||
|
|
ee5344a4ea | ||
|
|
abb3c918e3 | ||
|
|
ff348a348c | ||
|
|
d67c378bff | ||
|
|
d85a0439c5 | ||
|
|
9faabe9e7d | ||
|
|
5bd8c33a6d | ||
|
|
24759c92ad | ||
|
|
9e92ee020e | ||
|
|
7a4f6b628b | ||
|
|
7e2f223d7f | ||
|
|
eb48e4b668 | ||
|
|
9ace09a604 | ||
|
|
702735c2ca | ||
|
|
174f2ac3db | ||
|
|
e3b5b4a9d9 | ||
|
|
72ba012765 | ||
|
|
0f9bbcd060 | ||
|
|
a9d038d8bf | ||
|
|
54a6845315 | ||
|
|
0c7059a476 | ||
|
|
5bed92ab0b | ||
|
|
49a14785c6 | ||
|
|
2c78c06dda | ||
|
|
cf8a0efd0d | ||
|
|
5211cdd4c0 | ||
|
|
d10aa43d8b | ||
|
|
6b0f1ed429 | ||
|
|
4bde1ccb44 | ||
|
|
03c18c44e2 | ||
|
|
72ffc7ce6a | ||
|
|
87b738ef16 | ||
|
|
b868831bcb | ||
|
|
477d7214c5 | ||
|
|
f3cd3d4f06 | ||
|
|
aea4cc2389 | ||
|
|
245aa8eb8c | ||
|
|
f14a2add0f | ||
|
|
89703ba58f | ||
|
|
23715fca8b | ||
|
|
d90685600e | ||
|
|
f007e5eb5c | ||
|
|
a8ccea00c7 | ||
|
|
cd2ee00769 | ||
|
|
c98a418807 | ||
|
|
0e4ae26bae | ||
|
|
d50e7dd3f4 | ||
|
|
f0085f52eb | ||
|
|
5c19b08e5e | ||
|
|
79edbe52a3 | ||
|
|
0dd181bb5b | ||
|
|
d8682003fa | ||
|
|
f4a2cf9984 | ||
|
|
98e6358fd3 | ||
|
|
af90065d2e | ||
|
|
f372f4074b | ||
|
|
6a2e5f83a1 | ||
|
|
a2badd46c4 | ||
|
|
8623a983b8 | ||
|
|
151e662027 | ||
|
|
f588fe29db | ||
|
|
030b0351a2 | ||
|
|
d4453a5f38 | ||
|
|
2252905596 | ||
|
|
ec650a65f7 | ||
|
|
6953f8d814 | ||
|
|
624a84cbfb | ||
|
|
506d9793e1 | ||
|
|
ef52f6ab08 | ||
|
|
5312a6e885 | ||
|
|
fdd600794e | ||
|
|
7bfbdca72a | ||
|
|
a22c08a41d | ||
|
|
10ea9b418a | ||
|
|
e39efb1d68 | ||
|
|
7db84122f9 | ||
|
|
84ad167ab4 | ||
|
|
ed7e217a6b | ||
|
|
c1b0d4a4a7 | ||
|
|
2f84e24353 | ||
|
|
f73586185b | ||
|
|
653ffb9a68 | ||
|
|
fe8c2d157a | ||
|
|
86367a1276 | ||
|
|
b0fcf92ada | ||
|
|
283b6ebf81 | ||
|
|
d0a7fc5116 | ||
|
|
9851aacba7 | ||
|
|
51f9fb9e0a | ||
|
|
0325761f3e | ||
|
|
a6ca1b12da | ||
|
|
82a9e7e27d | ||
|
|
f5301e1315 | ||
|
|
adab30fc81 | ||
|
|
e7bd24f065 | ||
|
|
2ec448ba13 | ||
|
|
c6e6f2ae84 | ||
|
|
e9468a4c2f | ||
|
|
45de951897 | ||
|
|
db8d966fac | ||
|
|
6b69bc9618 | ||
|
|
0089b0b799 | ||
|
|
e4841e809b | ||
|
|
ba4237f1dd | ||
|
|
f6acec53c0 | ||
|
|
5f631eaa76 | ||
|
|
7730dd510c | ||
|
|
30bd264f17 | ||
|
|
5206665fa0 | ||
|
|
073491ccb4 | ||
|
|
561b62cd40 | ||
|
|
1284ed4d84 | ||
|
|
6f34443191 | ||
|
|
02f186c54e | ||
|
|
784c6cf585 | ||
|
|
14f132e127 | ||
|
|
9cb624e681 | ||
|
|
516e3da7e2 | ||
|
|
0e83586cae | ||
|
|
95bdae68f4 | ||
|
|
294778884b | ||
|
|
10caecbffd | ||
|
|
553a6a73dd | ||
|
|
e646b85e56 | ||
|
|
b7c513c05f | ||
|
|
9f82b4c21f | ||
|
|
02b2da38cf | ||
|
|
f51077b2be | ||
|
|
33f49bfddb | ||
|
|
9a81f13f81 | ||
|
|
915fb6759a | ||
|
|
c5a5bfde69 | ||
|
|
0a90fd110d | ||
|
|
541d6eb0b8 | ||
|
|
d443a0063d | ||
|
|
f0c6edb670 | ||
|
|
9189b53a0d | ||
|
|
fceccaefcc | ||
|
|
fbeabf43ca | ||
|
|
78c7893f90 | ||
|
|
cb9a25006c | ||
|
|
0e87550d85 | ||
|
|
dceb0ab832 | ||
|
|
a33590476a | ||
|
|
deaf618520 | ||
|
|
3d8a56d922 | ||
|
|
36af7cf471 | ||
|
|
ebd3449b4a | ||
|
|
99182f4a67 | ||
|
|
da84ba1a4d | ||
|
|
bca68fc185 | ||
|
|
59a7265bac | ||
|
|
9201ca1e03 | ||
|
|
6b6a76d2cc | ||
|
|
840c388ab9 | ||
|
|
5b4ec608c8 | ||
|
|
79ff1b81e0 | ||
|
|
ea67c01da8 | ||
|
|
1137e169ea | ||
|
|
17748cca47 | ||
|
|
080e1d98c6 | ||
|
|
ca633ae882 | ||
|
|
bb7b64fb96 | ||
|
|
bf901631bf | ||
|
|
0c0ce54b1f | ||
|
|
ee762c4cef | ||
|
|
ed9efb5a79 | ||
|
|
73eb85f2f4 | ||
|
|
cd055cff62 | ||
|
|
f8b2cce618 | ||
|
|
e648054c7a | ||
|
|
fe558163cc | ||
|
|
3883b8ff34 | ||
|
|
d286664763 | ||
|
|
b05ad2392b | ||
|
|
6dbdb85aaf | ||
|
|
26b48cfe4f | ||
|
|
2f39136143 | ||
|
|
8d0d3c5ce9 | ||
|
|
256081e4ed | ||
|
|
1dd7b0a221 | ||
|
|
82c0b28906 | ||
|
|
985fe083f0 | ||
|
|
6a0000dc4b | ||
|
|
1dd2f38066 | ||
|
|
004e1e3ca5 | ||
|
|
7c560d709b | ||
|
|
d3743ad62f | ||
|
|
ac234b77e2 | ||
|
|
9886987e68 | ||
|
|
d34cb8898f | ||
|
|
13aadbda64 | ||
|
|
c7c7c8eb01 | ||
|
|
b1e5bba33f | ||
|
|
474e7c6d62 | ||
|
|
794ec921b8 | ||
|
|
b674240362 | ||
|
|
a768c7c451 | ||
|
|
28d2a4ec2c | ||
|
|
9f1210d18f | ||
|
|
3012559627 | ||
|
|
b3ed57aee7 | ||
|
|
89d0a8107d | ||
|
|
6c0b71bd1b | ||
|
|
61abf74b2d | ||
|
|
21fdf02921 | ||
|
|
7a245d80ee | ||
|
|
da85922f23 | ||
|
|
a5356b6319 | ||
|
|
3828891b9b | ||
|
|
15d866ce04 | ||
|
|
560eb3d620 | ||
|
|
ac894254cc | ||
|
|
17e3fbde25 | ||
|
|
ee11a8410c | ||
|
|
ff5c51cfd9 | ||
|
|
b3943ae5e3 | ||
|
|
a32952fde6 | ||
|
|
9c4ee4014d | ||
|
|
dc9069f1f4 | ||
|
|
e402cacc05 | ||
|
|
a98cd248d6 | ||
|
|
00fbfb6a01 | ||
|
|
86c31c3766 | ||
|
|
698cfe910c | ||
|
|
16db23c159 | ||
|
|
b05a5ee1c6 | ||
|
|
8cb298937f | ||
|
|
68fe20ddf6 | ||
|
|
fab167bb34 | ||
|
|
f640d4b5f5 | ||
|
|
074562b141 | ||
|
|
fd030a5fd4 | ||
|
|
82fa6b13c6 | ||
|
|
bf16298c40 | ||
|
|
bcebb0a2b5 | ||
|
|
b27442cf74 | ||
|
|
92fbbd4812 | ||
|
|
321ed810e3 | ||
|
|
17ff530683 | ||
|
|
2b413736a4 | ||
|
|
a416d03614 | ||
|
|
4de9a274dd | ||
|
|
0b8f3c9d9d | ||
|
|
f3a168fd43 | ||
|
|
158c11a0ec | ||
|
|
f2d13148a3 | ||
|
|
6c8b4e1fb2 | ||
|
|
c95dffff0c | ||
|
|
6346fc04ae | ||
|
|
3a87354f8d | ||
|
|
e0863a58aa | ||
|
|
dba05aab07 | ||
|
|
fec904fd28 | ||
|
|
db321bed5d | ||
|
|
28cc0218c5 | ||
|
|
a2d5f25b58 | ||
|
|
3100160927 | ||
|
|
1c3fdd3c72 | ||
|
|
0c13eda1f5 | ||
|
|
f37b7cec87 | ||
|
|
962c75b2ca | ||
|
|
9a62e2ae41 | ||
|
|
0f00dc4e7c | ||
|
|
0f04cf6eae | ||
|
|
dc76ad820f | ||
|
|
e0cde9f138 | ||
|
|
db1dc78e38 | ||
|
|
fd98ef1250 | ||
|
|
cdf46c968a | ||
|
|
72b20ef563 | ||
|
|
30a0ac0def | ||
|
|
090208bd2c | ||
|
|
1e5c9c9c4d | ||
|
|
5918f37ffa | ||
|
|
554e1b1b91 | ||
|
|
8f510c1431 | ||
|
|
4723019624 | ||
|
|
1be9078b6c | ||
|
|
520658a295 | ||
|
|
b9ec722abb | ||
|
|
d917c798d7 | ||
|
|
0d168c039f | ||
|
|
af8f265555 | ||
|
|
c0e0d64284 | ||
|
|
9466a71141 | ||
|
|
d28a586a97 | ||
|
|
6fde0b6663 | ||
|
|
d143b9213b | ||
|
|
16433e9e46 | ||
|
|
39479d1999 | ||
|
|
a03b766e33 | ||
|
|
7df2655ba0 | ||
|
|
5c2ca9803d | ||
|
|
4e6af947fa | ||
|
|
bc9d5c8fd6 | ||
|
|
f412ac6260 | ||
|
|
26d8dfbb7f | ||
|
|
b45517bafd | ||
|
|
3edb6755b4 | ||
|
|
bda64fa391 | ||
|
|
e7040f7cc8 | ||
|
|
229970e799 | ||
|
|
7b0a9a055f | ||
|
|
06d370f716 | ||
|
|
ce0a4f1f96 | ||
|
|
3240aa3cb3 | ||
|
|
5c5935c738 | ||
|
|
00b2b1abcd | ||
|
|
e0891e1a15 | ||
|
|
f7df621c56 | ||
|
|
0b6dc5bcfc | ||
|
|
cbd6755aa5 | ||
|
|
3afbc248b1 | ||
|
|
30af81fe0a | ||
|
|
427b43c99b | ||
|
|
ed08ac6b46 | ||
|
|
1a2c1fa1b5 | ||
|
|
709fbac231 | ||
|
|
6b80a56f92 | ||
|
|
5c9d45a8a8 | ||
|
|
2edac24945 | ||
|
|
b68c9cc145 | ||
|
|
6f02d4eb62 | ||
|
|
6e60688e70 | ||
|
|
140b5c4292 | ||
|
|
8ee2ebbd20 | ||
|
|
b3eda4106d | ||
|
|
885e22be7c | ||
|
|
83ec073734 | ||
|
|
0160b0f9dc | ||
|
|
f55bd5e1a1 | ||
|
|
4d88eb8e79 | ||
|
|
874de74ac8 | ||
|
|
b3a4b34d48 | ||
|
|
f7b9d2bae7 | ||
|
|
ec4574bfcf | ||
|
|
73cfab166f | ||
|
|
0e8f85057d | ||
|
|
2e4908c557 | ||
|
|
401784414a | ||
|
|
8495124bc8 | ||
|
|
ba6ed540f5 | ||
|
|
19a60ea856 | ||
|
|
aecf1b463c | ||
|
|
ff24ba1011 | ||
|
|
802b708232 | ||
|
|
adeff3efb9 | ||
|
|
0103c1722e | ||
|
|
f9123e7b71 | ||
|
|
0f9ed4e69c | ||
|
|
9dfc95bac0 | ||
|
|
9b7914538f | ||
|
|
85c9cd260d | ||
|
|
73751cc049 | ||
|
|
2b61c48303 | ||
|
|
47b03f2bf4 | ||
|
|
3e02dfef63 | ||
|
|
4176d0130a | ||
|
|
f6175c2c69 | ||
|
|
b8b423ca19 | ||
|
|
3702d69b9d | ||
|
|
3253de9384 | ||
|
|
51070635a5 | ||
|
|
9b533f1ba6 | ||
|
|
9371dd405e | ||
|
|
27d8108e55 | ||
|
|
820a3f0b77 | ||
|
|
3d61b20271 | ||
|
|
eec81f8124 | ||
|
|
d7fbddb97f | ||
|
|
9170cb0318 | ||
|
|
76dec6fa9c | ||
|
|
4e3edcfc0a | ||
|
|
ad21d7ab64 | ||
|
|
f576eb509d | ||
|
|
33e229d0b2 | ||
|
|
78420d617b | ||
|
|
2552e33d64 | ||
|
|
301141c755 | ||
|
|
fac57ac89a | ||
|
|
da5ad0a845 | ||
|
|
60aeefe1c2 | ||
|
|
d527f6a5ce | ||
|
|
2802b42747 | ||
|
|
66c5d2f0a8 | ||
|
|
6dbf4ac62c | ||
|
|
ae2872830b | ||
|
|
6f4a3587e4 | ||
|
|
145f51906e | ||
|
|
12e72bc74b | ||
|
|
65a04799ef | ||
|
|
88cd5825d3 | ||
|
|
ecdad2a315 | ||
|
|
0398ddd6a2 | ||
|
|
50ea4d3b0f | ||
|
|
77be8169f2 | ||
|
|
7a435f76b6 | ||
|
|
42949e0dea | ||
|
|
26db423232 | ||
|
|
645cf52803 | ||
|
|
673b8ad5b2 | ||
|
|
2a03834bb2 | ||
|
|
c1b6149e49 | ||
|
|
0690d86e52 | ||
|
|
bb8a11d110 | ||
|
|
4f7ba4c9a8 | ||
|
|
aa41e4d915 | ||
|
|
bb43b5451f | ||
|
|
69dd415ab5 | ||
|
|
e605f549bd | ||
|
|
a961932b2e | ||
|
|
e8cc80f046 | ||
|
|
67f29ac483 | ||
|
|
c9bde5cdc0 | ||
|
|
e878911819 | ||
|
|
f1a0b7f0ef | ||
|
|
3e0a5104e7 | ||
|
|
8f53d563a4 | ||
|
|
414740ffb7 | ||
|
|
7437d47d92 | ||
|
|
a68f19d72f | ||
|
|
11641c5e22 | ||
|
|
8d3e21d46a | ||
|
|
5ad54bfdc1 | ||
|
|
a8f5e95fb1 | ||
|
|
a4f3d08c02 | ||
|
|
3d2174d84e | ||
|
|
12fbc7d258 | ||
|
|
164b7e2551 | ||
|
|
eafac491d8 | ||
|
|
3cfb6e968d | ||
|
|
375825125f | ||
|
|
a8520e7545 | ||
|
|
ac154cdd83 | ||
|
|
9290775ab5 | ||
|
|
d14e8cdee4 | ||
|
|
7aac9f9d0e | ||
|
|
41aaac7d32 | ||
|
|
c8d2399db9 | ||
|
|
f37c8e5fd4 | ||
|
|
9f5025c10b | ||
|
|
c27d999c41 | ||
|
|
9681bea237 | ||
|
|
8905d6352c | ||
|
|
8599b20678 | ||
|
|
491f09a51b | ||
|
|
0f1519a21f | ||
|
|
1a17f2956a | ||
|
|
d94e27bfa9 | ||
|
|
b892156092 | ||
|
|
7b1b8dc749 | ||
|
|
6d0167dcf3 | ||
|
|
0c2d661e1c | ||
|
|
95d1440d6f | ||
|
|
0cabf60dc4 | ||
|
|
836ca1cc6b | ||
|
|
be799daafe | ||
|
|
ad9d674a03 | ||
|
|
f52c3c430f | ||
|
|
a91ab0e910 | ||
|
|
39d1f1677f | ||
|
|
b0dcae3586 | ||
|
|
ed6351f8f1 | ||
|
|
e486a2fb26 | ||
|
|
195bdb947e | ||
|
|
1576aed1ea | ||
|
|
e66fbc3289 | ||
|
|
b4c89ad58f | ||
|
|
8cc5846808 | ||
|
|
2eaaf01ca1 | ||
|
|
67694c0f96 | ||
|
|
163e5b2c52 | ||
|
|
508f1d3a42 | ||
|
|
d2207a5255 | ||
|
|
bf03f5c9ae | ||
|
|
656223f57d | ||
|
|
dc6e3ec53b | ||
|
|
5835a756ce | ||
|
|
f3f98a50ed | ||
|
|
0f4bb78712 | ||
|
|
c4014518cb | ||
|
|
3605f62feb | ||
|
|
5c3e253067 | ||
|
|
8d43cee52e | ||
|
|
1e64413904 | ||
|
|
6fd1ea26ee | ||
|
|
e619fd4af9 | ||
|
|
e7658f9859 | ||
|
|
3defb09da9 | ||
|
|
a672434909 | ||
|
|
c3fdd977b1 | ||
|
|
dd233f77fc | ||
|
|
02efd9c217 | ||
|
|
20f3c0388a | ||
|
|
ef530780bd | ||
|
|
d7ec611ff4 | ||
|
|
b897e7102e | ||
|
|
1cc5c5384e | ||
|
|
db602ac65b | ||
|
|
eaa209bc3a | ||
|
|
51d4aea9e2 | ||
|
|
9738ada946 | ||
|
|
8ec105bee0 | ||
|
|
4fd0852bb3 | ||
|
|
a53e904f7b | ||
|
|
2d22b52b5d | ||
|
|
426ac49f6f | ||
|
|
c164814abd | ||
|
|
3084892ed8 | ||
|
|
9297f877c4 | ||
|
|
1bf808c9ee | ||
|
|
91f44fb394 | ||
|
|
385a52f676 | ||
|
|
8ef16781eb | ||
|
|
ad5ea1ca44 | ||
|
|
0ba5d754d5 | ||
|
|
ccdcfdce8a | ||
|
|
712fb4d0d3 | ||
|
|
de65a03998 | ||
|
|
6d6710db4a | ||
|
|
c34c3e51ea | ||
|
|
5dc3b64e0b | ||
|
|
e8ceeb6e20 | ||
|
|
d38c7ce6a5 | ||
|
|
e625543b94 | ||
|
|
679bd4e4c9 | ||
|
|
c6a312845a | ||
|
|
ef0530ec6b | ||
|
|
2c98a90d60 | ||
|
|
b90fad6664 | ||
|
|
5a5ea4a018 | ||
|
|
bc68c487ee | ||
|
|
617cdf14ad | ||
|
|
f1c970461f | ||
|
|
2fde47a86f | ||
|
|
4e5f2f44b6 | ||
|
|
e8a2e54d05 | ||
|
|
d77f3ecee8 | ||
|
|
06776ebe8f | ||
|
|
e1eec55f62 | ||
|
|
fcabf08e74 | ||
|
|
b4694313a0 | ||
|
|
abb2cae1f8 | ||
|
|
b0004fd9dc | ||
|
|
362a82f944 | ||
|
|
19fe61ed29 | ||
|
|
72de38b4fb | ||
|
|
02c0f96e5e | ||
|
|
aee82282ac | ||
|
|
8497aeeb91 | ||
|
|
5e9f688000 | ||
|
|
6a7e346695 | ||
|
|
071738116e | ||
|
|
147726ecb0 | ||
|
|
ae4ee6431d | ||
|
|
9cfcb714ae | ||
|
|
d1ccde2a4b | ||
|
|
4848091203 | ||
|
|
282f159311 | ||
|
|
4ef8c77a2d | ||
|
|
08c1cf2439 | ||
|
|
2fc33875bb | ||
|
|
9e92e4b5ff | ||
|
|
7f2cf70bf5 | ||
|
|
40725d4155 | ||
|
|
8164026891 | ||
|
|
0e23b3a1ac | ||
|
|
1739d4861e | ||
|
|
a6b6e7850d | ||
|
|
3e9dea6f07 | ||
|
|
1b37ca805f | ||
|
|
c772f56da7 | ||
|
|
bc183e39bb | ||
|
|
306d4f70a8 | ||
|
|
a386d39495 | ||
|
|
22b14dff5f | ||
|
|
e749cc7578 | ||
|
|
3e03002ead | ||
|
|
4ae9cddcce | ||
|
|
16724645ce | ||
|
|
6a12cad1c9 | ||
|
|
c15665803d | ||
|
|
97090888d5 | ||
|
|
4642308fbb | ||
|
|
59bccb1188 | ||
|
|
cd8fc007ac | ||
|
|
7cfb38307e | ||
|
|
994aa32745 | ||
|
|
f0b872e86b | ||
|
|
0c33432436 | ||
|
|
0bb4dd9442 | ||
|
|
7a54dc15da | ||
|
|
e16a1100d8 | ||
|
|
99214e22e3 | ||
|
|
c77d35a2ed | ||
|
|
d98fdbdc5c | ||
|
|
4551cf0a21 | ||
|
|
023c3474d2 | ||
|
|
2a4cefb4bf | ||
|
|
09305724fa | ||
|
|
360fda1ba7 | ||
|
|
dadf0cf96e | ||
|
|
3d60ac751e | ||
|
|
32793eef8c | ||
|
|
da1cdfd6fa | ||
|
|
58ad7dc161 | ||
|
|
0a15f44193 | ||
|
|
e1dec3c1ba | ||
|
|
7834860245 | ||
|
|
2da1025f26 | ||
|
|
78c83b2e21 | ||
|
|
414a47e2f2 | ||
|
|
6c78b4ec8f | ||
|
|
a6949bd3ae | ||
|
|
f7bed04ab2 | ||
|
|
6ec773079c | ||
|
|
366e27a321 | ||
|
|
32c304dc1b | ||
|
|
338499247d | ||
|
|
79e1761c1f | ||
|
|
4ea1a19572 | ||
|
|
e2ae341ba9 | ||
|
|
de03435bac | ||
|
|
e16c425f87 | ||
|
|
c461e00c5c | ||
|
|
fcf6bb43b7 | ||
|
|
f5f72f87a6 | ||
|
|
3340451245 | ||
|
|
c14f1b5000 | ||
|
|
a46e55d5c2 | ||
|
|
4b64bfaec0 | ||
|
|
2f0c1eeecc | ||
|
|
546d4c1d3d | ||
|
|
160d88f002 | ||
|
|
a83cd29f72 | ||
|
|
94304b5777 | ||
|
|
61ddfe01a1 | ||
|
|
00d334f704 | ||
|
|
f4a4979997 | ||
|
|
03171e4743 | ||
|
|
5369e68267 | ||
|
|
9eb23e38bd | ||
|
|
2a0166bb26 | ||
|
|
2df612ec1f | ||
|
|
36ba3758db | ||
|
|
7cc0f39d3c | ||
|
|
9cf5590371 | ||
|
|
81f835458f | ||
|
|
e01b1db706 | ||
|
|
cdb18de305 | ||
|
|
8e0eef3316 | ||
|
|
221d45f564 | ||
|
|
2a4a01a4be | ||
|
|
501670bdd2 | ||
|
|
24637a1693 | ||
|
|
7bd1340190 | ||
|
|
cb5c09d967 | ||
|
|
a01ba5909c | ||
|
|
1c4678af95 | ||
|
|
5f5435c645 | ||
|
|
2f7dc2c46c | ||
|
|
9bc1c9dd03 | ||
|
|
4c81cdb4a2 | ||
|
|
3406ffa7a2 | ||
|
|
6d05b6845e | ||
|
|
29b4966119 | ||
|
|
d0f8358431 | ||
|
|
a75bd07cd8 | ||
|
|
8c1835950b | ||
|
|
c7cd8e4c80 | ||
|
|
f65e4066e3 | ||
|
|
37c18c5d3c | ||
|
|
8885f580b2 | ||
|
|
512ac74ee6 | ||
|
|
384ce9853b | ||
|
|
b6d2030041 | ||
|
|
3ac09181c6 | ||
|
|
ffc9e5823a | ||
|
|
f5448fed59 | ||
|
|
8163e51434 | ||
|
|
3836836c72 | ||
|
|
b78bf39767 | ||
|
|
25f8283edd | ||
|
|
7c8399ce88 | ||
|
|
9fe2a1dd41 | ||
|
|
846f554157 | ||
|
|
d1f66cbf4d | ||
|
|
a4624c7377 | ||
|
|
10435cea69 | ||
|
|
ce9a23e021 | ||
|
|
4b7c8f21c2 | ||
|
|
6ddebdbbd1 | ||
|
|
d92729d346 | ||
|
|
fa06dbbd29 | ||
|
|
5d59a1a10e | ||
|
|
222a251180 | ||
|
|
9d6559f0d7 | ||
|
|
da02f49850 | ||
|
|
992961c488 | ||
|
|
0ce30a4e81 | ||
|
|
bb2d794b6f | ||
|
|
45dc302de4 | ||
|
|
4a2706a9d9 | ||
|
|
00be3c3ccc | ||
|
|
cb7fe50d46 | ||
|
|
d364dbac2c | ||
|
|
042788bec3 | ||
|
|
def261f578 | ||
|
|
c08e23085e | ||
|
|
e01dd2bf57 | ||
|
|
61396ec82e | ||
|
|
357c283437 | ||
|
|
1b38cd6ca7 | ||
|
|
bdfa8bfe5b | ||
|
|
7f2ef65fe6 | ||
|
|
102d0472c7 | ||
|
|
445fc6efb1 | ||
|
|
135726f177 | ||
|
|
671ca0a66f | ||
|
|
aa4a79934a | ||
|
|
16fc0617e4 | ||
|
|
64a2f3f8bb | ||
|
|
b7a65343af | ||
|
|
5c121ea48d | ||
|
|
673f28ed64 | ||
|
|
3fb97d16bb | ||
|
|
079c9176ef | ||
|
|
9377a0b545 | ||
|
|
1357c4a309 | ||
|
|
d77be5a244 | ||
|
|
08863edb52 | ||
|
|
3a77705142 | ||
|
|
1eafa9a38a | ||
|
|
396b7aac18 | ||
|
|
08defbbbd8 | ||
|
|
79d371fb76 | ||
|
|
9df262d502 | ||
|
|
6f392ce126 | ||
|
|
a83ec10b61 | ||
|
|
a93f75fb5a | ||
|
|
2353cc4f2c | ||
|
|
30709c66ef | ||
|
|
70e6a3d303 | ||
|
|
cc89939d05 | ||
|
|
7d4a01c757 | ||
|
|
e2d61cb518 | ||
|
|
fb1a9c9867 | ||
|
|
776ae04cbe | ||
|
|
2447ab4305 | ||
|
|
52124b15e8 | ||
|
|
b1e9e8677b | ||
|
|
617e772cc1 | ||
|
|
27f770604b | ||
|
|
5bfc581ad2 | ||
|
|
2664a52007 | ||
|
|
6dbbf1fc89 | ||
|
|
c254f2fdc4 | ||
|
|
cf450fa4e4 | ||
|
|
304f29bfac | ||
|
|
50b8b3d649 | ||
|
|
4e6c1094f3 | ||
|
|
a6134ca10f | ||
|
|
3d999a503c | ||
|
|
39c2124a26 | ||
|
|
4e3955b39d | ||
|
|
784ae0da53 | ||
|
|
eaede032b4 | ||
|
|
4ed153373f | ||
|
|
07d7fac490 | ||
|
|
5535b6a6e3 | ||
|
|
b7fbb84a58 | ||
|
|
19bd94ed02 | ||
|
|
54b45a36e1 | ||
|
|
ed1afa7549 | ||
|
|
2986a18c8f | ||
|
|
b2072c06b7 | ||
|
|
762018883f | ||
|
|
0322c01c0e | ||
|
|
16ccfb8714 | ||
|
|
68095700a2 | ||
|
|
058f8b544e | ||
|
|
4cb871849b | ||
|
|
423305c35a | ||
|
|
b55313527e | ||
|
|
af53c456ea | ||
|
|
37024eb91d | ||
|
|
ee99565b63 | ||
|
|
1a8c08799f | ||
|
|
8b08a5bee0 | ||
|
|
51497d87e0 | ||
|
|
7ede1a8d83 | ||
|
|
b4df5c076e | ||
|
|
52400252dd | ||
|
|
49923c4214 | ||
|
|
81b77c9688 | ||
|
|
7284bb54bc | ||
|
|
6afdd8375d | ||
|
|
af23d9fd14 | ||
|
|
e7aead292c | ||
|
|
fd2678ce2f | ||
|
|
a6d660e708 | ||
|
|
de35a26285 | ||
|
|
18bb045e9a | ||
|
|
9090ec54e7 | ||
|
|
6fa9994366 | ||
|
|
665f2412f1 | ||
|
|
395099aa40 | ||
|
|
97a72a9ee2 | ||
|
|
3414202b7b | ||
|
|
52e5453d56 | ||
|
|
dd039a612f | ||
|
|
f5ab034aeb | ||
|
|
893ec2d61c | ||
|
|
ff41b26e94 | ||
|
|
d4d6fbab88 | ||
|
|
e38fe871b2 | ||
|
|
152d7bc3b3 | ||
|
|
9e7cf3ccd9 | ||
|
|
f7370a0280 | ||
|
|
814c574f26 | ||
|
|
fd9f9ee178 | ||
|
|
29e8f8f5fb | ||
|
|
279692afea | ||
|
|
fd09321f8e | ||
|
|
ad236baa86 | ||
|
|
8965b1fbba | ||
|
|
9b32411659 | ||
|
|
32dda9b904 | ||
|
|
c0cb5b96bf | ||
|
|
ff60030ffb | ||
|
|
f40bf2d9ba | ||
|
|
9eebee3ce3 | ||
|
|
8a3bdf136b | ||
|
|
f62076d3fd | ||
|
|
92f4d6b392 | ||
|
|
96ffd7e147 | ||
|
|
07c38e9b6c | ||
|
|
c0aca97083 | ||
|
|
2fd25f53cc | ||
|
|
2b3383a163 | ||
|
|
421a27ceae | ||
|
|
10022451b4 | ||
|
|
3c8d923299 | ||
|
|
154044e32a | ||
|
|
bfc8c10f3d | ||
|
|
d93b5a7b5c | ||
|
|
4ae608ed93 | ||
|
|
e2aef1fc1d | ||
|
|
16cadfeae8 | ||
|
|
3c9b42b9f7 | ||
|
|
9c0f27edb4 | ||
|
|
f81ee1b267 | ||
|
|
a964d955f4 | ||
|
|
f11c65c393 | ||
|
|
f8e5e9f675 | ||
|
|
72eb36f5b3 | ||
|
|
97c0fe1ece | ||
|
|
844b552bf3 | ||
|
|
6bb85deca6 | ||
|
|
551f7616f0 | ||
|
|
285c508329 | ||
|
|
f751657903 | ||
|
|
89096554e8 | ||
|
|
4bf6cce4ba | ||
|
|
85eae0b74a | ||
|
|
0a5657738e | ||
|
|
3aa0adbf39 | ||
|
|
7dc21ce8a7 | ||
|
|
6a6b200861 | ||
|
|
1c7868312d | ||
|
|
90d1c16783 | ||
|
|
3cfca046ba | ||
|
|
85414eb65f | ||
|
|
fdff57da7c | ||
|
|
7c223feef5 | ||
|
|
3740cb2c30 | ||
|
|
b5dd48ad7b | ||
|
|
e46025739a | ||
|
|
66a3538d05 | ||
|
|
e1fa24c251 | ||
|
|
a76e22c021 | ||
|
|
c166327835 | ||
|
|
4ab006f065 | ||
|
|
7eaaef6e75 | ||
|
|
c4f94efe24 | ||
|
|
2eb729d712 | ||
|
|
0343b6cf98 | ||
|
|
7fc4ea0c68 | ||
|
|
195a3ab170 | ||
|
|
a96f485e3c | ||
|
|
1b3a32f83f | ||
|
|
cacf74af3c | ||
|
|
4e9f68acff | ||
|
|
b58295d1d6 | ||
|
|
cbcf187814 | ||
|
|
4baa003c0d | ||
|
|
8cf8c3c122 | ||
|
|
e3e2c0ab6a | ||
|
|
e8862a3811 | ||
|
|
1c1a82696b | ||
|
|
a2893bac7e | ||
|
|
0eda42f29f | ||
|
|
26f7310707 | ||
|
|
810da0db61 | ||
|
|
8f6aa950cd | ||
|
|
36a2482165 | ||
|
|
639c18395b | ||
|
|
fe08fd3f0a | ||
|
|
0822ee6b96 | ||
|
|
96fdb9241a | ||
|
|
0c6d193e0f | ||
|
|
ece15c7394 | ||
|
|
29bef052c7 | ||
|
|
3ce1e40b43 | ||
|
|
290316e23e | ||
|
|
a74736b100 | ||
|
|
3f7e7f2601 | ||
|
|
abefb011a5 | ||
|
|
259eff3fea | ||
|
|
c271235d16 | ||
|
|
7539afa91e | ||
|
|
4c79905f5b | ||
|
|
b6d020e202 | ||
|
|
5a4dec3dc5 | ||
|
|
23ad006187 | ||
|
|
f7926847ac | ||
|
|
895bd578e4 | ||
|
|
67a052b117 | ||
|
|
3e41dae3ea | ||
|
|
420c616e9d | ||
|
|
822009ec5f | ||
|
|
b5e1c78461 | ||
|
|
bd0e892447 | ||
|
|
92db453f81 | ||
|
|
0060f57b63 | ||
|
|
2c517de5bb | ||
|
|
9d5f7fdd9c | ||
|
|
ddaa5b784d | ||
|
|
fadd9ff95d | ||
|
|
a40f365a54 | ||
|
|
3964bffce4 | ||
|
|
a8deb3593b | ||
|
|
ba3ef98d1e | ||
|
|
59de0d47a3 | ||
|
|
e0d6e0117e | ||
|
|
e157160337 | ||
|
|
c7d2a3ffd4 | ||
|
|
2f897c9c98 | ||
|
|
de83db10d6 | ||
|
|
4c690dd3c6 | ||
|
|
14fa0b4fd3 | ||
|
|
f8b55eb017 | ||
|
|
2b0bccf2d8 | ||
|
|
c1c68cf72d | ||
|
|
3db5c49009 | ||
|
|
87ffaceca3 | ||
|
|
591d98d8b6 | ||
|
|
e0d93eaa9f | ||
|
|
5510ff7dce | ||
|
|
a1a6185fd6 | ||
|
|
b71b87e6e9 | ||
|
|
41cc518e20 | ||
|
|
508356898f | ||
|
|
0c40a954fa | ||
|
|
784f99a900 | ||
|
|
90ae0b3e44 | ||
|
|
520aaac31f | ||
|
|
8fe1370a74 | ||
|
|
c6ae89bf27 | ||
|
|
822ef8829e | ||
|
|
726e67ebb0 | ||
|
|
d4825b1d40 | ||
|
|
f58a16ca9d | ||
|
|
2c429fd406 | ||
|
|
ebcca0c3b8 | ||
|
|
925fd9f268 | ||
|
|
0058edc24e | ||
|
|
aa66133813 | ||
|
|
66f9a82f31 | ||
|
|
1092abe776 | ||
|
|
0411792ca5 | ||
|
|
b9a13d3a32 | ||
|
|
0a1359ed16 | ||
|
|
9bd8c774ab | ||
|
|
2943f93218 | ||
|
|
5b8a0881b7 | ||
|
|
5d677a9115 | ||
|
|
26bf9aab26 | ||
|
|
d9b4529932 | ||
|
|
35ecb8499d | ||
|
|
ed5dc7cdfd | ||
|
|
75489c00c2 | ||
|
|
3aaa7b62ef | ||
|
|
c13b9754eb | ||
|
|
a97417fd38 | ||
|
|
43261f8469 | ||
|
|
b32935dd97 | ||
|
|
35660ff5e7 | ||
|
|
9b07909ed8 | ||
|
|
b4eb317b00 | ||
|
|
464d77dfb5 | ||
|
|
a67ad12cde | ||
|
|
0dba9b8268 | ||
|
|
4a4c9cd63f | ||
|
|
d0c9c1043c | ||
|
|
795405c47d | ||
|
|
e0c2f873f5 | ||
|
|
1ec50cf6ad | ||
|
|
2ef53c6df9 | ||
|
|
249be451f7 | ||
|
|
34a228adbe | ||
|
|
9782eaaeea | ||
|
|
50d3122bee | ||
|
|
3a264e6baf | ||
|
|
1b75b68373 | ||
|
|
4224e8314b | ||
|
|
7b14ad9616 | ||
|
|
be7386f0d7 | ||
|
|
cd3263db50 | ||
|
|
3034019d5a | ||
|
|
1fd48a1cf8 | ||
|
|
c3f39ad24d | ||
|
|
68d9394d9f | ||
|
|
80fca589af | ||
|
|
420c33d3ba | ||
|
|
de0cd976de | ||
|
|
a116774104 | ||
|
|
1e180489a4 | ||
|
|
e00656d757 | ||
|
|
adcc74ac8e | ||
|
|
3e0085b4a4 | ||
|
|
17fb2a98d6 | ||
|
|
780efc2477 | ||
|
|
7f02fe4157 | ||
|
|
f722576bf2 | ||
|
|
7fecc2cf4c | ||
|
|
3519e070b4 | ||
|
|
ca6b7fbeb2 | ||
|
|
25d7e121c9 | ||
|
|
882077f0aa | ||
|
|
0479113949 | ||
|
|
b5b69ff369 | ||
|
|
f0ad76fff6 | ||
|
|
e651ea7614 | ||
|
|
acca85b99a | ||
|
|
230f44f4e6 | ||
|
|
19c42490e3 | ||
|
|
03a0e2084a | ||
|
|
116fa6777b | ||
|
|
35d4222c7a | ||
|
|
dd0de7e8be | ||
|
|
e3e7503a7c | ||
|
|
b66f4bf2be | ||
|
|
1c8dbae359 | ||
|
|
4f36349630 | ||
|
|
68b27451f2 | ||
|
|
c7acd63ea7 | ||
|
|
cfc17cf290 | ||
|
|
904e173037 | ||
|
|
8a8d38a30f | ||
|
|
a9ebf534c6 | ||
|
|
6429ff0603 | ||
|
|
f5057dfac4 | ||
|
|
00d61def0b | ||
|
|
f5a26c7116 | ||
|
|
54fba99bed | ||
|
|
7216a8b923 | ||
|
|
97e322ba22 | ||
|
|
fc603f11ce | ||
|
|
87f01007cc | ||
|
|
10bca290c3 | ||
|
|
3dabaeb2c9 | ||
|
|
cf74b879c6 | ||
|
|
0ae2a1f177 | ||
|
|
3d63d6c0f2 | ||
|
|
905a3a30f3 | ||
|
|
af29637163 | ||
|
|
7351fe9633 | ||
|
|
1a6b4a1188 | ||
|
|
ec96c1b534 | ||
|
|
8751dd3797 | ||
|
|
9a6df25280 | ||
|
|
ada8912a1f | ||
|
|
de4245025c | ||
|
|
f620f4a92e | ||
|
|
c74c5e0c6d | ||
|
|
2ca85c7829 | ||
|
|
8374404b0f | ||
|
|
c453c6c294 | ||
|
|
a5e5c3d941 | ||
|
|
c242a08653 | ||
|
|
f931603203 | ||
|
|
167d57408d | ||
|
|
ef03a3d9d4 | ||
|
|
ccfc9f2ad2 | ||
|
|
b3456ee96c | ||
|
|
05cd4ac14b | ||
|
|
ba2ecf9789 | ||
|
|
020e6b1cb3 | ||
|
|
2a7365730b | ||
|
|
ad77d74f4b | ||
|
|
ef8668dce4 | ||
|
|
3fb34e28a4 | ||
|
|
871214f907 | ||
|
|
7e717754a3 | ||
|
|
6e67946ae2 | ||
|
|
48d673c853 | ||
|
|
a9bb6f8099 | ||
|
|
f8ef69b88a | ||
|
|
a005ed2a84 | ||
|
|
1aa859b10d | ||
|
|
4aba34c18b | ||
|
|
5e099f522e | ||
|
|
15c33014e7 | ||
|
|
af5b9172ef | ||
|
|
fe9e813c79 | ||
|
|
51d7cdfd31 | ||
|
|
f3aef67be6 | ||
|
|
449af8060a | ||
|
|
fa19f1f5a0 | ||
|
|
9e461ef6e1 | ||
|
|
1ba301ed16 | ||
|
|
7e663b05d5 | ||
|
|
2225a735ca | ||
|
|
90c8fbb495 | ||
|
|
2b14efd3f8 | ||
|
|
3261c36f97 | ||
|
|
c48d65525a | ||
|
|
5fa6e755b2 | ||
|
|
8bbc0b9e1a | ||
|
|
3a5317f16a | ||
|
|
c0bb06bf49 | ||
|
|
8d45af2034 | ||
|
|
5f85bf62f5 | ||
|
|
8fa409d6c1 | ||
|
|
7167c2f20d | ||
|
|
20846c8eff | ||
|
|
1b44a01efd | ||
|
|
c4104dcd33 | ||
|
|
c319c3f520 | ||
|
|
85025695df | ||
|
|
f6ca22ecdd | ||
|
|
8d9594ba36 | ||
|
|
fe7c66cf1d | ||
|
|
b5aa940701 | ||
|
|
698dfb67d1 | ||
|
|
8e61d77497 | ||
|
|
38f2f1a3e4 | ||
|
|
b98c6ca5c5 | ||
|
|
5641874811 | ||
|
|
1dd34035c9 | ||
|
|
6bf170e273 | ||
|
|
084ac9b916 | ||
|
|
cebf061f85 | ||
|
|
5641db0026 | ||
|
|
a42ec8eddb | ||
|
|
ea9917dacc | ||
|
|
6272ae842c | ||
|
|
b000eda126 | ||
|
|
9962bac50b | ||
|
|
f0c3f1b9ba | ||
|
|
ec8eeef428 | ||
|
|
7eb1a4b489 | ||
|
|
23b23f0e38 | ||
|
|
cba78190a8 | ||
|
|
e097a49186 | ||
|
|
e895c784c7 | ||
|
|
7e1bcf84f0 | ||
|
|
a92f1b82d0 | ||
|
|
433e6901c6 | ||
|
|
e16d835727 | ||
|
|
a5cf2d37d4 | ||
|
|
4bd6fbd445 | ||
|
|
8f18933713 | ||
|
|
caad670dbf | ||
|
|
2d30f86cc6 | ||
|
|
1dd79d9e31 | ||
|
|
4171afe275 | ||
|
|
a287192649 | ||
|
|
f2e9631af4 | ||
|
|
c756ab70ae | ||
|
|
2e57fe0dfd | ||
|
|
be39d28be7 | ||
|
|
23a292b8ff | ||
|
|
cdbb247780 | ||
|
|
69d4f0ce10 | ||
|
|
2580475f67 | ||
|
|
138789149c | ||
|
|
1be66659d3 | ||
|
|
6d3ba0ae72 | ||
|
|
04f61677d7 | ||
|
|
0096e65fe6 | ||
|
|
b870306c5d | ||
|
|
480b2181f0 | ||
|
|
ddc3fe7807 | ||
|
|
a86e8659f7 | ||
|
|
ae10dd639b | ||
|
|
a0141624b9 | ||
|
|
dc137620eb | ||
|
|
e9b92b216a | ||
|
|
24bf057d17 | ||
|
|
b68c6b6807 | ||
|
|
34a268624b | ||
|
|
cdd527f3ac | ||
|
|
1f048a6d04 | ||
|
|
58cf10ffb2 | ||
|
|
1ef14e129f | ||
|
|
7c4030aaef | ||
|
|
c1bf0f8799 | ||
|
|
4b0a4aa5d2 | ||
|
|
115be88e5d | ||
|
|
268bd8f1a6 | ||
|
|
1d9ff17380 | ||
|
|
0fa0d72300 | ||
|
|
677d166b1e | ||
|
|
b5778a9cb5 | ||
|
|
b2fd94d20e | ||
|
|
16969bc39b | ||
|
|
3943314142 | ||
|
|
f7ee532add | ||
|
|
2fdab4c196 | ||
|
|
e6a95370c1 | ||
|
|
92907bced3 | ||
|
|
ca30b8b62a | ||
|
|
da9ac6ff25 | ||
|
|
475de5250e | ||
|
|
7a9860ac29 | ||
|
|
32ca02bcc7 | ||
|
|
ddefb99e5e | ||
|
|
ca4d6e0b2f | ||
|
|
c3fc3a3132 | ||
|
|
78b8a1c36f | ||
|
|
638c3492d6 | ||
|
|
4c1699935c | ||
|
|
25829451c8 | ||
|
|
74fbce8b96 | ||
|
|
542039df01 | ||
|
|
d652ecff21 | ||
|
|
00c4cf300a | ||
|
|
da47054497 | ||
|
|
051a2a3ef2 | ||
|
|
ee609f3e8f | ||
|
|
eb66354c76 | ||
|
|
c7fb7e58cf | ||
|
|
c2b02a45a2 | ||
|
|
e7ed532545 | ||
|
|
2a031320c2 | ||
|
|
d0379fdede | ||
|
|
45016b76e7 | ||
|
|
ee8cd8ef26 | ||
|
|
18d89e9cad | ||
|
|
623c8ca6b0 | ||
|
|
39736e865e | ||
|
|
8ea80a616e | ||
|
|
c5df7f9bb7 | ||
|
|
92374966fb | ||
|
|
6bebfb861c | ||
|
|
30ae13b245 | ||
|
|
891f990e35 | ||
|
|
2118327ae0 | ||
|
|
6aed2902a7 | ||
|
|
e149e32ce1 | ||
|
|
41f2af8c4e | ||
|
|
016f808345 | ||
|
|
bc69524654 | ||
|
|
3c6280c419 | ||
|
|
9d01a52a4a | ||
|
|
a8273a8fdc | ||
|
|
d6d3bf6943 | ||
|
|
f6e8346841 | ||
|
|
b9717e9894 | ||
|
|
6b3209e6ee | ||
|
|
0a6da5ead1 | ||
|
|
53441148b8 | ||
|
|
732d018819 | ||
|
|
e261a8ba21 | ||
|
|
c3c87bff74 | ||
|
|
c3f423aad5 | ||
|
|
580975fda1 | ||
|
|
9f114a1dad | ||
|
|
0ae93d0657 | ||
|
|
3a210c5bab | ||
|
|
44d2627e2a | ||
|
|
6e882760f1 | ||
|
|
ff79ffd1c8 | ||
|
|
3175b0c4ff | ||
|
|
21779395ef | ||
|
|
32cbb698ee | ||
|
|
3f99c52349 | ||
|
|
19a41b2792 | ||
|
|
599910daea | ||
|
|
bee42ea2fb | ||
|
|
221ea5ebb0 | ||
|
|
f24df9fb05 | ||
|
|
ce2a122d51 | ||
|
|
e8242aec85 | ||
|
|
6ed9dcbe93 | ||
|
|
58371e6e43 | ||
|
|
2d8957489e | ||
|
|
1fd0794bfb | ||
|
|
58da60985f | ||
|
|
6b6a3cd38e | ||
|
|
4b1df16ecf | ||
|
|
24ea686e4d | ||
|
|
a7030cdcb9 | ||
|
|
8c137ecc52 | ||
|
|
20e44aa891 | ||
|
|
118bb53c03 | ||
|
|
7c3be9f0b0 | ||
|
|
d1990a4263 | ||
|
|
396422ee3a | ||
|
|
f735b401df | ||
|
|
a42beb86c0 | ||
|
|
85020270d5 | ||
|
|
b1b9044021 | ||
|
|
8da30b216f | ||
|
|
167d3caa5d | ||
|
|
3259e6f0e8 | ||
|
|
64526c5232 | ||
|
|
d9630afafd | ||
|
|
c8c6e62aa0 | ||
|
|
7f561c30b3 | ||
|
|
1d8f342417 | ||
|
|
6ec090ea0d | ||
|
|
08a8eadb49 | ||
|
|
3e2835bef6 | ||
|
|
686fc754b2 | ||
|
|
ea17124d6d | ||
|
|
4000041308 | ||
|
|
1a50ed0316 | ||
|
|
42038cd6e7 | ||
|
|
44c5b41cc7 | ||
|
|
da7bd91514 | ||
|
|
0206623c6f | ||
|
|
3b2948d4dd | ||
|
|
918aeb670e | ||
|
|
fd9fec48a2 | ||
|
|
77e51b40b8 | ||
|
|
195663c6e3 | ||
|
|
ce4ca5c4d5 | ||
|
|
3e276c4111 | ||
|
|
41a4dc2fa2 | ||
|
|
7851047421 | ||
|
|
a30e478cbd | ||
|
|
ad4b3dfad1 | ||
|
|
ad7fc937a9 | ||
|
|
fd905ef308 | ||
|
|
3f257af7a9 | ||
|
|
030bb8fe76 | ||
|
|
131601d9d2 | ||
|
|
64317ffef5 | ||
|
|
911e65af55 | ||
|
|
82165eaf37 | ||
|
|
4a75f2ebca | ||
|
|
be39b3be8c | ||
|
|
50e8aff8fa | ||
|
|
804a790392 | ||
|
|
d04566a6c4 | ||
|
|
6c614a4b3c | ||
|
|
3277717a7f | ||
|
|
f9b2829396 | ||
|
|
81cf108471 | ||
|
|
5075fe358e | ||
|
|
c8085a368f | ||
|
|
8191c25dd7 | ||
|
|
dc4b2bd52e | ||
|
|
ca60afbcee | ||
|
|
374b74b710 | ||
|
|
ae0d3d78cd | ||
|
|
f9f197afd0 | ||
|
|
93c43ecbc3 | ||
|
|
1fd1b0388b | ||
|
|
833364a94e | ||
|
|
893c105bf2 | ||
|
|
e481bd4ec5 | ||
|
|
b0489aa61b | ||
|
|
376bc29e95 | ||
|
|
bd22e330a7 | ||
|
|
9ce7114f8c | ||
|
|
1303da1c20 | ||
|
|
c6bb33fa84 | ||
|
|
22939a6707 | ||
|
|
9222877306 | ||
|
|
5d8264e854 | ||
|
|
77124e098c | ||
|
|
bd0a70d024 | ||
|
|
914700712e | ||
|
|
80d792915a | ||
|
|
54dc363231 | ||
|
|
36c436af50 | ||
|
|
73eb9259e2 | ||
|
|
951d915326 | ||
|
|
14c25480ce | ||
|
|
77d87f8c50 | ||
|
|
ab389d4817 | ||
|
|
58b9e0cd7c | ||
|
|
ed2f5af204 | ||
|
|
5b2f1f8969 | ||
|
|
a2122cb7d7 | ||
|
|
d680702b15 | ||
|
|
d15de499dc | ||
|
|
bd382e3cc7 | ||
|
|
d417fa58ab | ||
|
|
ca9cb997b5 | ||
|
|
ebd920f3b2 | ||
|
|
a611ddea2d | ||
|
|
75614e0bbb | ||
|
|
dafef6463a | ||
|
|
61d502eea4 | ||
|
|
71aa525dfd | ||
|
|
c0e3875dfd | ||
|
|
9c188e0acd | ||
|
|
1de143362c | ||
|
|
7e37b6c151 | ||
|
|
0fa84a8b84 | ||
|
|
236ae57d01 | ||
|
|
7345f464a5 | ||
|
|
3c45f2abe2 | ||
|
|
9c5e1faf46 | ||
|
|
ce02d3a829 | ||
|
|
1b80c59e65 | ||
|
|
f20f528a11 | ||
|
|
814b66c04a | ||
|
|
00ad2e7a80 | ||
|
|
8f7e5e491f | ||
|
|
19101176a7 | ||
|
|
0bc383fec2 | ||
|
|
4df918d6a5 | ||
|
|
d3cbd8cdae | ||
|
|
0fa5dc225c | ||
|
|
b14f14c45a | ||
|
|
0851f4fdd4 | ||
|
|
807b3370e7 | ||
|
|
a0f114e15c | ||
|
|
1401fcd97d | ||
|
|
efcd291e65 | ||
|
|
f98792714e | ||
|
|
5649f85b58 | ||
|
|
cfaba932e0 | ||
|
|
b1db4e8a7a | ||
|
|
ab9c11e038 | ||
|
|
4d621dcbfe | ||
|
|
a45537cbf3 | ||
|
|
2d3ac286ac | ||
|
|
4e96b5d4a6 | ||
|
|
9294324732 | ||
|
|
b92422594b | ||
|
|
ea2637b1b4 | ||
|
|
c97b4859c1 | ||
|
|
7a2f42de30 | ||
|
|
99f5f78fc7 | ||
|
|
668f0ca675 | ||
|
|
6a89a51ea6 | ||
|
|
df6b0f3945 | ||
|
|
65cf243373 | ||
|
|
2ef7813219 | ||
|
|
216efd74bf | ||
|
|
b9d027a44a | ||
|
|
9097dd9645 | ||
|
|
d784e26913 | ||
|
|
cb69298385 | ||
|
|
a8fc42a17e | ||
|
|
005008814a | ||
|
|
ad3bbaedb3 | ||
|
|
cad0dabe42 | ||
|
|
48fa3c8aec | ||
|
|
fb585cbac0 | ||
|
|
dd1adda1a6 | ||
|
|
3742583508 | ||
|
|
3c6cd623af | ||
|
|
70c6e69b36 | ||
|
|
943e58d32a | ||
|
|
5237058016 | ||
|
|
b87c5f8a51 | ||
|
|
43e7a03af4 | ||
|
|
19fce4975d | ||
|
|
a9217810e7 | ||
|
|
a87610c856 | ||
|
|
0ec0cb1b19 | ||
|
|
9b1678a06c | ||
|
|
0da63062d7 | ||
|
|
c8dd12eb20 | ||
|
|
008592f13b | ||
|
|
56b9972053 | ||
|
|
1335c94bbc | ||
|
|
21a6ab369e | ||
|
|
2a80117d42 | ||
|
|
e65d312503 | ||
|
|
5fc34e643c | ||
|
|
3463a84903 | ||
|
|
48dc532de6 | ||
|
|
20cb62483f | ||
|
|
dcb5828313 | ||
|
|
74860256b9 | ||
|
|
97457f17c1 | ||
|
|
de9167cae6 | ||
|
|
2e5171c205 | ||
|
|
a0b5491178 | ||
|
|
fc8ef8678b | ||
|
|
2dc1f2ea5b | ||
|
|
7999527582 | ||
|
|
14be6506ee | ||
|
|
c85ad470ba | ||
|
|
8b6afcc5ec | ||
|
|
813dced6df | ||
|
|
0a39866045 | ||
|
|
48734689d8 | ||
|
|
dfe927dcbd | ||
|
|
ca158def31 | ||
|
|
409386336d | ||
|
|
eeed6c3474 | ||
|
|
3296cd6c39 | ||
|
|
60e25d9c67 | ||
|
|
ec65e2025e | ||
|
|
f09020c3bc | ||
|
|
91baaed96d | ||
|
|
64de64ce33 | ||
|
|
b685e7008e | ||
|
|
375b3d776c | ||
|
|
c1fddd7164 | ||
|
|
3af9bf9e12 | ||
|
|
9ef5d0c144 | ||
|
|
3d1b37dc85 | ||
|
|
80ce8347f6 | ||
|
|
3eb7e1392d | ||
|
|
ac78a44d74 | ||
|
|
87fed9fde3 | ||
|
|
2564430046 | ||
|
|
663861dc09 | ||
|
|
2d6a12101e | ||
|
|
e40110fa4c | ||
|
|
6ac162f3cd | ||
|
|
aea1d16e31 | ||
|
|
16e26ef215 | ||
|
|
7270e701d4 | ||
|
|
c8010d4d52 | ||
|
|
6941b7463e | ||
|
|
99a6cd82b2 | ||
|
|
1a44307664 | ||
|
|
53d7a92a0d | ||
|
|
4ba1f47423 | ||
|
|
c38e47b726 | ||
|
|
e6a4d79b86 | ||
|
|
b62d0697be | ||
|
|
f90ebbbb4e | ||
|
|
ab39802512 | ||
|
|
84da67adda | ||
|
|
cfff3c6d97 | ||
|
|
cc3d9e0d2d | ||
|
|
442e7eb015 | ||
|
|
59248b7c2e | ||
|
|
f2d7a45b74 | ||
|
|
c79b6147ea | ||
|
|
d93be76505 | ||
|
|
5fff65db5a | ||
|
|
53e240add7 | ||
|
|
9cfc65eeda | ||
|
|
47c305d557 | ||
|
|
c5ba89b054 | ||
|
|
de8977723a | ||
|
|
8cea93de94 | ||
|
|
e25cbe54d9 | ||
|
|
b356522f94 | ||
|
|
7a6c1de5d5 | ||
|
|
fb07adf7c1 | ||
|
|
9ceadd44c9 | ||
|
|
e1c529ab91 | ||
|
|
ce27af6083 | ||
|
|
ac7d224645 | ||
|
|
df26f492a7 | ||
|
|
448c01ca99 | ||
|
|
bd7a9e5444 | ||
|
|
1e717710b6 | ||
|
|
3cb14ad3bc | ||
|
|
4769a67936 | ||
|
|
279f866bf5 | ||
|
|
5cbe7600a6 | ||
|
|
cdb1a4c288 | ||
|
|
7d09d41a7d | ||
|
|
340bbd8727 | ||
|
|
53c916ea4f | ||
|
|
6451337274 | ||
|
|
294b75ce2d | ||
|
|
0ca4f3b104 | ||
|
|
ac74510d47 | ||
|
|
33ec69d33a | ||
|
|
f6d329ac48 | ||
|
|
a56fbeb611 | ||
|
|
8c20a67cfa | ||
|
|
fffa4fc031 | ||
|
|
3316b73ab6 | ||
|
|
211f7b7965 | ||
|
|
3a5a7bf674 | ||
|
|
7c749a964c | ||
|
|
997c8c87d0 | ||
|
|
ed6a417d7e | ||
|
|
4a54f545a4 | ||
|
|
789902b79a | ||
|
|
266859af19 | ||
|
|
9cca1a4819 | ||
|
|
aae1da3aa8 | ||
|
|
aed688224b | ||
|
|
3ce1ec708d | ||
|
|
510a564797 | ||
|
|
b36517babb | ||
|
|
415d18338e | ||
|
|
14384131f4 | ||
|
|
b3d54ce57e | ||
|
|
b5890340e3 | ||
|
|
050d987d3b | ||
|
|
c4651cd915 | ||
|
|
b5f97c0d94 | ||
|
|
35165ba2b8 | ||
|
|
aeb1dcdf15 | ||
|
|
37730744e7 | ||
|
|
f821fe0356 | ||
|
|
ba16fdb548 | ||
|
|
144e6f59c8 | ||
|
|
2e42c5e875 | ||
|
|
eec8743e2f | ||
|
|
e5e5684e2e | ||
|
|
efddc6ccec | ||
|
|
5aef46733b | ||
|
|
201782184c | ||
|
|
5f2ef046e1 | ||
|
|
42398950e4 | ||
|
|
506c8af1ea | ||
|
|
70d9c516af | ||
|
|
11ad86b9db | ||
|
|
2e9cfa6973 | ||
|
|
13e2c325e1 | ||
|
|
7e428a273f | ||
|
|
aa4bd516a9 | ||
|
|
82f8675b68 | ||
|
|
fdcb994e7a | ||
|
|
e89fa23533 | ||
|
|
21d4f0f569 | ||
|
|
625201e559 | ||
|
|
d36378fcbf | ||
|
|
929ecfd42b | ||
|
|
44496e424a | ||
|
|
1eb789e847 | ||
|
|
1ab76617df | ||
|
|
3bff653bbb | ||
|
|
4b7a8c6d6e | ||
|
|
9236be7fbd | ||
|
|
fd9b922b21 | ||
|
|
eea88f6e11 | ||
|
|
eb47c968ae | ||
|
|
560019b26c | ||
|
|
589e07f869 | ||
|
|
585de53148 | ||
|
|
1e85b25438 | ||
|
|
71b57bfed1 | ||
|
|
870cb26e01 | ||
|
|
9a180b098f | ||
|
|
06682c333f | ||
|
|
18c0aa5c81 | ||
|
|
e49b468fd5 | ||
|
|
7e5748b3a6 | ||
|
|
e99aa86863 | ||
|
|
bc6ae1d1b5 | ||
|
|
df94a87a51 | ||
|
|
9f7b2de311 | ||
|
|
dab6e10881 | ||
|
|
3b78c3a929 | ||
|
|
7029968c47 | ||
|
|
a8fe4e6aab | ||
|
|
b93dd8cb9b | ||
|
|
0ba614961d | ||
|
|
79c56d440c | ||
|
|
9601506270 | ||
|
|
9ed16b81e8 | ||
|
|
1800c1ff12 | ||
|
|
a8067bee36 | ||
|
|
f879663033 | ||
|
|
d618af19d6 | ||
|
|
8aa61bf5bc | ||
|
|
cd70f4b1c9 | ||
|
|
240e55029b | ||
|
|
9aabe7c72e | ||
|
|
6744dce57e | ||
|
|
d38e40d53f | ||
|
|
aa1b561bc0 | ||
|
|
6674b7890c | ||
|
|
a3a62165e9 | ||
|
|
8eb5a62737 | ||
|
|
c5ef462937 | ||
|
|
eca397b45f | ||
|
|
9f7a583c92 | ||
|
|
a59077b94f | ||
|
|
d61bfaa993 | ||
|
|
a17690f88b | ||
|
|
271e948c1f | ||
|
|
ac7de6213a | ||
|
|
7ff6b64742 | ||
|
|
531e0ad19d | ||
|
|
cc7112fb66 | ||
|
|
cf08af31ac | ||
|
|
1fdcf3877e | ||
|
|
0fadf035db | ||
|
|
58b1c4b511 | ||
|
|
0cc8feac57 | ||
|
|
ba1efd57a5 | ||
|
|
29656fb9a6 | ||
|
|
92d79ebeea | ||
|
|
3a69107eac | ||
|
|
4bfb528526 | ||
|
|
fe9dd1d014 | ||
|
|
4829c8b314 | ||
|
|
59b4bf5267 | ||
|
|
c19f34570d | ||
|
|
94d29796b8 | ||
|
|
e9f44ffcc6 | ||
|
|
a261ab4f0c | ||
|
|
929bcf03a0 | ||
|
|
a6a69ab1b6 | ||
|
|
39de79d3cd | ||
|
|
40ab540179 | ||
|
|
7d7b6f4475 | ||
|
|
ccdd433e35 | ||
|
|
4a6ea38ef8 | ||
|
|
b20e25f052 | ||
|
|
8591d4e96c | ||
|
|
912051637a | ||
|
|
c233f767f4 | ||
|
|
e1293c2c74 | ||
|
|
b63bf2465f | ||
|
|
505c9c6218 | ||
|
|
14350240eb | ||
|
|
cb21991efa | ||
|
|
49e58c25f2 | ||
|
|
ac6000a2ae | ||
|
|
6d1c9edc24 | ||
|
|
1a7fa3746d | ||
|
|
f7a57ffeb4 | ||
|
|
ad9d45a154 | ||
|
|
5fffb2afe3 | ||
|
|
1269114074 | ||
|
|
d24f6ae064 | ||
|
|
95fe09489c | ||
|
|
1a144da36d | ||
|
|
8e26da1759 | ||
|
|
daf53226c3 | ||
|
|
2b9e615e51 | ||
|
|
02acbecef5 | ||
|
|
8f28964ce2 | ||
|
|
495e74e2f0 | ||
|
|
543bd1a777 | ||
|
|
8f23970ccc | ||
|
|
9ec39658fe | ||
|
|
7c0518843f | ||
|
|
7131257354 | ||
|
|
db527be97c | ||
|
|
7c46e42820 | ||
|
|
9943e081d9 | ||
|
|
68a51c9c63 | ||
|
|
6a98cdf974 | ||
|
|
9ca8c66c47 | ||
|
|
56754d616b | ||
|
|
e7dd964825 | ||
|
|
39e348948c | ||
|
|
6583090d4f | ||
|
|
f20134415e | ||
|
|
bd9b9600c1 | ||
|
|
5ae9873455 | ||
|
|
5776ca0384 | ||
|
|
f8f4b39965 | ||
|
|
1d51419a11 | ||
|
|
5e1ca0c19f | ||
|
|
b341224c92 | ||
|
|
3861f23af3 | ||
|
|
e7beff79d0 | ||
|
|
2380875cbf | ||
|
|
343e6a50df | ||
|
|
5aa47d35e7 | ||
|
|
40996888c9 | ||
|
|
313ceed1d0 | ||
|
|
ac07d62344 | ||
|
|
2db1bbae4b | ||
|
|
090e50e936 | ||
|
|
b6bab0c723 | ||
|
|
1a333f7968 | ||
|
|
87c00b3804 | ||
|
|
eba71469a4 | ||
|
|
4eef127744 | ||
|
|
4c2941acf0 | ||
|
|
40791a9cd4 | ||
|
|
4d374581b5 | ||
|
|
4976dc3a4c | ||
|
|
9e0fd7d51e | ||
|
|
bf8b3c3b2f | ||
|
|
38336fdb02 | ||
|
|
7c7f77adc6 | ||
|
|
d28a2ebc57 | ||
|
|
67d413956d | ||
|
|
e644575bc5 | ||
|
|
0291ba8cb5 | ||
|
|
622a390b23 | ||
|
|
2e92705f9c | ||
|
|
c6548afa1b | ||
|
|
9e7deecb99 | ||
|
|
2773d7598b | ||
|
|
a9165aba25 | ||
|
|
fd9d54d2dd | ||
|
|
dde04ff979 | ||
|
|
e0f42f4a0a | ||
|
|
3a49d5fdc4 | ||
|
|
9dee7bb7e7 | ||
|
|
25428c9165 | ||
|
|
c6efc5b212 | ||
|
|
836075de10 | ||
|
|
396af917b5 | ||
|
|
a89104127a | ||
|
|
ed26706ee7 | ||
|
|
9de89e5544 | ||
|
|
d7f672ab0a | ||
|
|
b124aabf69 | ||
|
|
6c07a583f8 | ||
|
|
83256de752 | ||
|
|
44f4d083bf | ||
|
|
1b1a5be607 | ||
|
|
6b93f79d2e | ||
|
|
1ce26b3ada | ||
|
|
70f18151dd | ||
|
|
4de38a295c | ||
|
|
7701efc704 | ||
|
|
421f665e85 | ||
|
|
ca233be127 | ||
|
|
377bac67be | ||
|
|
1f97dd0111 | ||
|
|
f1fa22f4cf | ||
|
|
a998dc21b0 | ||
|
|
a0dbbfa04e | ||
|
|
e7092ae769 | ||
|
|
dd148b92c6 | ||
|
|
65d110eb0a | ||
|
|
78dec77c3c | ||
|
|
7723568cef | ||
|
|
ebfd50f30d | ||
|
|
e571c1f95c | ||
|
|
1b0e5e01fa | ||
|
|
a426591282 | ||
|
|
499ff590cd | ||
|
|
03aae3f787 | ||
|
|
ca25e257ef | ||
|
|
6e9c43c37b | ||
|
|
1db253f1fd | ||
|
|
67a55fee25 | ||
|
|
0f89c40a1d | ||
|
|
64627abe6d | ||
|
|
5895b37a06 | ||
|
|
5292d294be | ||
|
|
258d2c9ce3 | ||
|
|
b5cc515e42 | ||
|
|
88d5e9cbc3 | ||
|
|
6a9cc9bf37 | ||
|
|
cc7cee6d44 | ||
|
|
990db5967a | ||
|
|
28ae7eeaee | ||
|
|
ba8755a6d4 | ||
|
|
b4007038fb | ||
|
|
8c679a08c4 | ||
|
|
6c2e6ead2b | ||
|
|
f4a55d60a4 | ||
|
|
ab1e31b2ff | ||
|
|
1ceee8901e | ||
|
|
6042317552 | ||
|
|
d275702080 | ||
|
|
344d23bad1 | ||
|
|
ba85b56e9f | ||
|
|
64e5e02744 | ||
|
|
8084b2764a | ||
|
|
c057786011 | ||
|
|
9e0e66a0ae | ||
|
|
0168bfa67a | ||
|
|
d4b9557508 | ||
|
|
9ecb703b99 | ||
|
|
fa151cd320 | ||
|
|
a5bcf1a02d | ||
|
|
535e628eba | ||
|
|
edbfcda197 | ||
|
|
b8e35ed66c | ||
|
|
c548db513a | ||
|
|
476aabe671 | ||
|
|
969fc899a0 | ||
|
|
b61d89d01b | ||
|
|
bac7b3ab37 | ||
|
|
133a3e67d2 | ||
|
|
eb497be730 | ||
|
|
d553d7f772 | ||
|
|
5932db24e1 | ||
|
|
ddca4f9068 | ||
|
|
b244158b95 | ||
|
|
3bcc12869b | ||
|
|
6ee203a21d | ||
|
|
157d7c4f23 | ||
|
|
0d9f1ba95b | ||
|
|
a390f2e988 | ||
|
|
0faf6c8599 | ||
|
|
9ae2e3fba2 | ||
|
|
12b079df65 | ||
|
|
e920d9cdf3 | ||
|
|
542f363e92 | ||
|
|
40fa2d6779 | ||
|
|
3175bc1e48 | ||
|
|
62262a3572 | ||
|
|
6516a84986 | ||
|
|
16e887dcf0 | ||
|
|
63ffa4a212 | ||
|
|
539bf2ee24 | ||
|
|
deaeda59d0 | ||
|
|
4c0ff29488 | ||
|
|
7c28fe2795 | ||
|
|
deda2e158e | ||
|
|
a6e5cfff8a | ||
|
|
d1ea625435 | ||
|
|
ea551ab0a0 | ||
|
|
d9ae10f5bc | ||
|
|
d90211ef48 | ||
|
|
ace304914e | ||
|
|
6dc13b2c00 | ||
|
|
ca3617aa7d | ||
|
|
84ca7e8879 | ||
|
|
135b96a280 | ||
|
|
febf9cfafb | ||
|
|
27171ed974 | ||
|
|
2c346fdc08 | ||
|
|
229265cdd9 | ||
|
|
57234bc793 | ||
|
|
c687bb39ef | ||
|
|
d1a3545912 | ||
|
|
8d36c31cb4 | ||
|
|
08b2824ff0 | ||
|
|
b8b0ffb626 |
6
.gitattributes
vendored
Normal file
6
.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
deploy/data/windows/x64/tap/windows_7/OemVista.inf eol=crlf
|
||||
deploy/data/windows/x64/tap/windows_10/OemVista.inf eol=crlf
|
||||
deploy/data/windows/x32/tap/windows_7/OemVista.inf eol=crlf
|
||||
deploy/data/windows/x32/tap/windows_10/OemVista.inf eol=crlf
|
||||
client/3rd/* linguist-vendored
|
||||
client/android/gradlew.bat eol=crlf
|
||||
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**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.
|
||||
|
||||
**Log files**
|
||||
Attach log files to help explain your problem.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. Windows 10]
|
||||
- Version [e.g. 2.1.2]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Version [e.g. 2.1.2]
|
||||
|
||||
**Server (please complete the following information):**
|
||||
- OS: [e.g. Ubuntu 22.04]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
459
.github/workflows/deploy.yml
vendored
Normal file
459
.github/workflows/deploy.yml
vendored
Normal file
@@ -0,0 +1,459 @@
|
||||
name: 'Deploy workflow'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
env:
|
||||
QT_MIRROR: https://mirrors.ocf.berkeley.edu/qt/ # https://download.qt.io/static/mirrorlist/
|
||||
|
||||
jobs:
|
||||
Build-Linux-Ubuntu:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.6.2
|
||||
QIF_VERSION: 4.7
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
|
||||
steps:
|
||||
- name: 'Install Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'desktop'
|
||||
arch: 'gcc_64'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
tools: 'tools_ifw'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: 'Setup ccache'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Build project'
|
||||
run: |
|
||||
sudo apt-get install libxkbcommon-x11-0
|
||||
export QT_BIN_DIR=${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/gcc_64/bin
|
||||
export QIF_BIN_DIR=${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin
|
||||
bash deploy/build_linux.sh
|
||||
|
||||
- name: 'Pack installer'
|
||||
run: cd deploy && tar -cf AmneziaVPN_Linux_Installer.tar AmneziaVPN_Linux_Installer.bin
|
||||
|
||||
- name: 'Upload installer artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_Linux_installer.tar
|
||||
path: deploy/AmneziaVPN_Linux_Installer.tar
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload unpacked artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_Linux_unpacked
|
||||
path: deploy/AppDir
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload translations artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_translations
|
||||
path: client/translations
|
||||
retention-days: 7
|
||||
|
||||
# ------------------------------------------------------
|
||||
|
||||
Build-Windows:
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.6.2
|
||||
QIF_VERSION: 4.7
|
||||
BUILD_ARCH: 64
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
|
||||
steps:
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: 'Setup ccache'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Install Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'windows'
|
||||
target: 'desktop'
|
||||
arch: 'win64_msvc2019_64'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
tools: 'tools_ifw'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Setup mvsc'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: 'x64'
|
||||
|
||||
- name: 'Build project'
|
||||
shell: cmd
|
||||
run: |
|
||||
set BUILD_ARCH=${{ env.BUILD_ARCH }}
|
||||
set QT_BIN_DIR="${{ runner.temp }}\\Qt\\${{ env.QT_VERSION }}\\msvc2019_64\\bin"
|
||||
set QIF_BIN_DIR="${{ runner.temp }}\\Qt\\Tools\\QtInstallerFramework\\${{ env.QIF_VERSION }}\\bin"
|
||||
call deploy\\build_windows.bat
|
||||
|
||||
- name: 'Upload installer artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_Windows_installer
|
||||
path: AmneziaVPN_x${{ env.BUILD_ARCH }}.exe
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload unpacked artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_Windows_unpacked
|
||||
path: deploy\\build_${{ env.BUILD_ARCH }}\\client\\Release
|
||||
retention-days: 7
|
||||
|
||||
# ------------------------------------------------------
|
||||
|
||||
Build-iOS:
|
||||
runs-on: macos-13
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.6.2
|
||||
CC: cc
|
||||
CXX: c++
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
|
||||
steps:
|
||||
- name: 'Setup xcode'
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: '15.2'
|
||||
|
||||
- name: 'Install desktop Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'mac'
|
||||
target: 'desktop'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools qtmultimedia'
|
||||
arch: 'clang_64'
|
||||
dir: ${{ runner.temp }}
|
||||
set-env: 'true'
|
||||
extra: '--base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install iOS Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'mac'
|
||||
target: 'ios'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools qtmultimedia'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install go'
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.20'
|
||||
cache: false
|
||||
|
||||
- name: 'Setup gomobile'
|
||||
run: |
|
||||
export PATH=$PATH:~/go/bin
|
||||
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||
gomobile init
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: 'Setup ccache'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Install dependencies'
|
||||
run: pip install jsonschema jinja2
|
||||
|
||||
- name: 'Build project'
|
||||
run: |
|
||||
git submodule update --init --recursive
|
||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/ios/bin"
|
||||
export QT_MACOS_ROOT_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos"
|
||||
export PATH=$PATH:~/go/bin
|
||||
sh deploy/build_ios.sh
|
||||
env:
|
||||
IOS_TRUST_CERT_BASE64: ${{ secrets.IOS_TRUST_CERT_BASE64 }}
|
||||
IOS_SIGNING_CERT_BASE64: ${{ secrets.IOS_SIGNING_CERT_BASE64 }}
|
||||
IOS_SIGNING_CERT_PASSWORD: ${{ secrets.IOS_SIGNING_CERT_PASSWORD }}
|
||||
APPSTORE_CONNECT_KEY_ID: ${{ secrets.APPSTORE_CONNECT_KEY_ID }}
|
||||
APPSTORE_CONNECT_ISSUER_ID: ${{ secrets.APPSTORE_CONNECT_ISSUER_ID }}
|
||||
APPSTORE_CONNECT_PRIVATE_KEY: ${{ secrets.APPSTORE_CONNECT_PRIVATE_KEY }}
|
||||
IOS_APP_PROVISIONING_PROFILE: ${{ secrets.IOS_APP_PROVISIONING_PROFILE }}
|
||||
IOS_NE_PROVISIONING_PROFILE: ${{ secrets.IOS_NE_PROVISIONING_PROFILE }}
|
||||
|
||||
# - name: 'Upload appstore .ipa and dSYMs to artifacts'
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: app-store ipa & dsyms
|
||||
# path: |
|
||||
# ${{ github.workspace }}/AmneziaVPN-iOS.ipa
|
||||
# ${{ github.workspace }}/*.app.dSYM.zip
|
||||
# retention-days: 7
|
||||
|
||||
# ------------------------------------------------------
|
||||
|
||||
Build-MacOS:
|
||||
runs-on: macos-latest
|
||||
|
||||
env:
|
||||
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
|
||||
QT_VERSION: 6.4.3
|
||||
QIF_VERSION: 4.6
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
|
||||
steps:
|
||||
- name: 'Setup xcode'
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: '14.3.1'
|
||||
|
||||
- name: 'Install Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'mac'
|
||||
target: 'desktop'
|
||||
arch: 'clang_64'
|
||||
modules: 'qtremoteobjects qt5compat qtshadertools'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}'
|
||||
run: |
|
||||
mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework
|
||||
wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip
|
||||
unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: 'Setup ccache'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Build project'
|
||||
run: |
|
||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
||||
export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin"
|
||||
bash deploy/build_macos.sh
|
||||
|
||||
- name: 'Upload installer artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_MacOS_installer
|
||||
path: AmneziaVPN.dmg
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload unpacked artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_MacOS_unpacked
|
||||
path: deploy/build/client/AmneziaVPN.app
|
||||
retention-days: 7
|
||||
|
||||
# ------------------------------------------------------
|
||||
|
||||
Build-Android:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
ANDROID_BUILD_PLATFORM: android-34
|
||||
QT_VERSION: 6.6.2
|
||||
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
|
||||
steps:
|
||||
- name: 'Install desktop Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'desktop'
|
||||
arch: 'gcc_64'
|
||||
modules: ${{ env.QT_MODULES }}
|
||||
dir: ${{ runner.temp }}
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install android_x86_64 Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_x86_64'
|
||||
modules: ${{ env.QT_MODULES }}
|
||||
dir: ${{ runner.temp }}
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install android_x86 Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_x86'
|
||||
modules: ${{ env.QT_MODULES }}
|
||||
dir: ${{ runner.temp }}
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install android_armv7 Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_armv7'
|
||||
modules: ${{ env.QT_MODULES }}
|
||||
dir: ${{ runner.temp }}
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install android_arm64_v8a Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_arm64_v8a'
|
||||
modules: ${{ env.QT_MODULES }}
|
||||
dir: ${{ runner.temp }}
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Grant execute permission for qt-cmake'
|
||||
shell: bash
|
||||
run: |
|
||||
chmod +x ${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/android_x86_64/bin/qt-cmake
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
|
||||
- name: 'Setup ccache'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Setup Java'
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
cache: 'gradle'
|
||||
|
||||
- name: 'Setup Android NDK'
|
||||
id: setup-ndk
|
||||
uses: nttld/setup-ndk@v1
|
||||
with:
|
||||
ndk-version: 'r26b'
|
||||
|
||||
- name: 'Decode keystore secret to file'
|
||||
env:
|
||||
KEYSTORE_BASE64: ${{ secrets.ANDROID_RELEASE_KEYSTORE_BASE64 }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo $KEYSTORE_BASE64 | base64 --decode > android.keystore
|
||||
|
||||
- name: 'Build project'
|
||||
env:
|
||||
ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
QT_HOST_PATH: ${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/gcc_64
|
||||
ANDROID_KEYSTORE_PATH: ${{ github.workspace }}/android.keystore
|
||||
ANDROID_KEYSTORE_KEY_ALIAS: ${{ secrets.ANDROID_RELEASE_KEYSTORE_KEY_ALIAS }}
|
||||
ANDROID_KEYSTORE_KEY_PASS: ${{ secrets.ANDROID_RELEASE_KEYSTORE_KEY_PASS }}
|
||||
shell: bash
|
||||
run: ./deploy/build_android.sh --aab --apk all --build-platform ${{ env.ANDROID_BUILD_PLATFORM }}
|
||||
|
||||
- name: 'Upload x86_64 apk'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN-android-x86_64
|
||||
path: deploy/build/AmneziaVPN-x86_64-release.apk
|
||||
compression-level: 0
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload x86 apk'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN-android-x86
|
||||
path: deploy/build/AmneziaVPN-x86-release.apk
|
||||
compression-level: 0
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload arm64-v8a apk'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN-android-arm64-v8a
|
||||
path: deploy/build/AmneziaVPN-arm64-v8a-release.apk
|
||||
compression-level: 0
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload armeabi-v7a apk'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN-android-armeabi-v7a
|
||||
path: deploy/build/AmneziaVPN-armeabi-v7a-release.apk
|
||||
compression-level: 0
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload aab'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN-android
|
||||
path: deploy/build/AmneziaVPN-release.aab
|
||||
compression-level: 0
|
||||
retention-days: 7
|
||||
|
||||
Extra:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Search a corresponding PR
|
||||
uses: octokit/request-action@v2.x
|
||||
id: pull_request
|
||||
with:
|
||||
route: GET /repos/${{ github.repository }}/pulls
|
||||
head: ${{ github.repository_owner }}:${{ github.ref_name }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Add PR link to build summary
|
||||
if: ${{ fromJSON(steps.pull_request.outputs.data)[0].number != '' }}
|
||||
run: |
|
||||
echo "Pull request:" >> $GITHUB_STEP_SUMMARY
|
||||
echo "[[#${{ fromJSON(steps.pull_request.outputs.data)[0].number }}] ${{ fromJSON(steps.pull_request.outputs.data)[0].title }}](${{ fromJSON(steps.pull_request.outputs.data)[0].html_url }})" >> $GITHUB_STEP_SUMMARY
|
||||
143
.github/workflows/tag-deploy.yml
vendored
Normal file
143
.github/workflows/tag-deploy.yml
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
name: 'Release deploy workflow'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# push:
|
||||
# tags:
|
||||
# - **
|
||||
|
||||
jobs:
|
||||
|
||||
Build-Android-Release:
|
||||
name: 'Build-Android-Release'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.4.1
|
||||
QIF_VERSION: 4.5
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
|
||||
steps:
|
||||
- name: 'Install desktop Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'desktop'
|
||||
arch: 'gcc_64'
|
||||
modules: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
|
||||
- name: 'Install android Qt x86_64'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_x86_64'
|
||||
modules: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
|
||||
- name: 'Install android Qt x86'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_x86'
|
||||
modules: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
|
||||
- name: 'Install android Qt arm_v7'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_armv7'
|
||||
modules: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
|
||||
- name: 'Install android Qt arm_v8'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_arm64_v8a'
|
||||
modules: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: main
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: 'Preparations before keystore fetching'
|
||||
run: |
|
||||
mkdir keystore
|
||||
|
||||
- name: 'Getting keystore'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: amnezia-vpn/amnezia-android-certificates
|
||||
ssh-key: ${{ secrets.ANDROID_CERTS_SSH_PRIVATE_KEY }}
|
||||
path: keystore
|
||||
|
||||
- name: 'Setup ccache'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Setup Java'
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
|
||||
- name: 'Build project'
|
||||
run: |
|
||||
export QT_HOST_PATH="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/gcc_64"
|
||||
export NDK_VERSION=23c
|
||||
export ANDROID_NDK_PLATFORM=android-23
|
||||
export ANDROID_NDK_HOME=${{ runner.temp }}/android-ndk-r${NDK_VERSION}
|
||||
export ANDROID_NDK_ROOT=$ANDROID_NDK_HOME
|
||||
|
||||
if [ ! -f $ANDROID_NDK_ROOT/ndk-build ]; then
|
||||
wget https://dl.google.com/android/repository/android-ndk-r${NDK_VERSION}-linux.zip -qO ${{ runner.temp }}/ndk.zip &&
|
||||
unzip -q -d ${{ runner.temp }} ${{ runner.temp }}/ndk.zip ;
|
||||
fi
|
||||
|
||||
export QT_BIN_DIR=${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/android_arm64_v8a/bin
|
||||
cd main
|
||||
bash deploy/build_android.sh
|
||||
|
||||
- name: 'Signing APK'
|
||||
run: |
|
||||
pwd
|
||||
|
||||
ANDROID_BUILD_TOOLS_VERSION=30.0.3
|
||||
|
||||
${ANDROID_HOME}/build-tools/${ANDROID_BUILD_TOOLS_VERSION}/zipalign -f -v 4 AmneziaVPN-release-unsigned.apk AmneziaVPN-release-aligned.apk
|
||||
${ANDROID_HOME}/build-tools/${ANDROID_BUILD_TOOLS_VERSION}/apksigner sign --out AmneziaVPN-release-signed.apk --ks keystore/debug.keystore --ks-key-alias ${{ secrets.DEBUG_ANDROID_KEYSTORE_KEY_ALIAS }} --ks-pass pass:${{secrets.DEBUG_ANDROID_KEYSTOTE_KEY_PASS }} AmneziaVPN-release-aligned.apk
|
||||
|
||||
- name: 'Upload'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Release APK
|
||||
path: ${{ runner.temp }}/main/AmneziaVPN-release-signed.apk
|
||||
64
.github/workflows/tag-upload.yml
vendored
Normal file
64
.github/workflows/tag-upload.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: 'Upload a new version'
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+.[0-9]+.[0-9]+'
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
name: upload
|
||||
steps:
|
||||
- name: Checkout CMakeLists.txt
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref_name }}
|
||||
sparse-checkout: |
|
||||
CMakeLists.txt
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Verify git tag
|
||||
run: |
|
||||
GIT_TAG=${{ github.ref_name }}
|
||||
CMAKE_TAG=$(grep 'project.*VERSION' CMakeLists.txt | sed -E 's/.* ([0-9]+.[0-9]+.[0-9]+.[0-9]+)$/\1/')
|
||||
|
||||
if [[ "$GIT_TAG" == "$CMAKE_TAG" ]]; then
|
||||
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are the same. Continuing..."
|
||||
else
|
||||
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are not the same! Cancelling..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download artifacts from the "${{ github.ref_name }}" tag
|
||||
uses: robinraju/release-downloader@v1.8
|
||||
with:
|
||||
tag: ${{ github.ref_name }}
|
||||
fileName: "AmneziaVPN_(Linux_|)${{ github.ref_name }}*"
|
||||
out-file-path: ${{ github.ref_name }}
|
||||
|
||||
- name: Upload beta version
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
if: contains(github.event.base_ref, 'dev')
|
||||
with:
|
||||
args: --include "AmneziaVPN*" --delete
|
||||
env:
|
||||
AWS_S3_BUCKET: updates
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
|
||||
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
|
||||
SOURCE_DIR: ${{ github.ref_name }}
|
||||
DEST_DIR: beta/${{ github.ref_name }}
|
||||
|
||||
- name: Upload stable version
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
if: contains(github.event.base_ref, 'master')
|
||||
with:
|
||||
args: --include "AmneziaVPN*" --delete
|
||||
env:
|
||||
AWS_S3_BUCKET: updates
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
|
||||
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
|
||||
SOURCE_DIR: ${{ github.ref_name }}
|
||||
DEST_DIR: stable/${{ github.ref_name }}
|
||||
90
.gitignore
vendored
90
.gitignore
vendored
@@ -8,6 +8,8 @@ deploy/build/*
|
||||
deploy/build_32/*
|
||||
deploy/build_64/*
|
||||
winbuild*.bat
|
||||
.cache/
|
||||
|
||||
|
||||
# Qt-es
|
||||
/.qmake.cache
|
||||
@@ -22,7 +24,39 @@ qrc_*.cpp
|
||||
ui_*.h
|
||||
Makefile*
|
||||
*build-*
|
||||
compile_commands.json
|
||||
|
||||
# fastlane
|
||||
client/fastlane/report.xml
|
||||
client/fastlane/build/*
|
||||
|
||||
# Qt-es
|
||||
client/Release-iphoneos/
|
||||
client/Debug-iphoneos/
|
||||
client/.xcode/
|
||||
client/.qmake.cache
|
||||
client/.qmake.stash
|
||||
client/*.pro.user
|
||||
client/*.pro.user.*
|
||||
client/*.qbs.user
|
||||
client/*.qbs.user.*
|
||||
client/*.moc
|
||||
client/moc_*.cpp
|
||||
client/qrc_*.cpp
|
||||
client/ui_*.h
|
||||
client/ui_*.cpp
|
||||
client/Makefile*
|
||||
client/fastlane/build/
|
||||
client/*build-*
|
||||
client/AmneziaVPN.xcodeproj
|
||||
client/Debug-iphonesimulator/
|
||||
client/amneziavpn_plugin_import.cpp
|
||||
client/amneziavpn_qml_plugin_import.cpp
|
||||
client/qmlcache_loader.cpp
|
||||
client/rep_ipc_interface_replica.h
|
||||
client/resources_qmlcache.qrc
|
||||
client/3rd/OpenVPNAdpter/build/
|
||||
client/3rd/ShadowSocks/build/
|
||||
# QtCreator
|
||||
|
||||
*.autosave
|
||||
@@ -34,8 +68,15 @@ Makefile*
|
||||
# QtCtreator CMake
|
||||
CMakeLists.txt.user*
|
||||
|
||||
# Linux files
|
||||
*.7z
|
||||
deploy/AppDir
|
||||
deploy/Tools
|
||||
deploy/AmneziaVPN*Installer*
|
||||
|
||||
# MACOS files
|
||||
.DS_Store
|
||||
client/.DS_Store
|
||||
._.DS_Store
|
||||
._*
|
||||
*.dmg
|
||||
@@ -43,4 +84,53 @@ CMakeLists.txt.user*
|
||||
# tmp files
|
||||
*.*~
|
||||
|
||||
######################### Android
|
||||
# Built application files
|
||||
*.apk
|
||||
*.aar
|
||||
*.ap_
|
||||
*.aab
|
||||
|
||||
# Files for the ART/Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Android Studio Navigation editor temp files
|
||||
.navigation/
|
||||
|
||||
# Android Studio captures folder
|
||||
captures/
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea/
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||
#*.jks
|
||||
#*.keystore
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
|
||||
# Android Profiling
|
||||
*.hprof
|
||||
client/3rd/ShadowSocks/ss_ios.xcconfig
|
||||
|
||||
# UML generated pics
|
||||
out/
|
||||
|
||||
# CMake files
|
||||
CMakeFiles/
|
||||
@@ -1,27 +0,0 @@
|
||||
variables:
|
||||
GIT_STRATEGY: clone
|
||||
|
||||
stages:
|
||||
- build
|
||||
|
||||
build-windows:
|
||||
stage: build
|
||||
tags:
|
||||
- windows
|
||||
script:
|
||||
- cmd.exe /k "deploy\windows-env.bat && cd deploy && windows.bat"
|
||||
artifacts:
|
||||
name: artifacts-windows
|
||||
paths:
|
||||
- AmneziaVPN.exe
|
||||
|
||||
build-macos:
|
||||
stage: build
|
||||
tags:
|
||||
- macos
|
||||
script:
|
||||
- cd deploy && ./macos.sh
|
||||
artifacts:
|
||||
name: artifacts-macos
|
||||
paths:
|
||||
- AmneziaVPN.dmg
|
||||
24
.gitmodules
vendored
24
.gitmodules
vendored
@@ -1,3 +1,21 @@
|
||||
[submodule "3rd/QtSsh"]
|
||||
path = 3rd/QtSsh
|
||||
url = https://github.com/amnezia-vpn/QtSsh.git
|
||||
[submodule "client/3rd/OpenVPNAdapter"]
|
||||
path = client/3rd/OpenVPNAdapter
|
||||
url = https://github.com/amnezia-vpn/OpenVPNAdapter.git
|
||||
[submodule "client/3rd/qtkeychain"]
|
||||
path = client/3rd/qtkeychain
|
||||
url = https://github.com/frankosterfeld/qtkeychain.git
|
||||
[submodule "client/3rd/SortFilterProxyModel"]
|
||||
path = client/3rd/SortFilterProxyModel
|
||||
url = https://github.com/mitchcurtis/SortFilterProxyModel.git
|
||||
[submodule "client/3rd-prebuilt"]
|
||||
path = client/3rd-prebuilt
|
||||
url = https://github.com/amnezia-vpn/3rd-prebuilt
|
||||
[submodule "client/3rd/amneziawg-apple"]
|
||||
path = client/3rd/amneziawg-apple
|
||||
url = https://github.com/amnezia-vpn/amneziawg-apple
|
||||
[submodule "client/3rd/QSimpleCrypto"]
|
||||
path = client/3rd/QSimpleCrypto
|
||||
url = https://github.com/amnezia-vpn/QSimpleCrypto.git
|
||||
[submodule "client/3rd/SingleApplication"]
|
||||
path = client/3rd/SingleApplication
|
||||
url = git@github.com:itay-grudev/SingleApplication.git
|
||||
|
||||
47
.gitpod.Dockerfile
vendored
Normal file
47
.gitpod.Dockerfile
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
FROM gitpod/workspace-full-vnc
|
||||
|
||||
USER gitpod
|
||||
|
||||
RUN sudo apt-get -q update \
|
||||
&& sudo apt-get install -yq \
|
||||
build-essential \
|
||||
libgl1-mesa-dev \
|
||||
libgstreamer-gl1.0-0 \
|
||||
libpulse-dev \
|
||||
libsecret-1-dev \
|
||||
libxcb-glx0 \
|
||||
libxcb-icccm4 \
|
||||
libxcb-image0 \
|
||||
libxcb-keysyms1 \
|
||||
libxcb-randr0 \
|
||||
libxcb-render-util0 \
|
||||
libxcb-render0 \
|
||||
libxcb-shape0 \
|
||||
libxcb-shm0 \
|
||||
libxcb-sync1 \
|
||||
libxcb-util1 \
|
||||
libxcb-xfixes0 \
|
||||
libxcb-xinerama0 \
|
||||
libxcb1 \
|
||||
libxkbcommon-dev \
|
||||
libxkbcommon-x11-0 \
|
||||
libxcb-xkb-dev \
|
||||
p7zip-full \
|
||||
&& sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN sudo pip3 install aqtinstall
|
||||
|
||||
ARG QT_VERSION=6.4.1
|
||||
ARG QT_ARCH=gcc_64
|
||||
|
||||
ARG QT_DIR=/opt/qt
|
||||
RUN sudo aqt install-qt --outputdir ${QT_DIR} linux desktop ${QT_VERSION} ${QT_ARCH} --modules \
|
||||
qtremoteobjects \
|
||||
qt5compat \
|
||||
qtshadertools
|
||||
ENV QT_BIN_DIR=${QT_DIR}/${QT_VERSION}/${QT_ARCH}/bin
|
||||
|
||||
ARG QIF_VERSION=4.5
|
||||
ARG QIF_DIR=/opt/qif
|
||||
RUN sudo aqt install-tool --outputdir ${QIF_DIR} linux desktop tools_ifw
|
||||
ENV QIF_BIN_DIR=${QIF_DIR}/Tools/QtInstallerFramework/${QIF_VERSION}/bin
|
||||
8
.gitpod.yml
Normal file
8
.gitpod.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
tasks:
|
||||
- init: >-
|
||||
deploy/build_linux.sh
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
vscode:
|
||||
extensions:
|
||||
- llvm-vs-code-extensions.vscode-clangd
|
||||
144
.travis.yml
144
.travis.yml
@@ -1,144 +0,0 @@
|
||||
language: cpp
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- dev
|
||||
- /\d+\.\d+/
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- name: MacOS
|
||||
os: osx
|
||||
osx_image: xcode12.5
|
||||
|
||||
env:
|
||||
- QT_VERSION=5.15.2
|
||||
- QIF_VERSION=4.1
|
||||
- QT_BIN_DIR=$HOME/Qt/$QT_VERSION/clang_64/bin
|
||||
- QIF_BIN_DIR=$QT_BIN_DIR/../../../Tools/QtInstallerFramework/$QIF_VERSION/bin
|
||||
|
||||
script:
|
||||
- |
|
||||
if [ ! -f $HOME/Qt/$QT_VERSION/clang_64/bin/qmake ]; then \
|
||||
brew install p7zip && \
|
||||
python3 -m pip install --upgrade pip && \
|
||||
pip install -U aqtinstall requests py7zr && \
|
||||
pip show aqtinstall && \
|
||||
python3 -m aqt install --outputdir $HOME/Qt $QT_VERSION mac desktop clang_64 -m qtbase && \
|
||||
python3 -m aqt tool --outputdir $HOME/Qt mac tools_ifw $QIF_VERSION qt.tools.ifw.${QIF_VERSION/./};
|
||||
fi
|
||||
- bash deploy/build_macos.sh
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
token: $GH_TOKEN
|
||||
skip_cleanup: true
|
||||
file:
|
||||
- "AmneziaVPN_unsigned.dmg"
|
||||
on:
|
||||
tags: true
|
||||
branch: master
|
||||
|
||||
- name: Windows_x64
|
||||
os: windows
|
||||
|
||||
env:
|
||||
- PATH=/c/Python39:/c/Python39/Scripts:$PATH
|
||||
- QT_VERSION=5.14.2
|
||||
- QIF_VERSION=4.1
|
||||
- QT_BIN_DIR="c:\\Qt\\$QT_VERSION\\msvc2017_64\\bin"
|
||||
- QIF_BIN_DIR="c:\\Qt\\Tools\\QtInstallerFramework\\${QIF_VERSION}\\bin"
|
||||
- BUILD_ARCH=64
|
||||
|
||||
before_install:
|
||||
- if [ ! -f /C/Qt/$QT_VERSION/msvc2017_64/bin/qmake ]; then choco install python --version 3.9.1; fi
|
||||
|
||||
script:
|
||||
- dir "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build"
|
||||
- dir "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\Common7\Tools"
|
||||
- |
|
||||
if [ ! -f /C/Qt/$QT_VERSION/msvc2017_64/bin/qmake ]; then \
|
||||
python -m pip install --upgrade pip && \
|
||||
pip3 install -U aqtinstall requests py7zr && \
|
||||
pip3 show aqtinstall && \
|
||||
python -m aqt install --outputdir /C/Qt $QT_VERSION windows desktop win64_msvc2017_64 -m qtbase && \
|
||||
python -m aqt tool --outputdir /C/Qt windows tools_ifw $QIF_VERSION qt.tools.ifw.${QIF_VERSION/./}; \
|
||||
fi
|
||||
- echo set BUILD_ARCH=$BUILD_ARCH > winbuild.bat
|
||||
- echo set QT_BIN_DIR="$QT_BIN_DIR" >> winbuild.bat
|
||||
- echo set QIF_BIN_DIR="$QIF_BIN_DIR" >> winbuild.bat
|
||||
- echo call \""C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\VC\\Auxiliary\\Build\\vcvars${BUILD_ARCH}.bat\"" >> winbuild.bat
|
||||
- echo call \""C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\Common7\\Tools\\VsDevCmd.bat\" -arch=amd64" >> winbuild.bat
|
||||
- echo set WIN_CERT_PW=$WIN_CERT_PW >> winbuild.bat
|
||||
- echo call deploy\\build_windows.bat >> winbuild.bat
|
||||
- cmd //c winbuild.bat
|
||||
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
token: $GH_TOKEN
|
||||
skip_cleanup: true
|
||||
file:
|
||||
- "AmneziaVPN_x64.exe"
|
||||
on:
|
||||
tags: true
|
||||
branch: master
|
||||
|
||||
- name: Windows_x32
|
||||
os: windows
|
||||
|
||||
env:
|
||||
- PATH=/c/Python39:/c/Python39/Scripts:$PATH
|
||||
- QT_VERSION=5.14.2
|
||||
- QIF_VERSION=4.1
|
||||
- QT_BIN_DIR="c:\\Qt\\${QT_VERSION}\\msvc2017\\bin"
|
||||
- QIF_BIN_DIR="c:\\Qt\\Tools\\QtInstallerFramework\\${QIF_VERSION}\\bin"
|
||||
- BUILD_ARCH=32
|
||||
|
||||
before_install:
|
||||
- if [ ! -f /C/Qt/$QT_VERSION/msvc2017/bin/qmake ]; then choco install python --version 3.9.1; fi
|
||||
|
||||
script:
|
||||
- dir "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build"
|
||||
- dir "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\Common7\Tools"
|
||||
- |
|
||||
if [ ! -f /C/Qt/$QT_VERSION/msvc2017/bin/qmake ]; then \
|
||||
python -m pip install --upgrade pip && \
|
||||
pip3 install -U aqtinstall requests py7zr && \
|
||||
pip3 show aqtinstall && \
|
||||
python -m aqt install --outputdir /C/Qt $QT_VERSION windows desktop win32_msvc2017 -m qtbase && \
|
||||
python -m aqt tool --outputdir /C/Qt windows tools_ifw $QIF_VERSION qt.tools.ifw.${QIF_VERSION/./}; \
|
||||
fi
|
||||
- echo call \""C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\Common7\\Tools\\VsDevCmd.bat\"" > winbuild.bat
|
||||
- echo set BUILD_ARCH=$BUILD_ARCH >> winbuild.bat
|
||||
- echo set QT_BIN_DIR="$QT_BIN_DIR" >> winbuild.bat
|
||||
- echo set QIF_BIN_DIR="$QIF_BIN_DIR" >> winbuild.bat
|
||||
- echo call \""C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\VC\\Auxiliary\\Build\\vcvars${BUILD_ARCH}.bat\"" >> winbuild.bat
|
||||
- echo set WIN_CERT_PW=$WIN_CERT_PW >> winbuild.bat
|
||||
- echo call deploy\\build_windows.bat >> winbuild.bat
|
||||
- cmd //c winbuild.bat
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
token: $GH_TOKEN
|
||||
skip_cleanup: true
|
||||
file:
|
||||
- "AmneziaVPN_x32.exe"
|
||||
on:
|
||||
tags: true
|
||||
branch: master
|
||||
|
||||
deploy:
|
||||
skip_cleanup: true
|
||||
|
||||
before_cache:
|
||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew cleanup; fi
|
||||
# Cache only .git files under "/usr/local/Homebrew" so "brew update" does not take 5min every build
|
||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then find /usr/local/Homebrew \! -regex ".+\.git.+" -delete; fi
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/Qt
|
||||
- /C/Qt
|
||||
- $HOME/Library/Caches/Homebrew
|
||||
@@ -1,3 +0,0 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = client service platform
|
||||
|
||||
44
CMakeLists.txt
Normal file
44
CMakeLists.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
|
||||
project(${PROJECT} VERSION 4.7.0.0
|
||||
DESCRIPTION "AmneziaVPN"
|
||||
HOMEPAGE_URL "https://amnezia.org/"
|
||||
)
|
||||
|
||||
string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||
|
||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
set(APP_ANDROID_VERSION_CODE 57)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(MZ_PLATFORM_NAME "linux")
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
set(MZ_PLATFORM_NAME "windows")
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
set(MZ_PLATFORM_NAME "macos")
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
|
||||
set(MZ_PLATFORM_NAME "android")
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "iOS")
|
||||
set(MZ_PLATFORM_NAME "ios")
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
|
||||
set(MZ_PLATFORM_NAME "wasm")
|
||||
endif()
|
||||
|
||||
set(QT_BUILD_TOOLS_WHEN_CROSS_COMPILING ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(APPLE AND NOT IOS)
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64")
|
||||
endif()
|
||||
|
||||
add_subdirectory(client)
|
||||
|
||||
if(NOT IOS AND NOT ANDROID)
|
||||
add_subdirectory(service)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/deploy/installer/config.cmake)
|
||||
endif()
|
||||
192
README.md
192
README.md
@@ -1,50 +1,194 @@
|
||||
# Amnezia VPN
|
||||
## _The best client for self-hosted VPN_
|
||||
|
||||
[](https://travis-ci.com/amnezia-vpn/desktop-client)
|
||||
[](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml?query=branch:dev)
|
||||
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
|
||||
|
||||
Amnezia is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
|
||||
|
||||

|
||||
|
||||
<br>
|
||||
|
||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.6.0.3/AmneziaVPN_4.6.0.3_x64.exe"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/win.png" width="150" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.6.0.3/AmneziaVPN_4.6.0.3.dmg"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/mac.png" width="150" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.6.0.3/AmneziaVPN_Linux_4.6.0.3.tar.zip"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/lin.png" width="150" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/tag/4.6.0.3"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/andr.png" width="150" style="max-width: 100%;"></a>
|
||||
|
||||
<br>
|
||||
|
||||
<a href="https://play.google.com/store/search?q=amnezia+vpn&c=apps"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/play.png" width="150" style="max-width: 100%;"></a>
|
||||
<a href="https://apps.apple.com/us/app/amneziavpn/id1600529900"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/apl.png" width="150" style="max-width: 100%;"></a>
|
||||
|
||||
|
||||
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
|
||||
|
||||
<br>
|
||||
|
||||
Amnezia is a VPN client with the key feature of deploying your own VPN server on you virtual server.
|
||||
|
||||
## Features
|
||||
- Very easy to use - enter your ip address, ssh login and password, and Amnezia client will automatically install VPN docker containers to your server and connect to VPN.
|
||||
- OpenVPN and OpenVPN over ShadowSocks protocols support.
|
||||
- Custom VPN routing mode support - add any sites to client to enable VPN only for them.
|
||||
- Windows and MacOS support.
|
||||
- Unsecure sharing connection profile for family use.
|
||||
|
||||
- Very easy to use - enter your IP address, SSH login, password and Amnezia will automatically install VPN docker containers to your server and connect to the VPN.
|
||||
- Classic VPN-protocols: OpenVPN, WireGuard and IKEv2 protocols.
|
||||
- Protocols with traffic Masking (Obfuscation): OpenVPN over [Cloak](https://github.com/cbeuw/Cloak) plugin, Shadowsocks (OpenVPN over Shadowsocks), [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/) and XRay.
|
||||
- Split tunneling support - add any sites to the client to enable VPN only for them or add Apps (only for Android and Desktop).
|
||||
- Windows, MacOS, Linux, Android, iOS releases.
|
||||
- Support for AmneziaWG protocol configuration on [Keenetic beta firmware](https://docs.keenetic.com/ua/air/kn-1611/en/6319-latest-development-release.html#UUID-186c4108-5afd-c10b-f38a-cdff6c17fab3_section-idm33192196168192-improved).
|
||||
|
||||
## Links
|
||||
|
||||
- [https://amnezia.org](https://amnezia.org) - project website
|
||||
- [https://www.reddit.com/r/AmneziaVPN](https://www.reddit.com/r/AmneziaVPN) - Reddit
|
||||
- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Telegram support channel (English)
|
||||
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Telegram support channel (Farsi)
|
||||
- [https://t.me/amnezia_vpn_mm](https://t.me/amnezia_vpn_mm) - Telegram support channel (Myanmar)
|
||||
- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Telegram support channel (Russian)
|
||||
- [https://vpnpay.io/en/amnezia-premium/](https://vpnpay.io/en/amnezia-premium/) - Amnezia Premium
|
||||
|
||||
## Tech
|
||||
|
||||
AmneziaVPN uses a number of open source projects to work:
|
||||
AmneziaVPN uses several open-source projects to work:
|
||||
|
||||
- [OpenSSL](https://www.openssl.org/)
|
||||
- [OpenVPN](https://openvpn.net/)
|
||||
- [ShadowSocks](https://shadowsocks.org/)
|
||||
- [Shadowsocks](https://shadowsocks.org/)
|
||||
- [Qt](https://www.qt.io/)
|
||||
- [EasyRSA](https://github.com/OpenVPN/easy-rsa) - part of OpenVPN
|
||||
- [CygWin](https://www.cygwin.com/) - only for Windiws, used for launching EasyRSA scripts
|
||||
- [QtSsh](https://github.com/jaredtao/QtSsh) - forked form Qt Creator
|
||||
- [LibSsh](https://libssh.org) - forked from Qt Creator
|
||||
- and more...
|
||||
|
||||
## Checking out the source code
|
||||
|
||||
Make sure to pull all submodules after checking out the repo.
|
||||
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
Want to contribute? Welcome!
|
||||
|
||||
### Help with translations
|
||||
|
||||
Download the most actual translation files.
|
||||
|
||||
Go to ["Actions" tab](https://github.com/amnezia-vpn/amnezia-client/actions?query=is%3Asuccess+branch%3Adev), click on the first line.
|
||||
Then scroll down to the "Artifacts" section and download "AmneziaVPN_translations".
|
||||
|
||||
Unzip this file.
|
||||
Each *.ts file contains strings for one corresponding language.
|
||||
|
||||
Translate or correct some strings in one or multiple *.ts files and commit them back to this repository into the ``client/translations`` folder.
|
||||
You can do it via a web-interface or any other method you're familiar with.
|
||||
|
||||
### Building sources and deployment
|
||||
Easiest way to build your own executables - is to fork project and configure [Travis CI](https://travis-ci.com/)
|
||||
Or you can build sources manually using Qt Creator. Qt >= 14.2 supported.
|
||||
Look to the `build_macos.sh` and `build_windows.bat` scripts in `deploy` folder for details.
|
||||
|
||||
Check deploy folder for build scripts.
|
||||
|
||||
### How to build an iOS app from source code on MacOS
|
||||
|
||||
1. First, make sure you have [XCode](https://developer.apple.com/xcode/) installed, at least version 14 or higher.
|
||||
|
||||
2. We use QT to generate the XCode project. We need QT version 6.6.2. Install QT for MacOS [here](https://doc.qt.io/qt-6/macos.html) or [QT Online Installer](https://www.qt.io/download-open-source). Required modules:
|
||||
- MacOS
|
||||
- iOS
|
||||
- Qt 5 Compatibility Module
|
||||
- Qt Shader Tools
|
||||
- Additional Libraries:
|
||||
- Qt Image Formats
|
||||
- Qt Multimedia
|
||||
- Qt Remote Objects
|
||||
|
||||
3. Install CMake if required. We recommend CMake version 3.25. You can install CMake [here](https://cmake.org/download/)
|
||||
|
||||
4. You also need to install go >= v1.16. If you don't have it installed already,
|
||||
download go from the [official website](https://golang.org/dl/) or use Homebrew.
|
||||
The latest version is recommended. Install gomobile
|
||||
```bash
|
||||
export PATH=$PATH:~/go/bin
|
||||
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||
gomobile init
|
||||
```
|
||||
|
||||
5. Build the project
|
||||
```bash
|
||||
export QT_BIN_DIR="<PATH-TO-QT-FOLDER>/Qt/<QT-VERSION>/ios/bin"
|
||||
export QT_MACOS_ROOT_DIR="<PATH-TO-QT-FOLDER>/Qt/<QT-VERSION>/macos"
|
||||
export QT_IOS_BIN=$QT_BIN_DIR
|
||||
export PATH=$PATH:~/go/bin
|
||||
mkdir build-ios
|
||||
$QT_IOS_BIN/qt-cmake . -B build-ios -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR
|
||||
```
|
||||
Replace PATH-TO-QT-FOLDER and QT-VERSION to your environment
|
||||
|
||||
|
||||
If you get `gomobile: command not found` make sure to set PATH to the location
|
||||
of the bin folder where gomobile was installed. Usually, it's in `GOPATH`.
|
||||
```bash
|
||||
export PATH=$(PATH):/path/to/GOPATH/bin
|
||||
```
|
||||
|
||||
6. Open the XCode project. You can then run /test/archive/ship the app.
|
||||
|
||||
If the build fails with the following error
|
||||
```
|
||||
make: ***
|
||||
[$(PROJECTDIR)/client/build/AmneziaVPN.build/Debug-iphoneos/wireguard-go-bridge/goroot/.prepared]
|
||||
Error 1
|
||||
```
|
||||
Add a user-defined variable to both AmneziaVPN and WireGuardNetworkExtension targets' build settings with
|
||||
key `PATH` and value `${PATH}/path/to/bin/folder/with/go/executable`, e.g. `${PATH}:/usr/local/go/bin`.
|
||||
|
||||
if the above error persists on your M1 Mac, then most probably you need to install arch based CMake
|
||||
```
|
||||
arch -arm64 brew install cmake
|
||||
```
|
||||
|
||||
Build might fail with the "source files not found" error the first time you try it, because the modern XCode build system compiles dependencies in parallel, and some dependencies end up being built after the ones that
|
||||
require them. In this case, simply restart the build.
|
||||
|
||||
## How to build the Android app
|
||||
|
||||
_Tested on Mac OS_
|
||||
|
||||
The Android app has the following requirements:
|
||||
* JDK 11
|
||||
* Android platform SDK 33
|
||||
* CMake 3.25.0
|
||||
|
||||
After you have installed QT, QT Creator, and Android Studio, you need to configure QT Creator correctly.
|
||||
|
||||
- Click in the top menu bar on `QT Creator` -> `Preferences` -> `Devices` and select the tab `Android`.
|
||||
- Set path to JDK 11
|
||||
- Set path to Android SDK (`$ANDROID_HOME`)
|
||||
|
||||
In case you get errors regarding missing SDK or 'SDK manager not running', you cannot fix them by correcting the paths. If you have some spare GBs on your disk, you can let QT Creator install all requirements by choosing an empty folder for `Android SDK location` and clicking on `Set Up SDK`. Be aware: This will install a second Android SDK and NDK on your machine!
|
||||
Double-check that the right CMake version is configured: Click on `QT Creator` -> `Preferences` and click on the side menu on `Kits`. Under the center content view's `Kits` tab, you'll find an entry for `CMake Tool`. If the default selected CMake version is lower than 3.25.0, install on your system CMake >= 3.25.0 and choose `System CMake at <path>` from the drop-down list. If this entry is missing, you either have not installed CMake yet or QT Creator hasn't found the path to it. In that case, click in the preferences window on the side menu item `CMake`, then on the tab `Tools` in the center content view, and finally on the button `Add` to set the path to your installed CMake.
|
||||
Please make sure that you have selected Android Platform SDK 33 for your project: click in the main view's side menu on `Projects`, and on the left, you'll see a section `Build & Run` showing different Android build targets. You can select any of them, Amnezia VPN's project setup is designed in a way that all Android targets will be built. Click on the targets submenu item `Build` and scroll in the center content view to `Build Steps`. Click on `Details` at the end of the headline `Build Android APK` (the `Details` button might be hidden in case the QT Creator Window is not running in full screen!). Here we are: Choose `android-33` as `Android Build Platform SDK`.
|
||||
|
||||
That's it! You should be ready to compile the project from QT Creator!
|
||||
|
||||
### Development flow
|
||||
|
||||
After you've hit the build button, QT-Creator copies the whole project to a folder in the repository parent directory. The folder should look something like `build-amnezia-client-Android_Qt_<version>_Clang_<architecture>-<BuildType>`.
|
||||
If you want to develop Amnezia VPNs Android components written in Kotlin, such as components using system APIs, you need to import the generated project in Android Studio with `build-amnezia-client-Android_Qt_<version>_Clang_<architecture>-<BuildType>/client/android-build` as the projects root directory. While you should be able to compile the generated project from Android Studio, you cannot work directly in the repository's Android project. So whenever you are confident with your work in the generated project, you'll need to copy and paste the affected files to the corresponding path in the repository's Android project so that you can add and commit your changes!
|
||||
|
||||
You may face compiling issues in QT Creator after you've worked in Android Studio on the generated project. Just do a `./gradlew clean` in the generated project's root directory (`<path>/client/android-build/.`) and you should be good to go.
|
||||
|
||||
## License
|
||||
GPL v.3
|
||||
|
||||
## Contacts
|
||||
[https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Telegram support channel (English)
|
||||
[https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Telegram support channel (Russian)
|
||||
[https://signal.group/...](https://signal.group/#CjQKIB2gUf8QH_IXnOJMGQWMDjYz9cNfmRQipGWLFiIgc4MwEhAKBONrSiWHvoUFbbD0xwdh) - Signal channel
|
||||
[https://amnezia.org](https://amnezia.org) - project website
|
||||
GPL v3.0
|
||||
|
||||
## Donate
|
||||
Bitcoin: bc1qn9rhsffuxwnhcuuu4qzrwp4upkrq94xnh8r26u
|
||||
|
||||
Patreon: [https://www.patreon.com/amneziavpn](https://www.patreon.com/amneziavpn)
|
||||
|
||||
Bitcoin: bc1q26eevjcg9j0wuyywd2e3uc9cs2w58lpkpjxq6p <br>
|
||||
USDT BEP20: 0x6abD576765a826f87D1D95183438f9408C901bE4 <br>
|
||||
USDT TRC20: TELAitazF1MZGmiNjTcnxDjEiH5oe7LC9d <br>
|
||||
XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3
|
||||
payeer.com: P2561305
|
||||
ko-fi.com: [https://ko-fi.com/amnezia_vpn](https://ko-fi.com/amnezia_vpn)
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
This project is tested with BrowserStack.
|
||||
We express our gratitude to [BrowserStack](https://www.browserstack.com) for supporting our project.
|
||||
|
||||
1
client/3rd-prebuilt
Submodule
1
client/3rd-prebuilt
Submodule
Submodule client/3rd-prebuilt added at c38a587fcd
1
client/3rd/OpenVPNAdapter
vendored
Submodule
1
client/3rd/OpenVPNAdapter
vendored
Submodule
Submodule client/3rd/OpenVPNAdapter added at dea6040996
2
client/3rd/QJsonStruct/.gitignore
vendored
Normal file
2
client/3rd/QJsonStruct/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.user
|
||||
build/
|
||||
19
client/3rd/QJsonStruct/CMakeLists.txt
Normal file
19
client/3rd/QJsonStruct/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(QJsonStruct LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
option(BUILD_TESTING ON)
|
||||
|
||||
include(QJsonStruct.cmake)
|
||||
find_package(Qt5 COMPONENTS Core REQUIRED)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
21
client/3rd/QJsonStruct/LICENSE
Normal file
21
client/3rd/QJsonStruct/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Qv2ray Workgroup
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
190
client/3rd/QJsonStruct/QJsonIO.hpp
Normal file
190
client/3rd/QJsonStruct/QJsonIO.hpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#pragma once
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QList>
|
||||
#include <tuple>
|
||||
|
||||
enum class QJsonIOPathType
|
||||
{
|
||||
JSONIO_MODE_ARRAY,
|
||||
JSONIO_MODE_OBJECT
|
||||
};
|
||||
|
||||
typedef QPair<QString, QJsonIOPathType> QJsonIONodeType;
|
||||
|
||||
struct QJsonIOPath : QList<QJsonIONodeType>
|
||||
{
|
||||
template<typename type1, typename type2, typename... types>
|
||||
QJsonIOPath(const type1 t1, const type2 t2, const types... ts)
|
||||
{
|
||||
AppendPath(t1);
|
||||
AppendPath(t2);
|
||||
(AppendPath(ts), ...);
|
||||
}
|
||||
|
||||
void AppendPath(size_t index)
|
||||
{
|
||||
append({ QString::number(index), QJsonIOPathType::JSONIO_MODE_ARRAY });
|
||||
}
|
||||
|
||||
void AppendPath(const QString &key)
|
||||
{
|
||||
append({ key, QJsonIOPathType::JSONIO_MODE_OBJECT });
|
||||
}
|
||||
|
||||
template<typename t>
|
||||
QJsonIOPath &operator<<(const t &str)
|
||||
{
|
||||
AppendPath(str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename t>
|
||||
QJsonIOPath &operator+=(const t &val)
|
||||
{
|
||||
AppendPath(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
QJsonIOPath &operator<<(const QJsonIOPath &other)
|
||||
{
|
||||
for (const auto &x : other)
|
||||
this->append(x);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename t>
|
||||
QJsonIOPath &operator<<(const t &val) const
|
||||
{
|
||||
auto _new = *this;
|
||||
return _new << val;
|
||||
}
|
||||
|
||||
template<typename t>
|
||||
QJsonIOPath operator+(const t &val) const
|
||||
{
|
||||
auto _new = *this;
|
||||
return _new << val;
|
||||
}
|
||||
|
||||
QJsonIOPath operator+(const QJsonIOPath &other) const
|
||||
{
|
||||
auto _new = *this;
|
||||
for (const auto &x : other)
|
||||
_new.append(x);
|
||||
return _new;
|
||||
}
|
||||
};
|
||||
|
||||
class QJsonIO
|
||||
{
|
||||
public:
|
||||
const static inline QJsonValue Null = QJsonValue::Null;
|
||||
const static inline QJsonValue Undefined = QJsonValue::Undefined;
|
||||
|
||||
template<typename current_key_type, typename... t_other_types>
|
||||
static QJsonValue GetValue(const QJsonValue &parent, const current_key_type ¤t, const t_other_types &...other)
|
||||
{
|
||||
if constexpr (sizeof...(t_other_types) == 0)
|
||||
if constexpr (std::is_integral_v<current_key_type>)
|
||||
return parent.toArray()[current];
|
||||
else
|
||||
return parent.toObject()[current];
|
||||
else if constexpr (std::is_integral_v<current_key_type>)
|
||||
return GetValue(parent.toArray()[current], other...);
|
||||
else
|
||||
return GetValue(parent.toObject()[current], other...);
|
||||
}
|
||||
|
||||
template<typename... key_types_t>
|
||||
static QJsonValue GetValue(QJsonValue value, const std::tuple<key_types_t...> &keys, const QJsonValue &defaultValue = Undefined)
|
||||
{
|
||||
std::apply([&](auto &&...args) { ((value = value[args]), ...); }, keys);
|
||||
return value.isUndefined() ? defaultValue : value;
|
||||
}
|
||||
|
||||
template<typename parent_type, typename t_value_type, typename current_key_type, typename... t_other_key_types>
|
||||
static void SetValue(parent_type &parent, const t_value_type &val, const current_key_type ¤t, const t_other_key_types &...other)
|
||||
{
|
||||
// If current parent is an array, increase its size to fit the "key"
|
||||
if constexpr (std::is_integral_v<current_key_type>)
|
||||
for (auto i = parent.size(); i <= current; i++)
|
||||
parent.insert(i, {});
|
||||
|
||||
// If the t_other_key_types has nothing....
|
||||
// Means we have reached the end of recursion.
|
||||
if constexpr (sizeof...(t_other_key_types) == 0)
|
||||
parent[current] = val;
|
||||
else if constexpr (std::is_integral_v<typename std::tuple_element_t<0, std::tuple<t_other_key_types...>>>)
|
||||
{
|
||||
// Means we still have many keys
|
||||
// So this element is an array.
|
||||
auto _array = parent[current].toArray();
|
||||
SetValue(_array, val, other...);
|
||||
parent[current] = _array;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto _object = parent[current].toObject();
|
||||
SetValue(_object, val, other...);
|
||||
parent[current] = _object;
|
||||
}
|
||||
}
|
||||
|
||||
static QJsonValue GetValue(const QJsonValue &parent, const QJsonIOPath &path, const QJsonValue &defaultValue = QJsonIO::Undefined)
|
||||
{
|
||||
QJsonValue val = parent;
|
||||
for (const auto &[k, t] : path)
|
||||
{
|
||||
if (t == QJsonIOPathType::JSONIO_MODE_ARRAY)
|
||||
val = val.toArray()[k.toInt()];
|
||||
else
|
||||
val = val.toObject()[k];
|
||||
}
|
||||
return val.isUndefined() ? defaultValue : val;
|
||||
}
|
||||
|
||||
template<typename parent_type, typename value_type>
|
||||
static void SetValue(parent_type &parent, const value_type &t, const QJsonIOPath &path)
|
||||
{
|
||||
QList<std::tuple<QString, QJsonIOPathType, QJsonValue>> _stack;
|
||||
QJsonValue lastNode = parent;
|
||||
for (const auto &[key, type] : path)
|
||||
{
|
||||
_stack.prepend({ key, type, lastNode });
|
||||
if (type == QJsonIOPathType::JSONIO_MODE_ARRAY)
|
||||
lastNode = lastNode.toArray().at(key.toInt());
|
||||
else
|
||||
lastNode = lastNode.toObject()[key];
|
||||
}
|
||||
|
||||
lastNode = t;
|
||||
|
||||
for (const auto &[key, type, node] : _stack)
|
||||
{
|
||||
if (type == QJsonIOPathType::JSONIO_MODE_ARRAY)
|
||||
{
|
||||
const auto index = key.toInt();
|
||||
auto nodeArray = node.toArray();
|
||||
for (auto i = nodeArray.size(); i <= index; i++)
|
||||
nodeArray.insert(i, {});
|
||||
nodeArray[index] = lastNode;
|
||||
lastNode = nodeArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto nodeObject = node.toObject();
|
||||
nodeObject[key] = lastNode;
|
||||
lastNode = nodeObject;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<parent_type, QJsonObject>)
|
||||
parent = lastNode.toObject();
|
||||
else if constexpr (std::is_same_v<parent_type, QJsonArray>)
|
||||
parent = lastNode.toArray();
|
||||
else
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
};
|
||||
5
client/3rd/QJsonStruct/QJsonStruct.cmake
Normal file
5
client/3rd/QJsonStruct/QJsonStruct.cmake
Normal file
@@ -0,0 +1,5 @@
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
set(QJSONSTRUCT_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/QJsonStruct.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/QJsonIO.hpp)
|
||||
215
client/3rd/QJsonStruct/QJsonStruct.hpp
Normal file
215
client/3rd/QJsonStruct/QJsonStruct.hpp
Normal file
@@ -0,0 +1,215 @@
|
||||
#pragma once
|
||||
#include "macroexpansion.hpp"
|
||||
|
||||
#ifndef _X
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#endif
|
||||
|
||||
/// macro to define an operator==
|
||||
#define ___JSONSTRUCT_DEFAULT_COMPARE_IMPL(x) (this->x == ___another___instance__.x) &&
|
||||
#define JSONSTRUCT_COMPARE(CLASS, ...) \
|
||||
bool operator==(const CLASS &___another___instance__) const \
|
||||
{ \
|
||||
return FOR_EACH(___JSONSTRUCT_DEFAULT_COMPARE_IMPL, __VA_ARGS__) true; \
|
||||
}
|
||||
|
||||
// ============================================================================================
|
||||
// Load JSON IMPL
|
||||
#define ___DESERIALIZE_FROM_JSON_CONVERT_B_FUNC_IMPL(name) name::loadJson(___json_object_);
|
||||
#define ___DESERIALIZE_FROM_JSON_CONVERT_A_FUNC(name) ___DESERIALIZE_FROM_JSON_CONVERT_F_FUNC(name)
|
||||
#define ___DESERIALIZE_FROM_JSON_CONVERT_B_FUNC(...) FOREACH_CALL_FUNC_3(___DESERIALIZE_FROM_JSON_CONVERT_B_FUNC_IMPL, __VA_ARGS__)
|
||||
#define ___DESERIALIZE_FROM_JSON_CONVERT_F_FUNC(name) \
|
||||
if (___json_object_.toObject().contains(#name)) \
|
||||
{ \
|
||||
JsonStructHelper::Deserialize(this->name, ___json_object_.toObject()[#name]); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
this->name = ___qjsonstruct_default_check.name; \
|
||||
}
|
||||
|
||||
// ============================================================================================
|
||||
// To JSON IMPL
|
||||
#define ___SERIALIZE_TO_JSON_CONVERT_F_FUNC(name) \
|
||||
if (!(___qjsonstruct_default_check.name == this->name)) \
|
||||
{ \
|
||||
___json_object_.insert(#name, JsonStructHelper::Serialize(name)); \
|
||||
}
|
||||
#define ___SERIALIZE_TO_JSON_CONVERT_A_FUNC(name) ___json_object_.insert(#name, JsonStructHelper::Serialize(name));
|
||||
#define ___SERIALIZE_TO_JSON_CONVERT_B_FUNC_IMPL(name) JsonStructHelper::MergeJson(___json_object_, name::toJson());
|
||||
#define ___SERIALIZE_TO_JSON_CONVERT_B_FUNC(...) FOREACH_CALL_FUNC_3(___SERIALIZE_TO_JSON_CONVERT_B_FUNC_IMPL, __VA_ARGS__)
|
||||
|
||||
// ============================================================================================
|
||||
// Load JSON Wrapper
|
||||
#define ___DESERIALIZE_FROM_JSON_CONVERT_FUNC_DECL_A(...) FOREACH_CALL_FUNC_2(___DESERIALIZE_FROM_JSON_CONVERT_A_FUNC, __VA_ARGS__)
|
||||
#define ___DESERIALIZE_FROM_JSON_CONVERT_FUNC_DECL_F(...) FOREACH_CALL_FUNC_2(___DESERIALIZE_FROM_JSON_CONVERT_F_FUNC, __VA_ARGS__)
|
||||
#define ___DESERIALIZE_FROM_JSON_CONVERT_FUNC_DECL_B(...) FOREACH_CALL_FUNC_2(___DESERIALIZE_FROM_JSON_CONVERT_B_FUNC, __VA_ARGS__)
|
||||
#define ___DESERIALIZE_FROM_JSON_EXTRACT_B_F(name_option) ___DESERIALIZE_FROM_JSON_CONVERT_FUNC_DECL_##name_option
|
||||
|
||||
// ============================================================================================
|
||||
// To JSON Wrapper
|
||||
#define ___SERIALIZE_TO_JSON_CONVERT_FUNC_DECL_A(...) FOREACH_CALL_FUNC_2(___SERIALIZE_TO_JSON_CONVERT_A_FUNC, __VA_ARGS__)
|
||||
#define ___SERIALIZE_TO_JSON_CONVERT_FUNC_DECL_F(...) FOREACH_CALL_FUNC_2(___SERIALIZE_TO_JSON_CONVERT_F_FUNC, __VA_ARGS__)
|
||||
#define ___SERIALIZE_TO_JSON_CONVERT_FUNC_DECL_B(...) FOREACH_CALL_FUNC_2(___SERIALIZE_TO_JSON_CONVERT_B_FUNC, __VA_ARGS__)
|
||||
#define ___SERIALIZE_TO_JSON_EXTRACT_B_F(name_option) ___SERIALIZE_TO_JSON_CONVERT_FUNC_DECL_##name_option
|
||||
|
||||
// ============================================================================================
|
||||
#define JSONSTRUCT_REGISTER_NOCOPYMOVE(___class_type_, ...) \
|
||||
void loadJson(const QJsonValue &___json_object_) \
|
||||
{ \
|
||||
___class_type_ ___qjsonstruct_default_check; \
|
||||
FOREACH_CALL_FUNC(___DESERIALIZE_FROM_JSON_EXTRACT_B_F, __VA_ARGS__); \
|
||||
} \
|
||||
[[nodiscard]] const QJsonObject toJson() const \
|
||||
{ \
|
||||
___class_type_ ___qjsonstruct_default_check; \
|
||||
QJsonObject ___json_object_; \
|
||||
FOREACH_CALL_FUNC(___SERIALIZE_TO_JSON_EXTRACT_B_F, __VA_ARGS__); \
|
||||
return ___json_object_; \
|
||||
}
|
||||
|
||||
#define JSONSTRUCT_REGISTER(___class_type_, ...) \
|
||||
JSONSTRUCT_REGISTER_NOCOPYMOVE(___class_type_, __VA_ARGS__); \
|
||||
[[nodiscard]] static auto fromJson(const QJsonValue &___json_object_) \
|
||||
{ \
|
||||
___class_type_ _t; \
|
||||
_t.loadJson(___json_object_); \
|
||||
return _t; \
|
||||
}
|
||||
|
||||
#define ___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(type, convert_func) \
|
||||
static void Deserialize(type &t, const QJsonValue &d) \
|
||||
{ \
|
||||
t = d.convert_func; \
|
||||
}
|
||||
|
||||
class JsonStructHelper
|
||||
{
|
||||
public:
|
||||
static void MergeJson(QJsonObject &mergeTo, const QJsonObject &mergeIn)
|
||||
{
|
||||
for (const auto &key : mergeIn.keys())
|
||||
mergeTo[key] = mergeIn.value(key);
|
||||
}
|
||||
//
|
||||
template<typename T>
|
||||
static void Deserialize(T &t, const QJsonValue &d)
|
||||
{
|
||||
if constexpr (std::is_enum_v<T>)
|
||||
t = (T) d.toInt();
|
||||
else if constexpr (std::is_same_v<T, QJsonObject>)
|
||||
t = d.toObject();
|
||||
else if constexpr (std::is_same_v<T, QJsonArray>)
|
||||
t = d.toArray();
|
||||
else
|
||||
t.loadJson(d);
|
||||
}
|
||||
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(QString, toString());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(QChar, toVariant().toChar());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(std::string, toString().toStdString());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(std::wstring, toString().toStdWString());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(bool, toBool());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(double, toDouble());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(float, toVariant().toFloat());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(int, toInt());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(long, toVariant().toLongLong());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(long long, toVariant().toLongLong());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(unsigned int, toVariant().toUInt());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(unsigned long, toVariant().toULongLong());
|
||||
___DECL_JSON_STRUCT_LOAD_SIMPLE_TYPE_FUNC(unsigned long long, toVariant().toULongLong());
|
||||
|
||||
template<typename T>
|
||||
static void Deserialize(QList<T> &t, const QJsonValue &d)
|
||||
{
|
||||
t.clear();
|
||||
for (const auto &val : d.toArray())
|
||||
{
|
||||
T data;
|
||||
Deserialize(data, val);
|
||||
t.push_back(data);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TKey, typename TValue>
|
||||
static void Deserialize(QMap<TKey, TValue> &t, const QJsonValue &d)
|
||||
{
|
||||
t.clear();
|
||||
const auto &jsonObject = d.toObject();
|
||||
TKey keyVal;
|
||||
TValue valueVal;
|
||||
for (const auto &key : jsonObject.keys())
|
||||
{
|
||||
Deserialize(keyVal, key);
|
||||
Deserialize(valueVal, jsonObject.value(key));
|
||||
t.insert(keyVal, valueVal);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================== Store Json Data ===========================
|
||||
|
||||
template<typename T>
|
||||
static QJsonValue Serialize(const T &t)
|
||||
{
|
||||
if constexpr (std::is_enum_v<T>)
|
||||
return (int) t;
|
||||
else if constexpr (std::is_same_v<T, QJsonObject> || std::is_same_v<T, QJsonArray>)
|
||||
return t;
|
||||
else
|
||||
return t.toJson();
|
||||
}
|
||||
|
||||
#define pure_func(x) (x)
|
||||
#define ___DECL_JSON_STRUCT_STORE_SIMPLE_TYPE_FUNC(type) \
|
||||
static QJsonValue Serialize(const type &t) \
|
||||
{ \
|
||||
return QJsonValue(t); \
|
||||
}
|
||||
___DECL_JSON_STRUCT_STORE_SIMPLE_TYPE_FUNC(int);
|
||||
___DECL_JSON_STRUCT_STORE_SIMPLE_TYPE_FUNC(bool);
|
||||
___DECL_JSON_STRUCT_STORE_SIMPLE_TYPE_FUNC(QJsonArray);
|
||||
___DECL_JSON_STRUCT_STORE_SIMPLE_TYPE_FUNC(QJsonObject);
|
||||
___DECL_JSON_STRUCT_STORE_SIMPLE_TYPE_FUNC(QString);
|
||||
___DECL_JSON_STRUCT_STORE_SIMPLE_TYPE_FUNC(long long);
|
||||
___DECL_JSON_STRUCT_STORE_SIMPLE_TYPE_FUNC(float);
|
||||
___DECL_JSON_STRUCT_STORE_SIMPLE_TYPE_FUNC(double);
|
||||
|
||||
#define ___DECL_JSON_STRUCT_STORE_VARIANT_TYPE_FUNC(type, func) \
|
||||
static QJsonValue Serialize(const type &t) \
|
||||
{ \
|
||||
return QJsonValue::fromVariant(func); \
|
||||
}
|
||||
|
||||
___DECL_JSON_STRUCT_STORE_VARIANT_TYPE_FUNC(std::string, QString::fromStdString(t))
|
||||
___DECL_JSON_STRUCT_STORE_VARIANT_TYPE_FUNC(std::wstring, QString::fromStdWString(t))
|
||||
___DECL_JSON_STRUCT_STORE_VARIANT_TYPE_FUNC(long, QVariant::fromValue<long>(t))
|
||||
___DECL_JSON_STRUCT_STORE_VARIANT_TYPE_FUNC(unsigned int, QVariant::fromValue<unsigned int>(t))
|
||||
___DECL_JSON_STRUCT_STORE_VARIANT_TYPE_FUNC(unsigned long, QVariant::fromValue<unsigned long>(t))
|
||||
___DECL_JSON_STRUCT_STORE_VARIANT_TYPE_FUNC(unsigned long long, QVariant::fromValue<unsigned long long>(t))
|
||||
|
||||
template<typename TValue>
|
||||
static QJsonValue Serialize(const QMap<QString, TValue> &t)
|
||||
{
|
||||
QJsonObject mapObject;
|
||||
for (const auto &key : t.keys())
|
||||
{
|
||||
auto valueVal = Serialize(t.value(key));
|
||||
mapObject.insert(key, valueVal);
|
||||
}
|
||||
return mapObject;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static QJsonValue Serialize(const QList<T> &t)
|
||||
{
|
||||
QJsonArray listObject;
|
||||
for (const auto &item : t)
|
||||
{
|
||||
listObject.push_back(Serialize(item));
|
||||
}
|
||||
return listObject;
|
||||
}
|
||||
};
|
||||
74
client/3rd/QJsonStruct/macroexpansion.hpp
Normal file
74
client/3rd/QJsonStruct/macroexpansion.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
|
||||
#define CONCATENATE2(arg1, arg2) arg1##arg2
|
||||
#define CONCATENATE(x, y) x##y
|
||||
|
||||
#define EXPAND(...) __VA_ARGS__
|
||||
#define FOR_EACH_1(what, x, ...) what(x)
|
||||
#define FOR_EACH_2(what, x, ...) what(x) EXPAND(FOR_EACH_1(what, __VA_ARGS__))
|
||||
#define FOR_EACH_3(what, x, ...) what(x) EXPAND(FOR_EACH_2(what, __VA_ARGS__))
|
||||
#define FOR_EACH_4(what, x, ...) what(x) EXPAND(FOR_EACH_3(what, __VA_ARGS__))
|
||||
#define FOR_EACH_5(what, x, ...) what(x) EXPAND(FOR_EACH_4(what, __VA_ARGS__))
|
||||
#define FOR_EACH_6(what, x, ...) what(x) EXPAND(FOR_EACH_5(what, __VA_ARGS__))
|
||||
#define FOR_EACH_7(what, x, ...) what(x) EXPAND(FOR_EACH_6(what, __VA_ARGS__))
|
||||
#define FOR_EACH_8(what, x, ...) what(x) EXPAND(FOR_EACH_7(what, __VA_ARGS__))
|
||||
#define FOR_EACH_9(what, x, ...) what(x) EXPAND(FOR_EACH_8(what, __VA_ARGS__))
|
||||
#define FOR_EACH_10(what, x, ...) what(x) EXPAND(FOR_EACH_9(what, __VA_ARGS__))
|
||||
#define FOR_EACH_11(what, x, ...) what(x) EXPAND(FOR_EACH_10(what, __VA_ARGS__))
|
||||
#define FOR_EACH_12(what, x, ...) what(x) EXPAND(FOR_EACH_11(what, __VA_ARGS__))
|
||||
#define FOR_EACH_13(what, x, ...) what(x) EXPAND(FOR_EACH_12(what, __VA_ARGS__))
|
||||
#define FOR_EACH_14(what, x, ...) what(x) EXPAND(FOR_EACH_13(what, __VA_ARGS__))
|
||||
#define FOR_EACH_15(what, x, ...) what(x) EXPAND(FOR_EACH_14(what, __VA_ARGS__))
|
||||
#define FOR_EACH_16(what, x, ...) what(x) EXPAND(FOR_EACH_15(what, __VA_ARGS__))
|
||||
|
||||
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
|
||||
#define FOR_EACH_NARG_(...) EXPAND(FOR_EACH_ARG_N(__VA_ARGS__))
|
||||
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
|
||||
#define FOR_EACH_RSEQ_N() 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
|
||||
#define FOR_EACH_(N, what, ...) EXPAND(CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__))
|
||||
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
|
||||
#define FOREACH_CALL_FUNC(func, ...) FOR_EACH(func, __VA_ARGS__)
|
||||
|
||||
// Bad hack ==========================================================================================================================
|
||||
#define _2X_FOR_EACH_1(what, x, ...) what(x)
|
||||
#define _2X_FOR_EACH_2(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_1(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_3(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_2(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_4(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_3(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_5(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_4(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_6(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_5(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_7(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_6(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_8(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_7(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_9(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_8(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_10(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_9(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_11(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_10(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_12(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_11(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_13(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_12(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_14(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_13(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_15(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_14(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_16(what, x, ...) what(x) EXPAND(_2X_FOR_EACH_15(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH_(N, what, ...) EXPAND(CONCATENATE(_2X_FOR_EACH_, N)(what, __VA_ARGS__))
|
||||
#define _2X_FOR_EACH(what, ...) _2X_FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
|
||||
#define FOREACH_CALL_FUNC_2(func, ...) _2X_FOR_EACH(func, __VA_ARGS__)
|
||||
|
||||
// Bad hack ==========================================================================================================================
|
||||
#define _3X_FOR_EACH_1(what, x, ...) what(x)
|
||||
#define _3X_FOR_EACH_2(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_1(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_3(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_2(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_4(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_3(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_5(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_4(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_6(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_5(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_7(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_6(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_8(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_7(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_9(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_8(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_10(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_9(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_11(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_10(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_12(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_11(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_13(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_12(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_14(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_13(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_15(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_14(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_16(what, x, ...) what(x) EXPAND(_3X_FOR_EACH_15(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH_(N, what, ...) EXPAND(CONCATENATE(_3X_FOR_EACH_, N)(what, __VA_ARGS__))
|
||||
#define _3X_FOR_EACH(what, ...) _3X_FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
|
||||
#define FOREACH_CALL_FUNC_3(func, ...) _3X_FOR_EACH(func, __VA_ARGS__)
|
||||
16
client/3rd/QJsonStruct/test/CMakeLists.txt
Normal file
16
client/3rd/QJsonStruct/test/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
function(QJSONSTRUCT_ADD_TEST TEST_NAME TEST_SOURCE)
|
||||
add_executable(${TEST_NAME} ${TEST_SOURCE} catch.hpp ${QJSONSTRUCT_SOURCES})
|
||||
target_include_directories(${TEST_NAME}
|
||||
PRIVATE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
)
|
||||
target_link_libraries(
|
||||
${TEST_NAME}
|
||||
PRIVATE
|
||||
Qt::Core
|
||||
)
|
||||
add_test(NAME QJSONSTRUCT_TEST_${TEST_NAME} COMMAND $<TARGET_FILE:${TEST_NAME}> -s)
|
||||
endfunction()
|
||||
|
||||
QJSONSTRUCT_ADD_TEST(serialization serialize/main.cpp)
|
||||
#QJSONSTRUCT_ADD_TEST(serialize_strings serialize/strings.cpp)
|
||||
45
client/3rd/QJsonStruct/test/TestIO.hpp
Normal file
45
client/3rd/QJsonStruct/test/TestIO.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include "QJsonStruct.hpp"
|
||||
#ifndef _X
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#endif
|
||||
|
||||
struct BaseStruct
|
||||
{
|
||||
QString baseStr;
|
||||
int o;
|
||||
JSONSTRUCT_REGISTER(BaseStruct, F(baseStr, o))
|
||||
};
|
||||
|
||||
struct BaseStruct2
|
||||
{
|
||||
QString baseStr2;
|
||||
int o2;
|
||||
JSONSTRUCT_REGISTER(BaseStruct, F(baseStr2, o2))
|
||||
};
|
||||
struct TestInnerStruct
|
||||
: BaseStruct
|
||||
, BaseStruct2
|
||||
{
|
||||
QJsonObject jobj;
|
||||
QJsonArray jarray;
|
||||
QString str;
|
||||
JSONSTRUCT_REGISTER(TestInnerStruct, B(BaseStruct, BaseStruct2), F(str, jobj, jarray))
|
||||
};
|
||||
|
||||
struct JsonIOTest
|
||||
{
|
||||
QString str;
|
||||
QList<int> listOfNumber;
|
||||
QList<bool> listOfBool;
|
||||
QList<QString> listOfString;
|
||||
QList<QList<QString>> listOfListOfString;
|
||||
|
||||
QMap<QString, QString> map;
|
||||
TestInnerStruct inner;
|
||||
|
||||
JSONSTRUCT_REGISTER(JsonIOTest, F(str, listOfNumber, listOfBool, listOfString, listOfListOfString, map, inner));
|
||||
JsonIOTest(){};
|
||||
};
|
||||
19
client/3rd/QJsonStruct/test/TestOut.hpp
Normal file
19
client/3rd/QJsonStruct/test/TestOut.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "QJsonStruct.hpp"
|
||||
|
||||
struct SubData
|
||||
{
|
||||
QString subString;
|
||||
JSONSTRUCT_REGISTER_TOJSON(subString)
|
||||
};
|
||||
|
||||
struct ToJsonOnlyData
|
||||
{
|
||||
QString x;
|
||||
int y;
|
||||
int z;
|
||||
QList<int> ints;
|
||||
SubData sub;
|
||||
QMap<QString, SubData> subs;
|
||||
JSONSTRUCT_REGISTER_TOJSON(x, y, z, sub, ints, subs)
|
||||
};
|
||||
17698
client/3rd/QJsonStruct/test/catch.hpp
Normal file
17698
client/3rd/QJsonStruct/test/catch.hpp
Normal file
File diff suppressed because it is too large
Load Diff
70
client/3rd/QJsonStruct/test/main.cpp
Normal file
70
client/3rd/QJsonStruct/test/main.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "QJsonIO.hpp"
|
||||
#include "QJsonStruct.hpp"
|
||||
#include "TestIO.hpp"
|
||||
#include "TestOut.hpp"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Q_UNUSED(argc)
|
||||
Q_UNUSED(argv)
|
||||
|
||||
{
|
||||
ToJsonOnlyData data;
|
||||
data.x = "1string";
|
||||
data.y = 2;
|
||||
data.ints << 0;
|
||||
data.ints << 100;
|
||||
data.ints << 900;
|
||||
data.sub.subString = "subs";
|
||||
data.subs["subs-1"] = { "subs1-data" };
|
||||
data.subs["subs-2"] = { "subs2-data" };
|
||||
data.subs["subs-3"] = { "subs3-data" };
|
||||
data.z = 3;
|
||||
auto x = data.toJson();
|
||||
std::cout << QJsonDocument(x).toJson().toStdString() << std::endl;
|
||||
}
|
||||
//
|
||||
{
|
||||
auto f = JsonIOTest::fromJson( //
|
||||
QJsonObject{
|
||||
{ "inner", QJsonObject{ { "str", "innerString" }, //
|
||||
{ "jobj", QJsonObject{ { "key", "value" } } }, //
|
||||
{ "jarray", QJsonArray{ "array0", "array1", "array2" } }, //
|
||||
{ "baseStr", "baseInnerString" } } }, //
|
||||
{ "str", "data1" }, //
|
||||
{ "map", QJsonObject{ { "mapStr", "mapData" } } }, //
|
||||
{ "listOfString", QJsonArray{ "1", "2", "3", "4", "5" } }, //
|
||||
{ "listOfNumber", QJsonArray{ 1, 2, 3, 4, 5 } }, //
|
||||
{ "listOfBool", QJsonArray{ true, false, false, true, true } }, //
|
||||
{ "listOfListOfString", QJsonArray{ QJsonArray{ "1" }, //
|
||||
QJsonArray{ "1", "2" }, //
|
||||
QJsonArray{ "1", "2", "3" }, //
|
||||
QJsonArray{ "1", "2", "3", "4" }, //
|
||||
QJsonArray{ "1", "2", "3", "4", "5" } } }, //
|
||||
});
|
||||
auto x = f.toJson();
|
||||
std::cout << QJsonDocument(x).toJson().toStdString() << std::endl;
|
||||
}
|
||||
{
|
||||
QJsonObject obj{
|
||||
{ "inner", QJsonObject{ { "str", "innerString" }, { "baseStr", "baseInnerString" } } }, //
|
||||
{ "str", "data1" }, //
|
||||
{ "map", QJsonObject{ { "mapStr", "mapData" } } }, //
|
||||
{ "listOfString", QJsonArray{ "1", "2", "3", "4", "5" } }, //
|
||||
{ "listOfNumber", QJsonArray{ 1, 2, 3, 4, 5 } }, //
|
||||
{ "listOfBool", QJsonArray{ true, false, false, true, true } }, //
|
||||
{ "listOfListOfString", QJsonArray{ QJsonArray{ "1" }, //
|
||||
QJsonArray{ "1", "2" }, //
|
||||
QJsonArray{ "1", "2", "3" }, //
|
||||
QJsonArray{ "1", "2", "3", "4" }, //
|
||||
QJsonArray{ "1", "2", "3", "4", "5" } } }, //
|
||||
};
|
||||
auto y = QJsonIO::GetValue(obj, std::tuple{ "listOfListOfString", 2 });
|
||||
y.toObject();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
181
client/3rd/QJsonStruct/test/serialize/main.cpp
Normal file
181
client/3rd/QJsonStruct/test/serialize/main.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "QJsonStruct.hpp"
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
|
||||
const static inline auto INT_TEST_MAX = std::numeric_limits<int>::max() - 1;
|
||||
const static inline auto INT_TEST_MIN = -(std::numeric_limits<int>::min() + 1);
|
||||
|
||||
#define SINGLE_ELEMENT_CLASS_DECL(CLASS, TYPE, field, defaultvalue, existance) \
|
||||
class CLASS \
|
||||
{ \
|
||||
public: \
|
||||
TYPE field = defaultvalue; \
|
||||
JSONSTRUCT_REGISTER(CLASS, existance(field)); \
|
||||
};
|
||||
|
||||
// SINGLE_ELEMENT_REQUIRE( CLASS_NAME , TYPE , FIELD , DEFAULT_VALUE , SET VALUE , CHECK VALUE )
|
||||
#define SINGLE_ELEMENT_REQUIRE(CLASS, TYPE, field, defaultvalue, value, checkvalue, existance) \
|
||||
SINGLE_ELEMENT_CLASS_DECL(CLASS, TYPE, field, defaultvalue, existance); \
|
||||
CLASS CLASS##_class; \
|
||||
CLASS##_class.field = value; \
|
||||
REQUIRE(CLASS##_class.toJson()[#field] == checkvalue);
|
||||
|
||||
using namespace std;
|
||||
SCENARIO("Test Serialization", "[Serialize]")
|
||||
{
|
||||
GIVEN("Single Element")
|
||||
{
|
||||
const static QList<QString> defaultList{ "entry 1", "entry 2" };
|
||||
const static QMap<QString, QString> defaultMap{ { "key1", "value1" }, { "key2", "value2" } };
|
||||
typedef QMap<QString, QString> QStringQStringMap;
|
||||
|
||||
WHEN("Serialize a single element")
|
||||
{
|
||||
const static QStringQStringMap setValueMap{ { "newkey1", "newvalue1" } };
|
||||
const static QJsonObject setValueJson{ { "newkey1", QJsonValue{ "newvalue1" } } };
|
||||
|
||||
SINGLE_ELEMENT_REQUIRE(QStringTest_Empty, QString, a, "empty", "", "", F);
|
||||
SINGLE_ELEMENT_REQUIRE(QStringTest, QString, a, "empty", "Some QString", "Some QString", F);
|
||||
SINGLE_ELEMENT_REQUIRE(QStringTest_WithQoutes, QString, a, "empty", "\"", "\"", F);
|
||||
SINGLE_ELEMENT_REQUIRE(QStringTest_zint, int, a, -10, 0, 0, F);
|
||||
SINGLE_ELEMENT_REQUIRE(QStringTest_nint, int, a, -10, 1, 1, F);
|
||||
SINGLE_ELEMENT_REQUIRE(QStringTest_pint, int, a, -10, -1, -1, F);
|
||||
SINGLE_ELEMENT_REQUIRE(QStringTest_pmint, int, a, -1, INT_TEST_MAX, INT_TEST_MAX, F);
|
||||
SINGLE_ELEMENT_REQUIRE(QStringTest_zmint, int, a, -1, INT_TEST_MIN, INT_TEST_MIN, F);
|
||||
SINGLE_ELEMENT_REQUIRE(QStringTest_zuint, uint, a, -10, 0, 0, F);
|
||||
SINGLE_ELEMENT_REQUIRE(QStringTest_puint, uint, a, -10, 1, 1, F);
|
||||
SINGLE_ELEMENT_REQUIRE(BoolTest_True, bool, a, false, true, true, F);
|
||||
SINGLE_ELEMENT_REQUIRE(BoolTest_False, bool, a, true, false, false, F);
|
||||
SINGLE_ELEMENT_REQUIRE(StdStringTest, string, a, "def", "std::string _test", "std::string _test", F);
|
||||
SINGLE_ELEMENT_REQUIRE(QListTest, QList<QString>, a, defaultList, { "newEntry" }, QJsonArray{ "newEntry" }, F);
|
||||
SINGLE_ELEMENT_REQUIRE(QMapTest, QStringQStringMap, a, defaultMap, {}, QJsonObject{}, F);
|
||||
SINGLE_ELEMENT_REQUIRE(QMapValueTest, QStringQStringMap, a, defaultMap, setValueMap, setValueJson, F);
|
||||
}
|
||||
|
||||
WHEN("Serialize a default value")
|
||||
{
|
||||
SINGLE_ELEMENT_REQUIRE(DefaultQString, QString, a, "defaultvalue", "defaultvalue", QJsonValue::Undefined, F);
|
||||
SINGLE_ELEMENT_REQUIRE(DefaultInteger, int, a, 12345, 12345, QJsonValue::Undefined, F);
|
||||
SINGLE_ELEMENT_REQUIRE(DefaultList, QList<QString>, a, defaultList, defaultList, QJsonValue::Undefined, F);
|
||||
SINGLE_ELEMENT_REQUIRE(DefaultMap, QStringQStringMap, a, defaultMap, defaultMap, QJsonValue::Undefined, F);
|
||||
}
|
||||
|
||||
WHEN("Serialize a force existance default value")
|
||||
{
|
||||
const static QJsonArray defaultListJson{ "entry 1", "entry 2" };
|
||||
const static QJsonObject defaultMapJson{ { "key1", "value1" }, { "key2", "value2" } };
|
||||
SINGLE_ELEMENT_REQUIRE(DefaultQString, QString, a, "defaultvalue", "defaultvalue", "defaultvalue", A);
|
||||
SINGLE_ELEMENT_REQUIRE(DefaultInteger, int, a, 12345, 12345, 12345, A);
|
||||
SINGLE_ELEMENT_REQUIRE(DefaultList, QList<QString>, a, defaultList, defaultList, defaultListJson, A);
|
||||
SINGLE_ELEMENT_REQUIRE(DefaultMap, QStringQStringMap, a, defaultMap, defaultMap, defaultMapJson, A);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Multiple Simple Elements")
|
||||
{
|
||||
WHEN("Can Omit Default Value")
|
||||
{
|
||||
class MultipleNonDefaultElementTestClass
|
||||
{
|
||||
public:
|
||||
QString astring;
|
||||
int integer = 0;
|
||||
double adouble = 0.0;
|
||||
QList<QString> myList;
|
||||
JSONSTRUCT_REGISTER(MultipleNonDefaultElementTestClass, F(astring, integer, adouble, myList))
|
||||
};
|
||||
MultipleNonDefaultElementTestClass instance;
|
||||
const auto json = instance.toJson();
|
||||
REQUIRE(json["astring"] == QJsonValue::Undefined);
|
||||
REQUIRE(json["integer"] == QJsonValue::Undefined);
|
||||
REQUIRE(json["adouble"] == QJsonValue::Undefined);
|
||||
REQUIRE(json["myList"] == QJsonValue::Undefined);
|
||||
}
|
||||
|
||||
WHEN("Forcing Existance")
|
||||
{
|
||||
class MultipleNonDefaultExistanceElementTestClass
|
||||
{
|
||||
public:
|
||||
QString astring;
|
||||
int integer = 0;
|
||||
double adouble = 0.0;
|
||||
QList<QString> myList;
|
||||
JSONSTRUCT_REGISTER(MultipleNonDefaultExistanceElementTestClass, A(astring, integer, adouble, myList))
|
||||
};
|
||||
MultipleNonDefaultExistanceElementTestClass instance;
|
||||
const auto json = instance.toJson();
|
||||
REQUIRE(json["astring"] == "");
|
||||
REQUIRE(json["integer"] == 0);
|
||||
REQUIRE(json["adouble"] == 0.0);
|
||||
REQUIRE(json["myList"] == QJsonArray{});
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Nested Elements")
|
||||
{
|
||||
WHEN("Can Omit Default Value")
|
||||
{
|
||||
class Parent
|
||||
{
|
||||
class NestedChild
|
||||
{
|
||||
class NestedChild2
|
||||
{
|
||||
public:
|
||||
int childChildInt = 13579;
|
||||
JSONSTRUCT_COMPARE(NestedChild2, childChildInt)
|
||||
JSONSTRUCT_REGISTER(NestedChild2, F(childChildInt))
|
||||
};
|
||||
|
||||
public:
|
||||
int childInt = 54321;
|
||||
QString childQString = "A QString";
|
||||
NestedChild2 anotherChild;
|
||||
JSONSTRUCT_COMPARE(NestedChild, childInt, childQString, anotherChild)
|
||||
JSONSTRUCT_REGISTER(NestedChild, F(childInt, childQString, anotherChild))
|
||||
};
|
||||
|
||||
public:
|
||||
int parentInt = 12345;
|
||||
NestedChild child;
|
||||
JSONSTRUCT_REGISTER(Parent, F(parentInt, child))
|
||||
};
|
||||
|
||||
WHEN("Omitted whole child element")
|
||||
{
|
||||
Parent parent;
|
||||
const auto json = parent.toJson();
|
||||
REQUIRE(json["parentInt"] == QJsonValue::Undefined);
|
||||
REQUIRE(json["child"] == QJsonValue::Undefined);
|
||||
}
|
||||
|
||||
WHEN("Omitted one element in the child")
|
||||
{
|
||||
const auto childJson = QJsonObject{ { "childInt", 1314 } };
|
||||
Parent parent;
|
||||
parent.child.childInt = 1314;
|
||||
const auto json = parent.toJson();
|
||||
REQUIRE(json["parentInt"] == QJsonValue::Undefined);
|
||||
REQUIRE(json["child"] == childJson);
|
||||
REQUIRE(json["child"]["childInt"] == 1314);
|
||||
REQUIRE(json["child"]["childQString"] == QJsonValue::Undefined);
|
||||
REQUIRE(json["child"]["child"]["anotherChild"] == QJsonValue::Undefined);
|
||||
}
|
||||
|
||||
WHEN("Omitted one element in the child child")
|
||||
{
|
||||
Parent parent;
|
||||
parent.child.childInt = 1314;
|
||||
parent.child.anotherChild.childChildInt = 97531;
|
||||
const auto json = parent.toJson();
|
||||
REQUIRE(json["parentInt"] == QJsonValue::Undefined);
|
||||
REQUIRE(json["child"]["childInt"] == 1314);
|
||||
REQUIRE(json["child"]["childQString"] == QJsonValue::Undefined);
|
||||
const QJsonObject childChild{ { "childChildInt", 97531 } };
|
||||
REQUIRE(json["child"]["anotherChild"] == childChild);
|
||||
REQUIRE(json["child"]["anotherChild"]["childChildInt"] == 97531);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,129 +0,0 @@
|
||||
|
||||
#if !defined(AFX_QR_ENCODE_H__AC886DF7_C0AE_4C9F_AC7A_FCDA8CB1DD37__INCLUDED_)
|
||||
#define AFX_QR_ENCODE_H__AC886DF7_C0AE_4C9F_AC7A_FCDA8CB1DD37__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
#define QR_LEVEL_L 0
|
||||
#define QR_LEVEL_M 1
|
||||
#define QR_LEVEL_Q 2
|
||||
#define QR_LEVEL_H 3
|
||||
|
||||
//
|
||||
#define QR_MODE_NUMERAL 0
|
||||
#define QR_MODE_ALPHABET 1
|
||||
#define QR_MODE_8BIT 2
|
||||
#define QR_MODE_KANJI 3
|
||||
|
||||
//
|
||||
#define QR_VRESION_S 0
|
||||
#define QR_VRESION_M 1
|
||||
#define QR_VRESION_L 2
|
||||
|
||||
#define MAX_ALLCODEWORD 3706
|
||||
#define MAX_DATACODEWORD 2956
|
||||
#define MAX_CODEBLOCK 153
|
||||
#define MAX_MODULESIZE 177
|
||||
|
||||
#define QR_MARGIN 0
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
typedef struct tagRS_BLOCKINFO
|
||||
{
|
||||
int ncRSBlock;
|
||||
int ncAllCodeWord;
|
||||
int ncDataCodeWord;
|
||||
|
||||
} RS_BLOCKINFO, *LPRS_BLOCKINFO;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct tagQR_VERSIONINFO
|
||||
{
|
||||
int nVersionNo;
|
||||
int ncAllCodeWord;
|
||||
|
||||
int ncDataCodeWord[4];
|
||||
|
||||
int ncAlignPoint;
|
||||
int nAlignPoint[6];
|
||||
|
||||
RS_BLOCKINFO RS_BlockInfo1[4];
|
||||
RS_BLOCKINFO RS_BlockInfo2[4];
|
||||
|
||||
} QR_VERSIONINFO, *LPQR_VERSIONINFO;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CQR_Encode
|
||||
{
|
||||
public:
|
||||
CQR_Encode();
|
||||
~CQR_Encode();
|
||||
|
||||
public:
|
||||
int m_nLevel;
|
||||
int m_nVersion;
|
||||
bool m_bAutoExtent;
|
||||
int m_nMaskingNo;
|
||||
|
||||
public:
|
||||
int m_nSymbleSize;
|
||||
unsigned char m_byModuleData[MAX_MODULESIZE][MAX_MODULESIZE]; // [x][y]
|
||||
|
||||
private:
|
||||
int m_ncDataCodeWordBit;
|
||||
unsigned char m_byDataCodeWord[MAX_DATACODEWORD];
|
||||
|
||||
int m_ncDataBlock;
|
||||
unsigned char m_byBlockMode[MAX_DATACODEWORD];
|
||||
int m_nBlockLength[MAX_DATACODEWORD];
|
||||
|
||||
int m_ncAllCodeWord;
|
||||
unsigned char m_byAllCodeWord[MAX_ALLCODEWORD];
|
||||
unsigned char m_byRSWork[MAX_CODEBLOCK];
|
||||
|
||||
public:
|
||||
bool EncodeData(int nLevel, int nVersion, bool bAutoExtent, int nMaskingNo, char* lpsSource, int ncSource = 0);
|
||||
|
||||
private:
|
||||
int GetEncodeVersion(int nVersion, char* lpsSource, int ncLength);
|
||||
bool EncodeSourceData(char* lpsSource, int ncLength, int nVerGroup);
|
||||
|
||||
int GetBitLength(unsigned char nMode, int ncData, int nVerGroup);
|
||||
|
||||
int SetBitStream(int nIndex, unsigned short wData, int ncData);
|
||||
|
||||
bool IsNumeralData(unsigned char c);
|
||||
bool IsAlphabetData(unsigned char c);
|
||||
bool IsKanjiData(unsigned char c1, unsigned char c2);
|
||||
|
||||
unsigned char AlphabetToBinaly(unsigned char c);
|
||||
unsigned short KanjiToBinaly(unsigned short wc);
|
||||
|
||||
void GetRSCodeWord(unsigned char * lpbyRSWork, int ncDataCodeWord, int ncRSCodeWord);
|
||||
|
||||
private:
|
||||
void FormatModule();
|
||||
|
||||
void SetFunctionModule();
|
||||
void SetFinderPattern(int x, int y);
|
||||
void SetAlignmentPattern(int x, int y);
|
||||
void SetVersionPattern();
|
||||
void SetCodeWordPattern();
|
||||
void SetMaskingPattern(int nPatternNo);
|
||||
void SetFormatInfoPattern(int nPatternNo);
|
||||
int CountPenalty();
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // !defined(AFX_QR_ENCODE_H__AC886DF7_C0AE_4C9F_AC7A_FCDA8CB1DD37__INCLUDED_)
|
||||
@@ -1,5 +0,0 @@
|
||||
HEADERS += \
|
||||
3rd/QRCodeGenerator/QRCodeGenerator.h \
|
||||
|
||||
SOURCES += \
|
||||
3rd/QRCodeGenerator/QRCodeGenerator.cpp \
|
||||
1
client/3rd/QSimpleCrypto
vendored
Submodule
1
client/3rd/QSimpleCrypto
vendored
Submodule
Submodule client/3rd/QSimpleCrypto added at c99b33f0e0
50
client/3rd/QtSsh/.gitignore
vendored
50
client/3rd/QtSsh/.gitignore
vendored
@@ -1,50 +0,0 @@
|
||||
# User settings
|
||||
*.user
|
||||
macOSPackage/
|
||||
|
||||
# C++ objects and libs
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.a
|
||||
*.la
|
||||
*.lai
|
||||
*.so
|
||||
*.dll
|
||||
*.dylib
|
||||
|
||||
# Qt-es
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
*.qbs.user
|
||||
*.qbs.user.*
|
||||
*.moc
|
||||
moc_*.cpp
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
Makefile*
|
||||
*build-*
|
||||
|
||||
# QtCreator
|
||||
|
||||
*.autosave
|
||||
|
||||
# QtCtreator Qml
|
||||
*.qmlproject.user
|
||||
*.qmlproject.user.*
|
||||
|
||||
# QtCtreator CMake
|
||||
CMakeLists.txt.user*
|
||||
|
||||
# MACOS files
|
||||
.DS_Store
|
||||
._.DS_Store
|
||||
._*
|
||||
|
||||
# tmp files
|
||||
*.*~
|
||||
|
||||
# Certificates
|
||||
*.p12
|
||||
@@ -1,3 +0,0 @@
|
||||
load(qt_build_config)
|
||||
|
||||
MODULE_VERSION = 4.3.1
|
||||
@@ -1 +0,0 @@
|
||||
load(qt_parts)
|
||||
@@ -1,46 +0,0 @@
|
||||
# QSsh
|
||||
|
||||
this project is base on Qt-creator-open-source-4.3.1
|
||||
project is at
|
||||
|
||||
`http://code.qt.io/cgit/qt-creator/qt-creator.git/`
|
||||
|
||||
you can download code zip at
|
||||
|
||||
`http://download.qt.io/official_releases/qtcreator/4.3/4.3.1/`
|
||||
|
||||
## Getting Started
|
||||
|
||||
> * For linux user, if your Qt is installed through package manager tools such "apt-get", make sure that you have installed the Qt5 develop package *qtbase5-private-dev*
|
||||
|
||||
### Usage(1): Use QtSsh as Qt5's addon module
|
||||
|
||||
#### Building the module
|
||||
|
||||
> **Note**: Perl is needed in this step.
|
||||
|
||||
* Download the source code.
|
||||
|
||||
* Put the source code in any directory you like
|
||||
|
||||
* Go to top directory of the project in a terminal and run
|
||||
|
||||
```
|
||||
qmake
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
The library, the header files, and others will be installed to your system.
|
||||
|
||||
#### Import the module
|
||||
|
||||
` QT += ssh`
|
||||
|
||||
#### Include Headerfile
|
||||
|
||||
` #include<QtSsh/sshconnection.h>`
|
||||
|
||||
#### Close qtc.ssh log
|
||||
|
||||
` QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false")`
|
||||
@@ -1,2 +0,0 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = gitlab
|
||||
@@ -1,5 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>Qml/Main.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -1,51 +0,0 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.0
|
||||
import Ssh 1.0
|
||||
Item {
|
||||
width: 1024
|
||||
height: 768
|
||||
|
||||
TextField {
|
||||
id: input
|
||||
x: 104
|
||||
y: 44
|
||||
width: 482
|
||||
height: 40
|
||||
implicitWidth: 200
|
||||
selectByMouse: true
|
||||
text: "https://www.zhihu.com"
|
||||
}
|
||||
function get(url) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
console.log(xhr.responseXML, xhr.responseText.toString())
|
||||
} else if (xhr.readyState === XMLHttpRequest) {
|
||||
|
||||
}
|
||||
}
|
||||
xhr.open('GET', url)
|
||||
xhr.send()
|
||||
}
|
||||
Button {
|
||||
x: 627
|
||||
y: 44
|
||||
text: "get"
|
||||
onClicked: {
|
||||
get(input.text)
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: button
|
||||
x: 104
|
||||
y: 170
|
||||
text: qsTr("Ssh")
|
||||
onClicked: ssh.connectToHost()
|
||||
}
|
||||
Ssh {
|
||||
id: ssh
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickView>
|
||||
#include "Ssh.hpp"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
qmlRegisterType<Ssh> ("Ssh", 1, 0, "Ssh");
|
||||
|
||||
QQuickView view;
|
||||
view.setSource(QUrl("qrc:/Qml/Main.qml"));
|
||||
view.show();
|
||||
return app.exec();
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#include "Ssh.hpp"
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Ssh::Ssh(QObject *parent) : QObject(parent) {
|
||||
//关掉qtc.ssh中的各种打印信息
|
||||
QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false"));
|
||||
|
||||
mParams.host="ftb.autoio.org";
|
||||
mParams.userName = "ftb";
|
||||
mParams.port = 11122;
|
||||
|
||||
mParams.privateKeyFile = QDir::homePath() + QStringLiteral("/.ssh/id_rsa");
|
||||
mParams.timeout = 5;
|
||||
mParams.authenticationType = SshConnectionParameters::AuthenticationTypePublicKey;
|
||||
mParams.options = SshIgnoreDefaultProxy;
|
||||
mParams.hostKeyCheckingMode = SshHostKeyCheckingNone;
|
||||
|
||||
mConnections = std::make_shared<SshConnection>(mParams);
|
||||
connect(mConnections.get(), &SshConnection::error, [&](QSsh::SshError){
|
||||
qWarning() << "Error: " << mConnections->errorString();
|
||||
});
|
||||
connect(mConnections.get(), &SshConnection::connected, [&](){
|
||||
qWarning() << "Connected";
|
||||
create();
|
||||
});
|
||||
connect(mConnections.get(), &SshConnection::disconnected, [](){
|
||||
qWarning() << "Disconnected";
|
||||
});
|
||||
connect(mConnections.get(), &SshConnection::dataAvailable, [](const QString &message){
|
||||
qWarning() << "Message: " << message;
|
||||
});
|
||||
}
|
||||
|
||||
void Ssh::connectToHost() {
|
||||
mConnections->connectToHost();
|
||||
}
|
||||
|
||||
void Ssh::create() {
|
||||
mRemoteProcess = mConnections->createRemoteProcess(QString::fromLatin1("/bin/ls -a").toUtf8());
|
||||
if (!mRemoteProcess) {
|
||||
qWarning() << QLatin1String("Error: UnmRemoteProcess SSH connection creates remote process.");
|
||||
return;
|
||||
}
|
||||
connect(mRemoteProcess.data(), &SshRemoteProcess::started, [&](){
|
||||
qWarning() << "started";
|
||||
});
|
||||
connect(mRemoteProcess.data(), &SshRemoteProcess::readyReadStandardOutput, [&](){
|
||||
qWarning() << "StandardOutput";
|
||||
qWarning() << QString::fromLatin1(mRemoteProcess->readAllStandardOutput()).split('\n');
|
||||
});
|
||||
connect(mRemoteProcess.data(), &SshRemoteProcess::readyReadStandardError, [&](){
|
||||
qWarning() << "StandardError" << mRemoteProcess->readAllStandardError();
|
||||
});
|
||||
connect(mRemoteProcess.data(), &SshRemoteProcess::closed, [&](int exitStatus){
|
||||
qWarning() << "Exit" << exitStatus;
|
||||
});
|
||||
mRemoteProcess->start();
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
|
||||
#include <QObject>
|
||||
#include <QtSsh/sshconnection.h>
|
||||
#include <QtSsh/sshremoteprocess.h>
|
||||
|
||||
using namespace QSsh;
|
||||
|
||||
class Ssh : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Ssh(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void connectToHost();
|
||||
void create();
|
||||
|
||||
private:
|
||||
SshConnectionParameters mParams;
|
||||
std::shared_ptr<SshConnection> mConnections;
|
||||
QSharedPointer<SshRemoteProcess> mRemoteProcess;
|
||||
};
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
QT += quick network ssh
|
||||
CONFIG += c++11
|
||||
TEMPLATE = app
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which as been marked deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
#DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += Src/Main.cpp \
|
||||
Src/Ssh.cpp
|
||||
|
||||
RESOURCES += Qml.qrc
|
||||
|
||||
# Additional import path used to resolve QML modules in Qt Creator's code model
|
||||
QML_IMPORT_PATH =
|
||||
|
||||
# Additional import path used to resolve QML modules just for Qt Quick Designer
|
||||
QML_DESIGNER_IMPORT_PATH =
|
||||
|
||||
HEADERS += \
|
||||
Src/Ssh.hpp
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,53 +0,0 @@
|
||||
INCLUDEPATH += $$PWD/include
|
||||
DEPENDPATH += $$PWD
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
INCLUDEPATH += $$PWD/include/external
|
||||
|
||||
win32 {
|
||||
QMAKE_CXXFLAGS += -bigobj
|
||||
LIBS += \
|
||||
-lcrypt32 \
|
||||
|
||||
!contains(QMAKE_TARGET.arch, x86_64) {
|
||||
message("Windows x86 build")
|
||||
INCLUDEPATH += $$PWD/windows/x86_64
|
||||
HEADERS += $$PWD/windows/x86/botan_all.h
|
||||
SOURCES += $$PWD/windows/x86/botan_all.cpp
|
||||
}
|
||||
else {
|
||||
message("Windows x86_64 build")
|
||||
INCLUDEPATH += $$PWD/windows/x86_64
|
||||
HEADERS += $$PWD/windows/x86_64/botan_all.h
|
||||
SOURCES += $$PWD/windows/x86_64/botan_all.cpp
|
||||
}
|
||||
}
|
||||
|
||||
macx {
|
||||
message("macOS build")
|
||||
INCLUDEPATH += $$PWD/macos
|
||||
HEADERS += $$PWD/macos/botan_all.h
|
||||
SOURCES += $$PWD/macos/botan_all.cpp
|
||||
}
|
||||
|
||||
linux-g++ {
|
||||
message("Linux build")
|
||||
INCLUDEPATH += $$PWD/linux
|
||||
HEADERS += $$PWD/linux/botan_all.h
|
||||
SOURCES += $$PWD/linux/botan_all.cpp
|
||||
|
||||
LIBS += -ldl
|
||||
}
|
||||
|
||||
android {
|
||||
for (abi, ANDROID_ABIS): {
|
||||
equals(ANDROID_TARGET_ARCH,$$abi) {
|
||||
message("Android build for ANDROID_TARGET_ARCH" $$abi)
|
||||
INCLUDEPATH += $$PWD/android/$${abi}
|
||||
HEADERS += $$PWD/android/$${abi}/botan_all.h
|
||||
SOURCES += $$PWD/android/$${abi}/botan_all.cpp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
264
client/3rd/QtSsh/src/botan/include/external/pkcs11.h
vendored
264
client/3rd/QtSsh/src/botan/include/external/pkcs11.h
vendored
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01
|
||||
* Committee Specification Draft 01 / Public Review Draft 01
|
||||
* 09 December 2015
|
||||
* Copyright (c) OASIS Open 2015. All Rights Reserved.
|
||||
* Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/
|
||||
* Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
|
||||
* https://www.oasis-open.org/policies-guidelines/ipr
|
||||
*/
|
||||
|
||||
#ifndef _PKCS11_H_
|
||||
#define _PKCS11_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Before including this file (pkcs11.h) (or pkcs11t.h by
|
||||
* itself), 5 platform-specific macros must be defined. These
|
||||
* macros are described below, and typical definitions for them
|
||||
* are also given. Be advised that these definitions can depend
|
||||
* on both the platform and the compiler used (and possibly also
|
||||
* on whether a Cryptoki library is linked statically or
|
||||
* dynamically).
|
||||
*
|
||||
* In addition to defining these 5 macros, the packing convention
|
||||
* for Cryptoki structures should be set. The Cryptoki
|
||||
* convention on packing is that structures should be 1-byte
|
||||
* aligned.
|
||||
*
|
||||
* If you're using Microsoft Developer Studio 5.0 to produce
|
||||
* Win32 stuff, this might be done by using the following
|
||||
* preprocessor directive before including pkcs11.h or pkcs11t.h:
|
||||
*
|
||||
* #pragma pack(push, cryptoki, 1)
|
||||
*
|
||||
* and using the following preprocessor directive after including
|
||||
* pkcs11.h or pkcs11t.h:
|
||||
*
|
||||
* #pragma pack(pop, cryptoki)
|
||||
*
|
||||
* If you're using an earlier version of Microsoft Developer
|
||||
* Studio to produce Win16 stuff, this might be done by using
|
||||
* the following preprocessor directive before including
|
||||
* pkcs11.h or pkcs11t.h:
|
||||
*
|
||||
* #pragma pack(1)
|
||||
*
|
||||
* In a UNIX environment, you're on your own for this. You might
|
||||
* not need to do (or be able to do!) anything.
|
||||
*
|
||||
*
|
||||
* Now for the macros:
|
||||
*
|
||||
*
|
||||
* 1. CK_PTR: The indirection string for making a pointer to an
|
||||
* object. It can be used like this:
|
||||
*
|
||||
* typedef CK_BYTE CK_PTR CK_BYTE_PTR;
|
||||
*
|
||||
* If you're using Microsoft Developer Studio 5.0 to produce
|
||||
* Win32 stuff, it might be defined by:
|
||||
*
|
||||
* #define CK_PTR *
|
||||
*
|
||||
* If you're using an earlier version of Microsoft Developer
|
||||
* Studio to produce Win16 stuff, it might be defined by:
|
||||
*
|
||||
* #define CK_PTR far *
|
||||
*
|
||||
* In a typical UNIX environment, it might be defined by:
|
||||
*
|
||||
* #define CK_PTR *
|
||||
*
|
||||
*
|
||||
* 2. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
|
||||
* an importable Cryptoki library function declaration out of a
|
||||
* return type and a function name. It should be used in the
|
||||
* following fashion:
|
||||
*
|
||||
* extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
|
||||
* CK_VOID_PTR pReserved
|
||||
* );
|
||||
*
|
||||
* If you're using Microsoft Developer Studio 5.0 to declare a
|
||||
* function in a Win32 Cryptoki .dll, it might be defined by:
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION(returnType, name) \
|
||||
* returnType __declspec(dllimport) name
|
||||
*
|
||||
* If you're using an earlier version of Microsoft Developer
|
||||
* Studio to declare a function in a Win16 Cryptoki .dll, it
|
||||
* might be defined by:
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION(returnType, name) \
|
||||
* returnType __export _far _pascal name
|
||||
*
|
||||
* In a UNIX environment, it might be defined by:
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION(returnType, name) \
|
||||
* returnType name
|
||||
*
|
||||
*
|
||||
* 3. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
|
||||
* which makes a Cryptoki API function pointer declaration or
|
||||
* function pointer type declaration out of a return type and a
|
||||
* function name. It should be used in the following fashion:
|
||||
*
|
||||
* // Define funcPtr to be a pointer to a Cryptoki API function
|
||||
* // taking arguments args and returning CK_RV.
|
||||
* CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
|
||||
*
|
||||
* or
|
||||
*
|
||||
* // Define funcPtrType to be the type of a pointer to a
|
||||
* // Cryptoki API function taking arguments args and returning
|
||||
* // CK_RV, and then define funcPtr to be a variable of type
|
||||
* // funcPtrType.
|
||||
* typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
|
||||
* funcPtrType funcPtr;
|
||||
*
|
||||
* If you're using Microsoft Developer Studio 5.0 to access
|
||||
* functions in a Win32 Cryptoki .dll, in might be defined by:
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
|
||||
* returnType __declspec(dllimport) (* name)
|
||||
*
|
||||
* If you're using an earlier version of Microsoft Developer
|
||||
* Studio to access functions in a Win16 Cryptoki .dll, it might
|
||||
* be defined by:
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
|
||||
* returnType __export _far _pascal (* name)
|
||||
*
|
||||
* In a UNIX environment, it might be defined by:
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
|
||||
* returnType (* name)
|
||||
*
|
||||
*
|
||||
* 4. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
|
||||
* a function pointer type for an application callback out of
|
||||
* a return type for the callback and a name for the callback.
|
||||
* It should be used in the following fashion:
|
||||
*
|
||||
* CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
|
||||
*
|
||||
* to declare a function pointer, myCallback, to a callback
|
||||
* which takes arguments args and returns a CK_RV. It can also
|
||||
* be used like this:
|
||||
*
|
||||
* typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
|
||||
* myCallbackType myCallback;
|
||||
*
|
||||
* If you're using Microsoft Developer Studio 5.0 to do Win32
|
||||
* Cryptoki development, it might be defined by:
|
||||
*
|
||||
* #define CK_CALLBACK_FUNCTION(returnType, name) \
|
||||
* returnType (* name)
|
||||
*
|
||||
* If you're using an earlier version of Microsoft Developer
|
||||
* Studio to do Win16 development, it might be defined by:
|
||||
*
|
||||
* #define CK_CALLBACK_FUNCTION(returnType, name) \
|
||||
* returnType _far _pascal (* name)
|
||||
*
|
||||
* In a UNIX environment, it might be defined by:
|
||||
*
|
||||
* #define CK_CALLBACK_FUNCTION(returnType, name) \
|
||||
* returnType (* name)
|
||||
*
|
||||
*
|
||||
* 5. NULL_PTR: This macro is the value of a NULL pointer.
|
||||
*
|
||||
* In any ANSI/ISO C environment (and in many others as well),
|
||||
* this should best be defined by
|
||||
*
|
||||
* #ifndef NULL_PTR
|
||||
* #define NULL_PTR 0
|
||||
* #endif
|
||||
*/
|
||||
|
||||
|
||||
/* All the various Cryptoki types and #define'd values are in the
|
||||
* file pkcs11t.h.
|
||||
*/
|
||||
#include "pkcs11t.h"
|
||||
|
||||
#define __PASTE(x,y) x##y
|
||||
|
||||
|
||||
/* ==============================================================
|
||||
* Define the "extern" form of all the entry points.
|
||||
* ==============================================================
|
||||
*/
|
||||
|
||||
#define CK_NEED_ARG_LIST 1
|
||||
#define CK_PKCS11_FUNCTION_INFO(name) \
|
||||
extern CK_DECLARE_FUNCTION(CK_RV, name)
|
||||
|
||||
/* pkcs11f.h has all the information about the Cryptoki
|
||||
* function prototypes.
|
||||
*/
|
||||
#include "pkcs11f.h"
|
||||
|
||||
#undef CK_NEED_ARG_LIST
|
||||
#undef CK_PKCS11_FUNCTION_INFO
|
||||
|
||||
|
||||
/* ==============================================================
|
||||
* Define the typedef form of all the entry points. That is, for
|
||||
* each Cryptoki function C_XXX, define a type CK_C_XXX which is
|
||||
* a pointer to that kind of function.
|
||||
* ==============================================================
|
||||
*/
|
||||
|
||||
#define CK_NEED_ARG_LIST 1
|
||||
#define CK_PKCS11_FUNCTION_INFO(name) \
|
||||
typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
|
||||
|
||||
/* pkcs11f.h has all the information about the Cryptoki
|
||||
* function prototypes.
|
||||
*/
|
||||
#include "pkcs11f.h"
|
||||
|
||||
#undef CK_NEED_ARG_LIST
|
||||
#undef CK_PKCS11_FUNCTION_INFO
|
||||
|
||||
|
||||
/* ==============================================================
|
||||
* Define structed vector of entry points. A CK_FUNCTION_LIST
|
||||
* contains a CK_VERSION indicating a library's Cryptoki version
|
||||
* and then a whole slew of function pointers to the routines in
|
||||
* the library. This type was declared, but not defined, in
|
||||
* pkcs11t.h.
|
||||
* ==============================================================
|
||||
*/
|
||||
|
||||
#define CK_PKCS11_FUNCTION_INFO(name) \
|
||||
__PASTE(CK_,name) name;
|
||||
|
||||
struct CK_FUNCTION_LIST {
|
||||
|
||||
CK_VERSION version; /* Cryptoki version */
|
||||
|
||||
/* Pile all the function pointers into the CK_FUNCTION_LIST. */
|
||||
/* pkcs11f.h has all the information about the Cryptoki
|
||||
* function prototypes.
|
||||
*/
|
||||
#include "pkcs11f.h"
|
||||
|
||||
};
|
||||
|
||||
#undef CK_PKCS11_FUNCTION_INFO
|
||||
|
||||
|
||||
#undef __PASTE
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _PKCS11_H_ */
|
||||
|
||||
@@ -1,938 +0,0 @@
|
||||
/*
|
||||
* PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01
|
||||
* Committee Specification Draft 01 / Public Review Draft 01
|
||||
* 09 December 2015
|
||||
* Copyright (c) OASIS Open 2015. All Rights Reserved.
|
||||
* Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/
|
||||
* Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
|
||||
* https://www.oasis-open.org/policies-guidelines/ipr
|
||||
*/
|
||||
|
||||
/* This header file contains pretty much everything about all the
|
||||
* Cryptoki function prototypes. Because this information is
|
||||
* used for more than just declaring function prototypes, the
|
||||
* order of the functions appearing herein is important, and
|
||||
* should not be altered.
|
||||
*/
|
||||
|
||||
/* General-purpose */
|
||||
|
||||
/* C_Initialize initializes the Cryptoki library. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Initialize)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
|
||||
* cast to CK_C_INITIALIZE_ARGS_PTR
|
||||
* and dereferenced
|
||||
*/
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Finalize indicates that an application is done with the
|
||||
* Cryptoki library.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_Finalize)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetInfo returns general information about Cryptoki. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetInfo)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_INFO_PTR pInfo /* location that receives information */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetFunctionList returns the function list. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
|
||||
* function list
|
||||
*/
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Slot and token management */
|
||||
|
||||
/* C_GetSlotList obtains a list of slots in the system. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_BBOOL tokenPresent, /* only slots with tokens */
|
||||
CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
|
||||
CK_ULONG_PTR pulCount /* receives number of slots */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetSlotInfo obtains information about a particular slot in
|
||||
* the system.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* the ID of the slot */
|
||||
CK_SLOT_INFO_PTR pInfo /* receives the slot information */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetTokenInfo obtains information about a particular token
|
||||
* in the system.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* ID of the token's slot */
|
||||
CK_TOKEN_INFO_PTR pInfo /* receives the token information */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetMechanismList obtains a list of mechanism types
|
||||
* supported by a token.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* ID of token's slot */
|
||||
CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
|
||||
CK_ULONG_PTR pulCount /* gets # of mechs. */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetMechanismInfo obtains information about a particular
|
||||
* mechanism possibly supported by a token.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* ID of the token's slot */
|
||||
CK_MECHANISM_TYPE type, /* type of mechanism */
|
||||
CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_InitToken initializes a token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_InitToken)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* ID of the token's slot */
|
||||
CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */
|
||||
CK_ULONG ulPinLen, /* length in bytes of the PIN */
|
||||
CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_InitPIN initializes the normal user's PIN. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_InitPIN)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */
|
||||
CK_ULONG ulPinLen /* length in bytes of the PIN */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SetPIN modifies the PIN of the user who is logged in. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SetPIN)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_UTF8CHAR_PTR pOldPin, /* the old PIN */
|
||||
CK_ULONG ulOldLen, /* length of the old PIN */
|
||||
CK_UTF8CHAR_PTR pNewPin, /* the new PIN */
|
||||
CK_ULONG ulNewLen /* length of the new PIN */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Session management */
|
||||
|
||||
/* C_OpenSession opens a session between an application and a
|
||||
* token.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_OpenSession)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* the slot's ID */
|
||||
CK_FLAGS flags, /* from CK_SESSION_INFO */
|
||||
CK_VOID_PTR pApplication, /* passed to callback */
|
||||
CK_NOTIFY Notify, /* callback function */
|
||||
CK_SESSION_HANDLE_PTR phSession /* gets session handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_CloseSession closes a session between an application and a
|
||||
* token.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_CloseSession)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession /* the session's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_CloseAllSessions closes all sessions with a token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID /* the token's slot */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetSessionInfo obtains information about the session. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_SESSION_INFO_PTR pInfo /* receives session info */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetOperationState obtains the state of the cryptographic operation
|
||||
* in a session.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pOperationState, /* gets state */
|
||||
CK_ULONG_PTR pulOperationStateLen /* gets state length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SetOperationState restores the state of the cryptographic
|
||||
* operation in a session.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pOperationState, /* holds state */
|
||||
CK_ULONG ulOperationStateLen, /* holds state length */
|
||||
CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
|
||||
CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Login logs a user into a token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Login)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_USER_TYPE userType, /* the user type */
|
||||
CK_UTF8CHAR_PTR pPin, /* the user's PIN */
|
||||
CK_ULONG ulPinLen /* the length of the PIN */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Logout logs a user out from a token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Logout)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession /* the session's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Object management */
|
||||
|
||||
/* C_CreateObject creates a new object. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_CreateObject)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
|
||||
CK_ULONG ulCount, /* attributes in template */
|
||||
CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_CopyObject copies an object, creating a new object for the
|
||||
* copy.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_CopyObject)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
|
||||
CK_ULONG ulCount, /* attributes in template */
|
||||
CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DestroyObject destroys an object. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hObject /* the object's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetObjectSize gets the size of an object in bytes. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
||||
CK_ULONG_PTR pulSize /* receives size of object */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetAttributeValue obtains the value of one or more object
|
||||
* attributes.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
|
||||
CK_ULONG ulCount /* attributes in template */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SetAttributeValue modifies the value of one or more object
|
||||
* attributes.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
|
||||
CK_ULONG ulCount /* attributes in template */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_FindObjectsInit initializes a search for token and session
|
||||
* objects that match a template.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
|
||||
CK_ULONG ulCount /* attrs in search template */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_FindObjects continues a search for token and session
|
||||
* objects that match a template, obtaining additional object
|
||||
* handles.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_FindObjects)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
|
||||
CK_ULONG ulMaxObjectCount, /* max handles to get */
|
||||
CK_ULONG_PTR pulObjectCount /* actual # returned */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_FindObjectsFinal finishes a search for token and session
|
||||
* objects.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession /* the session's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Encryption and decryption */
|
||||
|
||||
/* C_EncryptInit initializes an encryption operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* handle of encryption key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Encrypt encrypts single-part data. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Encrypt)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pData, /* the plaintext data */
|
||||
CK_ULONG ulDataLen, /* bytes of plaintext */
|
||||
CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
|
||||
CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_EncryptUpdate continues a multiple-part encryption
|
||||
* operation.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pPart, /* the plaintext data */
|
||||
CK_ULONG ulPartLen, /* plaintext data len */
|
||||
CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
|
||||
CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_EncryptFinal finishes a multiple-part encryption
|
||||
* operation.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session handle */
|
||||
CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
|
||||
CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DecryptInit initializes a decryption operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* handle of decryption key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Decrypt decrypts encrypted data in a single part. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Decrypt)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pEncryptedData, /* ciphertext */
|
||||
CK_ULONG ulEncryptedDataLen, /* ciphertext length */
|
||||
CK_BYTE_PTR pData, /* gets plaintext */
|
||||
CK_ULONG_PTR pulDataLen /* gets p-text size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DecryptUpdate continues a multiple-part decryption
|
||||
* operation.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pEncryptedPart, /* encrypted data */
|
||||
CK_ULONG ulEncryptedPartLen, /* input length */
|
||||
CK_BYTE_PTR pPart, /* gets plaintext */
|
||||
CK_ULONG_PTR pulPartLen /* p-text size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DecryptFinal finishes a multiple-part decryption
|
||||
* operation.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pLastPart, /* gets plaintext */
|
||||
CK_ULONG_PTR pulLastPartLen /* p-text size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Message digesting */
|
||||
|
||||
/* C_DigestInit initializes a message-digesting operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DigestInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Digest digests data in a single part. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Digest)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pData, /* data to be digested */
|
||||
CK_ULONG ulDataLen, /* bytes of data to digest */
|
||||
CK_BYTE_PTR pDigest, /* gets the message digest */
|
||||
CK_ULONG_PTR pulDigestLen /* gets digest length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DigestUpdate continues a multiple-part message-digesting
|
||||
* operation.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pPart, /* data to be digested */
|
||||
CK_ULONG ulPartLen /* bytes of data to be digested */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DigestKey continues a multi-part message-digesting
|
||||
* operation, by digesting the value of a secret key as part of
|
||||
* the data already digested.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_DigestKey)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hKey /* secret key to digest */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DigestFinal finishes a multiple-part message-digesting
|
||||
* operation.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pDigest, /* gets the message digest */
|
||||
CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Signing and MACing */
|
||||
|
||||
/* C_SignInit initializes a signature (private key encryption)
|
||||
* operation, where the signature is (will be) an appendix to
|
||||
* the data, and plaintext cannot be recovered from the
|
||||
* signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* handle of signature key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Sign signs (encrypts with private key) data in a single
|
||||
* part, where the signature is (will be) an appendix to the
|
||||
* data, and plaintext cannot be recovered from the signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_Sign)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pData, /* the data to sign */
|
||||
CK_ULONG ulDataLen, /* count of bytes to sign */
|
||||
CK_BYTE_PTR pSignature, /* gets the signature */
|
||||
CK_ULONG_PTR pulSignatureLen /* gets signature length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SignUpdate continues a multiple-part signature operation,
|
||||
* where the signature is (will be) an appendix to the data,
|
||||
* and plaintext cannot be recovered from the signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pPart, /* the data to sign */
|
||||
CK_ULONG ulPartLen /* count of bytes to sign */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SignFinal finishes a multiple-part signature operation,
|
||||
* returning the signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pSignature, /* gets the signature */
|
||||
CK_ULONG_PTR pulSignatureLen /* gets signature length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SignRecoverInit initializes a signature operation, where
|
||||
* the data can be recovered from the signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* handle of the signature key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SignRecover signs data in a single operation, where the
|
||||
* data can be recovered from the signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignRecover)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pData, /* the data to sign */
|
||||
CK_ULONG ulDataLen, /* count of bytes to sign */
|
||||
CK_BYTE_PTR pSignature, /* gets the signature */
|
||||
CK_ULONG_PTR pulSignatureLen /* gets signature length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Verifying signatures and MACs */
|
||||
|
||||
/* C_VerifyInit initializes a verification operation, where the
|
||||
* signature is an appendix to the data, and plaintext cannot
|
||||
* cannot be recovered from the signature (e.g. DSA).
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* verification key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Verify verifies a signature in a single-part operation,
|
||||
* where the signature is an appendix to the data, and plaintext
|
||||
* cannot be recovered from the signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_Verify)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pData, /* signed data */
|
||||
CK_ULONG ulDataLen, /* length of signed data */
|
||||
CK_BYTE_PTR pSignature, /* signature */
|
||||
CK_ULONG ulSignatureLen /* signature length*/
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_VerifyUpdate continues a multiple-part verification
|
||||
* operation, where the signature is an appendix to the data,
|
||||
* and plaintext cannot be recovered from the signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pPart, /* signed data */
|
||||
CK_ULONG ulPartLen /* length of signed data */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_VerifyFinal finishes a multiple-part verification
|
||||
* operation, checking the signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pSignature, /* signature to verify */
|
||||
CK_ULONG ulSignatureLen /* signature length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_VerifyRecoverInit initializes a signature verification
|
||||
* operation, where the data is recovered from the signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* verification key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_VerifyRecover verifies a signature in a single-part
|
||||
* operation, where the data is recovered from the signature.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pSignature, /* signature to verify */
|
||||
CK_ULONG ulSignatureLen, /* signature length */
|
||||
CK_BYTE_PTR pData, /* gets signed data */
|
||||
CK_ULONG_PTR pulDataLen /* gets signed data len */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Dual-function cryptographic operations */
|
||||
|
||||
/* C_DigestEncryptUpdate continues a multiple-part digesting
|
||||
* and encryption operation.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pPart, /* the plaintext data */
|
||||
CK_ULONG ulPartLen, /* plaintext length */
|
||||
CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
|
||||
CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DecryptDigestUpdate continues a multiple-part decryption and
|
||||
* digesting operation.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pEncryptedPart, /* ciphertext */
|
||||
CK_ULONG ulEncryptedPartLen, /* ciphertext length */
|
||||
CK_BYTE_PTR pPart, /* gets plaintext */
|
||||
CK_ULONG_PTR pulPartLen /* gets plaintext len */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SignEncryptUpdate continues a multiple-part signing and
|
||||
* encryption operation.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pPart, /* the plaintext data */
|
||||
CK_ULONG ulPartLen, /* plaintext length */
|
||||
CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
|
||||
CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DecryptVerifyUpdate continues a multiple-part decryption and
|
||||
* verify operation.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pEncryptedPart, /* ciphertext */
|
||||
CK_ULONG ulEncryptedPartLen, /* ciphertext length */
|
||||
CK_BYTE_PTR pPart, /* gets plaintext */
|
||||
CK_ULONG_PTR pulPartLen /* gets p-text length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Key management */
|
||||
|
||||
/* C_GenerateKey generates a secret key, creating a new key
|
||||
* object.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* key generation mech. */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
|
||||
CK_ULONG ulCount, /* # of attrs in template */
|
||||
CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GenerateKeyPair generates a public-key/private-key pair,
|
||||
* creating new key objects.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* key-gen mech. */
|
||||
CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template for pub. key */
|
||||
CK_ULONG ulPublicKeyAttributeCount, /* # pub. attrs. */
|
||||
CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template for priv. key */
|
||||
CK_ULONG ulPrivateKeyAttributeCount, /* # priv. attrs. */
|
||||
CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub. key handle */
|
||||
CK_OBJECT_HANDLE_PTR phPrivateKey /* gets priv. key handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_WrapKey wraps (i.e., encrypts) a key. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_WrapKey)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
|
||||
CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
|
||||
CK_OBJECT_HANDLE hKey, /* key to be wrapped */
|
||||
CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
|
||||
CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
|
||||
* key object.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
|
||||
CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
|
||||
CK_BYTE_PTR pWrappedKey, /* the wrapped key */
|
||||
CK_ULONG ulWrappedKeyLen, /* wrapped key len */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* new key template */
|
||||
CK_ULONG ulAttributeCount, /* template length */
|
||||
CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DeriveKey derives a key from a base key, creating a new key
|
||||
* object.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
|
||||
CK_OBJECT_HANDLE hBaseKey, /* base key */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* new key template */
|
||||
CK_ULONG ulAttributeCount, /* template length */
|
||||
CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Random number generation */
|
||||
|
||||
/* C_SeedRandom mixes additional seed material into the token's
|
||||
* random number generator.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pSeed, /* the seed material */
|
||||
CK_ULONG ulSeedLen /* length of seed material */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GenerateRandom generates random data. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR RandomData, /* receives the random data */
|
||||
CK_ULONG ulRandomLen /* # of bytes to generate */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Parallel function management */
|
||||
|
||||
/* C_GetFunctionStatus is a legacy function; it obtains an
|
||||
* updated status of a function running in parallel with an
|
||||
* application.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession /* the session's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_CancelFunction is a legacy function; it cancels a function
|
||||
* running in parallel.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession /* the session's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_WaitForSlotEvent waits for a slot event (token insertion,
|
||||
* removal, etc.) to occur.
|
||||
*/
|
||||
CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_FLAGS flags, /* blocking/nonblocking flag */
|
||||
CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
|
||||
CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
|
||||
);
|
||||
#endif
|
||||
|
||||
2002
client/3rd/QtSsh/src/botan/include/external/pkcs11t.h
vendored
2002
client/3rd/QtSsh/src/botan/include/external/pkcs11t.h
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 862 B |
Binary file not shown.
|
Before Width: | Height: | Size: 430 B |
Binary file not shown.
|
Before Width: | Height: | Size: 345 B |
@@ -1,200 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "opensshkeyfilereader_p.h"
|
||||
|
||||
#include "sshcapabilities_p.h"
|
||||
#include "ssherrors.h"
|
||||
#include "sshexception_p.h"
|
||||
#include "sshlogging_p.h"
|
||||
#include "sshpacketparser_p.h"
|
||||
#include "ssh_global.h"
|
||||
|
||||
#include <botan_all.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
using namespace Botan;
|
||||
|
||||
bool OpenSshKeyFileReader::parseKey(const QByteArray &privKeyFileContents)
|
||||
{
|
||||
static const QByteArray magicPrefix = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
|
||||
static const QByteArray magicSuffix = "-----END OPENSSH PRIVATE KEY-----\n";
|
||||
if (!privKeyFileContents.startsWith(magicPrefix)) {
|
||||
qCDebug(sshLog) << "not an OpenSSH key file: prefix does not match";
|
||||
return false;
|
||||
}
|
||||
if (!privKeyFileContents.endsWith(magicSuffix))
|
||||
throwException(SSH_TR("Unexpected end-of-file marker."));
|
||||
const QByteArray payload = QByteArray::fromBase64
|
||||
(privKeyFileContents.mid(magicPrefix.size(), privKeyFileContents.size()
|
||||
- magicPrefix.size() - magicSuffix.size()));
|
||||
doParse(payload);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Private_Key> OpenSshKeyFileReader::privateKey() const
|
||||
{
|
||||
if (m_keyType == SshCapabilities::PubKeyRsa) {
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(m_parameters.size() == 5, nullptr);
|
||||
const BigInt &e = m_parameters.at(0);
|
||||
const BigInt &n = m_parameters.at(1);
|
||||
const BigInt &p = m_parameters.at(2);
|
||||
const BigInt &q = m_parameters.at(3);
|
||||
const BigInt &d = m_parameters.at(4);
|
||||
return std::make_unique<RSA_PrivateKey>(p, q, e, d, n);
|
||||
} else if (m_keyType == SshCapabilities::PubKeyDss) {
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(m_parameters.size() == 5, nullptr);
|
||||
const BigInt &p = m_parameters.at(0);
|
||||
const BigInt &q = m_parameters.at(1);
|
||||
const BigInt &g = m_parameters.at(2);
|
||||
const BigInt &x = m_parameters.at(4);
|
||||
return std::make_unique<DSA_PrivateKey>(m_rng, DL_Group(p, q, g), x);
|
||||
} else if (m_keyType.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(m_parameters.size() == 1, nullptr);
|
||||
const BigInt &value = m_parameters.first();
|
||||
const EC_Group group(SshCapabilities::oid(m_keyType));
|
||||
return std::make_unique<ECDSA_PrivateKey>(m_rng, group, value);
|
||||
}
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(false, nullptr);
|
||||
}
|
||||
|
||||
QList<BigInt> OpenSshKeyFileReader::publicParameters() const
|
||||
{
|
||||
if (m_keyType == SshCapabilities::PubKeyRsa)
|
||||
return m_parameters.mid(0, 2);
|
||||
if (m_keyType == SshCapabilities::PubKeyDss)
|
||||
return m_parameters.mid(0, 4);
|
||||
if (m_keyType.startsWith(SshCapabilities::PubKeyEcdsaPrefix))
|
||||
return QList<BigInt>();
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(false, QList<BigInt>());
|
||||
}
|
||||
|
||||
void OpenSshKeyFileReader::doParse(const QByteArray &payload)
|
||||
{
|
||||
// See PROTOCOL.key in OpenSSH sources.
|
||||
static const QByteArray magicString = "openssh-key-v1";
|
||||
if (!payload.startsWith(magicString))
|
||||
throwException(SSH_TR("Unexpected magic string."));
|
||||
try {
|
||||
quint32 offset = magicString.size() + 1; // null byte
|
||||
m_cipherName = SshPacketParser::asString(payload, &offset);
|
||||
qCDebug(sshLog) << "cipher:" << m_cipherName;
|
||||
m_kdf = SshPacketParser::asString(payload, &offset);
|
||||
qCDebug(sshLog) << "kdf:" << m_kdf;
|
||||
parseKdfOptions(SshPacketParser::asString(payload, &offset));
|
||||
const quint32 keyCount = SshPacketParser::asUint32(payload, &offset);
|
||||
if (keyCount != 1) {
|
||||
qCWarning(sshLog) << "more than one key found in OpenSSH private key file, ignoring "
|
||||
"all but the first one";
|
||||
}
|
||||
for (quint32 i = 0; i < keyCount; ++i) // Skip the public key blob(s).
|
||||
SshPacketParser::asString(payload, &offset);
|
||||
m_privateKeyList = SshPacketParser::asString(payload, &offset);
|
||||
decryptPrivateKeyList();
|
||||
parsePrivateKeyList();
|
||||
} catch (const SshPacketParseException &) {
|
||||
throwException(SSH_TR("Parse error."));
|
||||
} catch (const Exception &e) {
|
||||
throwException(QLatin1String(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void OpenSshKeyFileReader::parseKdfOptions(const QByteArray &kdfOptions)
|
||||
{
|
||||
if (m_cipherName == "none")
|
||||
return;
|
||||
quint32 offset = 0;
|
||||
m_salt = SshPacketParser::asString(kdfOptions, &offset);
|
||||
if (m_salt.size() != 16)
|
||||
throwException(SSH_TR("Invalid salt size %1.").arg(m_salt.size()));
|
||||
m_rounds = SshPacketParser::asUint32(kdfOptions, &offset);
|
||||
qCDebug(sshLog) << "salt:" << m_salt.toHex();
|
||||
qCDebug(sshLog) << "rounds:" << m_rounds;
|
||||
}
|
||||
|
||||
void OpenSshKeyFileReader::decryptPrivateKeyList()
|
||||
{
|
||||
if (m_cipherName == "none")
|
||||
return;
|
||||
if (m_kdf != "bcrypt") {
|
||||
throwException(SSH_TR("Unexpected key derivation function '%1'.")
|
||||
.arg(QLatin1String(m_kdf)));
|
||||
}
|
||||
|
||||
// OpenSSH uses a proprietary algorithm for the key derivation. We'd basically have to
|
||||
// copy the code.
|
||||
// TODO: If the lower-level operations (hashing primitives, blowfish stuff) can be taken
|
||||
// over by Botan, that might be feasible. Investigate.
|
||||
throwException(SSH_TR("Encrypted keys are currently not supported in this format."));
|
||||
}
|
||||
|
||||
void OpenSshKeyFileReader::parsePrivateKeyList()
|
||||
{
|
||||
quint32 offset = 0;
|
||||
const quint32 checkInt1 = SshPacketParser::asUint32(m_privateKeyList, &offset);
|
||||
const quint32 checkInt2 = SshPacketParser::asUint32(m_privateKeyList, &offset);
|
||||
if (checkInt1 != checkInt2)
|
||||
throwException(SSH_TR("Verification failed."));
|
||||
m_keyType = SshPacketParser::asString(m_privateKeyList, &offset);
|
||||
qCDebug(sshLog) << "key type:" << m_keyType;
|
||||
if (m_keyType == SshCapabilities::PubKeyRsa) {
|
||||
const BigInt n = SshPacketParser::asBigInt(m_privateKeyList, &offset);
|
||||
const BigInt e = SshPacketParser::asBigInt(m_privateKeyList, &offset);
|
||||
const BigInt d = SshPacketParser::asBigInt(m_privateKeyList, &offset);
|
||||
SshPacketParser::asBigInt(m_privateKeyList, &offset); // iqmp
|
||||
const BigInt p = SshPacketParser::asBigInt(m_privateKeyList, &offset);
|
||||
const BigInt q = SshPacketParser::asBigInt(m_privateKeyList, &offset);
|
||||
m_parameters = QList<BigInt>{e, n, p, q, d};
|
||||
} else if (m_keyType == SshCapabilities::PubKeyDss) {
|
||||
const BigInt p = SshPacketParser::asBigInt(m_privateKeyList, &offset);
|
||||
const BigInt q = SshPacketParser::asBigInt(m_privateKeyList, &offset);
|
||||
const BigInt g = SshPacketParser::asBigInt(m_privateKeyList, &offset);
|
||||
const BigInt y = SshPacketParser::asBigInt(m_privateKeyList, &offset);
|
||||
const BigInt x = SshPacketParser::asBigInt(m_privateKeyList, &offset);
|
||||
m_parameters = QList<BigInt>{p, q, g, y, x};
|
||||
} else if (m_keyType.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
|
||||
SshPacketParser::asString(m_privateKeyList, &offset); // name
|
||||
SshPacketParser::asString(m_privateKeyList, &offset); // pubkey representation
|
||||
m_parameters = {SshPacketParser::asBigInt(m_privateKeyList, &offset)};
|
||||
} else {
|
||||
throwException(SSH_TR("Private key type '%1' is not supported.")
|
||||
.arg(QString::fromLatin1(m_keyType)));
|
||||
}
|
||||
const QByteArray comment = SshPacketParser::asString(m_privateKeyList, &offset);
|
||||
qCDebug(sshLog) << "comment:" << comment;
|
||||
}
|
||||
|
||||
void OpenSshKeyFileReader::throwException(const QString &reason)
|
||||
{
|
||||
throw SshClientException(SshKeyFileError,
|
||||
SSH_TR("Processing OpenSSH private key file failed: %1").arg(reason));
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
@@ -1,73 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
|
||||
#include <botan_all.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Botan {
|
||||
class Private_Key;
|
||||
class RandomNumberGenerator;
|
||||
}
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
class OpenSshKeyFileReader
|
||||
{
|
||||
public:
|
||||
OpenSshKeyFileReader(Botan::RandomNumberGenerator &rng) : m_rng(rng) {}
|
||||
|
||||
bool parseKey(const QByteArray &privKeyFileContents);
|
||||
QByteArray keyType() const { return m_keyType; }
|
||||
std::unique_ptr<Botan::Private_Key> privateKey() const;
|
||||
QList<Botan::BigInt> allParameters() const { return m_parameters; }
|
||||
QList<Botan::BigInt> publicParameters() const;
|
||||
|
||||
private:
|
||||
void doParse(const QByteArray &payload);
|
||||
void parseKdfOptions(const QByteArray &kdfOptions);
|
||||
void decryptPrivateKeyList();
|
||||
void parsePrivateKeyList();
|
||||
[[noreturn]] void throwException(const QString &reason);
|
||||
|
||||
Botan::RandomNumberGenerator &m_rng;
|
||||
QByteArray m_keyType;
|
||||
QList<Botan::BigInt> m_parameters;
|
||||
QByteArray m_cipherName;
|
||||
QByteArray m_kdf;
|
||||
QByteArray m_salt;
|
||||
quint32 m_rounds;
|
||||
QByteArray m_privateKeyList;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
QT += gui network widgets
|
||||
|
||||
INCLUDEPATH += $$PWD
|
||||
DEPENDPATH += $$PWD
|
||||
|
||||
#!win32-msvc* {
|
||||
# QMAKE_CXXFLAGS += -Wextra -pedantic
|
||||
#}
|
||||
|
||||
#contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
|
||||
|
||||
SOURCES = $$PWD/sshsendfacility.cpp \
|
||||
$$PWD/sshremoteprocess.cpp \
|
||||
$$PWD/sshpacketparser.cpp \
|
||||
$$PWD/sshpacket.cpp \
|
||||
$$PWD/sshoutgoingpacket.cpp \
|
||||
$$PWD/sshkeygenerator.cpp \
|
||||
$$PWD/sshkeyexchange.cpp \
|
||||
$$PWD/sshincomingpacket.cpp \
|
||||
$$PWD/sshcryptofacility.cpp \
|
||||
$$PWD/sshconnection.cpp \
|
||||
$$PWD/sshchannelmanager.cpp \
|
||||
$$PWD/sshchannel.cpp \
|
||||
$$PWD/sshcapabilities.cpp \
|
||||
$$PWD/sftppacket.cpp \
|
||||
$$PWD/sftpoutgoingpacket.cpp \
|
||||
$$PWD/sftpoperation.cpp \
|
||||
$$PWD/sftpincomingpacket.cpp \
|
||||
$$PWD/sftpdefs.cpp \
|
||||
$$PWD/sftpchannel.cpp \
|
||||
$$PWD/sshremoteprocessrunner.cpp \
|
||||
$$PWD/sshconnectionmanager.cpp \
|
||||
$$PWD/sshkeypasswordretriever.cpp \
|
||||
$$PWD/sftpfilesystemmodel.cpp \
|
||||
$$PWD/sshdirecttcpiptunnel.cpp \
|
||||
$$PWD/sshhostkeydatabase.cpp \
|
||||
$$PWD/sshlogging.cpp \
|
||||
$$PWD/sshtcpipforwardserver.cpp \
|
||||
$$PWD/sshtcpiptunnel.cpp \
|
||||
$$PWD/sshforwardedtcpiptunnel.cpp \
|
||||
$$PWD/sshagent.cpp \
|
||||
$$PWD/sshx11channel.cpp \
|
||||
$$PWD/sshx11inforetriever.cpp \
|
||||
$$PWD/opensshkeyfilereader.cpp \
|
||||
|
||||
PUBLIC_HEADERS = \
|
||||
$$PWD/sftpdefs.h \
|
||||
$$PWD/ssherrors.h \
|
||||
$$PWD/sshremoteprocess.h \
|
||||
$$PWD/sftpchannel.h \
|
||||
$$PWD/sshkeygenerator.h \
|
||||
$$PWD/sshremoteprocessrunner.h \
|
||||
$$PWD/sshconnectionmanager.h \
|
||||
$$PWD/sshpseudoterminal.h \
|
||||
$$PWD/sftpfilesystemmodel.h \
|
||||
$$PWD/sshdirecttcpiptunnel.h \
|
||||
$$PWD/sshtcpipforwardserver.h \
|
||||
$$PWD/sshhostkeydatabase.h \
|
||||
$$PWD/sshforwardedtcpiptunnel.h \
|
||||
$$PWD/ssh_global.h \
|
||||
$$PWD/sshconnection.h \
|
||||
|
||||
HEADERS = $$PUBLIC_HEADERS \
|
||||
$$PWD/sshsendfacility_p.h \
|
||||
$$PWD/sshremoteprocess_p.h \
|
||||
$$PWD/sshpacketparser_p.h \
|
||||
$$PWD/sshpacket_p.h \
|
||||
$$PWD/sshoutgoingpacket_p.h \
|
||||
$$PWD/sshkeyexchange_p.h \
|
||||
$$PWD/sshincomingpacket_p.h \
|
||||
$$PWD/sshexception_p.h \
|
||||
$$PWD/sshcryptofacility_p.h \
|
||||
$$PWD/sshconnection_p.h \
|
||||
$$PWD/sshchannelmanager_p.h \
|
||||
$$PWD/sshchannel_p.h \
|
||||
$$PWD/sshcapabilities_p.h \
|
||||
$$PWD/sshbotanconversions_p.h \
|
||||
$$PWD/sftppacket_p.h \
|
||||
$$PWD/sftpoutgoingpacket_p.h \
|
||||
$$PWD/sftpoperation_p.h \
|
||||
$$PWD/sftpincomingpacket_p.h \
|
||||
$$PWD/sftpchannel_p.h \
|
||||
$$PWD/sshkeypasswordretriever_p.h \
|
||||
$$PWD/sshdirecttcpiptunnel_p.h \
|
||||
$$PWD/sshlogging_p.h \
|
||||
$$PWD/sshtcpipforwardserver_p.h \
|
||||
$$PWD/sshtcpiptunnel_p.h \
|
||||
$$PWD/sshforwardedtcpiptunnel_p.h \
|
||||
$$PWD/sshagent_p.h \
|
||||
$$PWD/sshx11channel_p.h \
|
||||
$$PWD/sshx11displayinfo_p.h \
|
||||
$$PWD/sshx11inforetriever_p.h \
|
||||
$$PWD/opensshkeyfilereader_p.h \
|
||||
|
||||
RESOURCES += $$PWD/qssh.qrc
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/ssh">
|
||||
<file>images/dir.png</file>
|
||||
<file>images/help.png</file>
|
||||
<file>images/unknownfile.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,263 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SFTCHANNEL_H
|
||||
#define SFTCHANNEL_H
|
||||
|
||||
#include "sftpdefs.h"
|
||||
|
||||
#include "ssh_global.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
|
||||
namespace QSsh {
|
||||
|
||||
namespace Internal {
|
||||
class SftpChannelPrivate;
|
||||
class SshChannelManager;
|
||||
class SshSendFacility;
|
||||
} // namespace Internal
|
||||
|
||||
|
||||
/*!
|
||||
\class QSsh::SftpChannel
|
||||
|
||||
\brief This class provides SFTP operations.
|
||||
|
||||
Objects are created via SshConnection::createSftpChannel().
|
||||
The channel needs to be initialized with
|
||||
a call to initialize() and is closed via closeChannel(). After closing
|
||||
a channel, no more operations are possible. It cannot be re-opened
|
||||
using initialize(); use SshConnection::createSftpChannel() if you need
|
||||
a new one.
|
||||
|
||||
After the initialized() signal has been emitted, operations can be started.
|
||||
All SFTP operations are asynchronous (non-blocking) and can be in-flight
|
||||
simultaneously (though callers must ensure that concurrently running jobs
|
||||
are independent of each other, e.g. they must not write to the same file).
|
||||
Operations are identified by their job id, which is returned by
|
||||
the respective member function. If the function can right away detect that
|
||||
the operation cannot succeed, it returns SftpInvalidJob. If an error occurs
|
||||
later, the finished() signal is emitted for the respective job with a
|
||||
non-empty error string.
|
||||
|
||||
Note that directory names must not have a trailing slash.
|
||||
*/
|
||||
|
||||
class QSSH_EXPORT SftpChannel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class Internal::SftpChannelPrivate;
|
||||
friend class Internal::SshChannelManager;
|
||||
public:
|
||||
/// Convenience typedef
|
||||
typedef QSharedPointer<SftpChannel> Ptr;
|
||||
|
||||
/// \see state
|
||||
enum State { Uninitialized, Initializing, Initialized, Closing, Closed };
|
||||
|
||||
/// Current state of this channel
|
||||
State state() const;
|
||||
|
||||
/*!
|
||||
* @brief Makes this channel ready to use.
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
/*!
|
||||
* @brief Call this when you are done with the channel.
|
||||
*/
|
||||
void closeChannel();
|
||||
|
||||
/*!
|
||||
* \brief Get information about a remote path, file or directory
|
||||
* \param path Remote path to state
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId statFile(const QString &path);
|
||||
|
||||
/*!
|
||||
* \brief Get list of contents of a directory
|
||||
* \param dirPath Remote path of directory
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId listDirectory(const QString &dirPath);
|
||||
|
||||
/*!
|
||||
* \brief Create remote directory
|
||||
* \param dirPath Remote path of directory
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId createDirectory(const QString &dirPath);
|
||||
|
||||
/*!
|
||||
* \brief Remove remote directory
|
||||
* \param dirPath Remote path of directory
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId removeDirectory(const QString &dirPath);
|
||||
|
||||
/*!
|
||||
* \brief Remove remote file
|
||||
* \param filePath Remote path of file
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId removeFile(const QString &filePath);
|
||||
|
||||
/*!
|
||||
* \brief Rename or move a remote file or directory
|
||||
* \param oldPath Path of existing file or directory
|
||||
* \param newPath New path the file or directory should be available as
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId renameFileOrDirectory(const QString &oldPath,
|
||||
const QString &newPath);
|
||||
|
||||
/*!
|
||||
* \brief Create a new empty file.
|
||||
* \param filePath Remote path of the file.
|
||||
* \param mode The behavior if the file already exists.
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId createFile(const QString &filePath, SftpOverwriteMode mode);
|
||||
|
||||
/*!
|
||||
* \brief Creates a symbolic link pointing to another file.
|
||||
* \param filePath The path of the symbolic
|
||||
* \param target The path the symbolic link should point to
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId createLink(const QString &filePath, const QString &target);
|
||||
|
||||
/*!
|
||||
* \brief Creates a remote file and fills it with data from \a device
|
||||
* \param device If this is not open already it will be opened in \a QIODevice::ReadOnly mode
|
||||
* \param remoteFilePath The path on the server to upload the file to
|
||||
* \param mode #QSsh::SftpOverwriteMode defines the behavior if the file already exists
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId uploadFile(QSharedPointer<QIODevice> device,
|
||||
const QString &remoteFilePath, SftpOverwriteMode mode);
|
||||
|
||||
/*!
|
||||
* \brief Uploads a local file to the remote host.
|
||||
* \param localFilePath The local path to an existing file
|
||||
* \param remoteFilePath The remote path the file should be uploaded to
|
||||
* \param mode What it will do if the file already exists
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId uploadFile(const QString &localFilePath,
|
||||
const QString &remoteFilePath, SftpOverwriteMode mode);
|
||||
|
||||
/*!
|
||||
* \brief Downloads a remote file to a local path
|
||||
* \param remoteFilePath The remote path to the file to be downloaded
|
||||
* \param localFilePath The local path for where to download the file
|
||||
* \param mode Controls what happens if the local file already exists
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId downloadFile(const QString &remoteFilePath,
|
||||
const QString &localFilePath, SftpOverwriteMode mode);
|
||||
|
||||
/*!
|
||||
* \brief Retrieves the contents of a remote file and writes it to \a device
|
||||
* \param remoteFilePath The remote path of the file to retrieve the contents of
|
||||
* \param device The QIODevice to write the data to, this needs to be open in a writable mode
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId downloadFile(const QString &remoteFilePath,
|
||||
QSharedPointer<QIODevice> device);
|
||||
|
||||
/*!
|
||||
* \brief Uploads a local directory (recursively) with files to the remote host
|
||||
* \param localDirPath The path to an existing local directory
|
||||
* \param remoteParentDirPath The remote path to upload it to, the name of the local directory will be appended to this
|
||||
* \return A unique ID identifying this job
|
||||
*/
|
||||
SftpJobId uploadDir(const QString &localDirPath,
|
||||
const QString &remoteParentDirPath);
|
||||
|
||||
/*!
|
||||
* \brief Downloads a remote directory (recursively) to a local path
|
||||
* \param remoteDirPath The remote path of an existing directory to download
|
||||
* \param localDirPath The local path to download the directory to
|
||||
* \param mode
|
||||
* \return
|
||||
*/
|
||||
SftpJobId downloadDir(const QString &remoteDirPath,
|
||||
const QString &localDirPath, SftpOverwriteMode mode);
|
||||
|
||||
~SftpChannel();
|
||||
|
||||
signals:
|
||||
/// Emitted when you can start using the channel
|
||||
void initialized();
|
||||
|
||||
/// Emitted when an error happened
|
||||
void channelError(const QString &reason);
|
||||
|
||||
/// Emitted when the channel has closed for some reason, either an error occured or it was asked for.
|
||||
void closed();
|
||||
|
||||
/// error.isEmpty means it finished successfully
|
||||
void finished(QSsh::SftpJobId job, const SftpError errorType = SftpError::NoError, const QString &error = QString());
|
||||
|
||||
/*!
|
||||
* Continously emitted during data transfer.
|
||||
* Does not emit for each file copied by uploadDir().
|
||||
*/
|
||||
void dataAvailable(QSsh::SftpJobId job, const QString &data);
|
||||
|
||||
/*!
|
||||
* This signal is emitted as a result of:
|
||||
* - statFile() (with the list having exactly one element)
|
||||
* - listDirectory() (potentially more than once)
|
||||
* It will continously be emitted as data is discovered, not only when the job is done.
|
||||
*/
|
||||
void fileInfoAvailable(QSsh::SftpJobId job, const QList<QSsh::SftpFileInfo> &fileInfoList);
|
||||
|
||||
/*!
|
||||
* Emitted during upload or download
|
||||
*/
|
||||
void transferProgress(QSsh::SftpJobId job, quint64 progress, quint64 total);
|
||||
|
||||
private:
|
||||
SftpChannel(quint32 channelId, Internal::SshSendFacility &sendFacility);
|
||||
|
||||
Internal::SftpChannelPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // SFTPCHANNEL_H
|
||||
@@ -1,135 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SFTCHANNEL_P_H
|
||||
#define SFTCHANNEL_P_H
|
||||
|
||||
#include "sftpdefs.h"
|
||||
#include "sftpincomingpacket_p.h"
|
||||
#include "sftpoperation_p.h"
|
||||
#include "sftpoutgoingpacket_p.h"
|
||||
#include "sshchannel_p.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMap>
|
||||
|
||||
namespace QSsh {
|
||||
class SftpChannel;
|
||||
namespace Internal {
|
||||
|
||||
class SftpChannelPrivate : public AbstractSshChannel
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class QSsh::SftpChannel;
|
||||
public:
|
||||
enum SftpState { Inactive, SubsystemRequested, InitSent, Initialized };
|
||||
|
||||
signals:
|
||||
void initialized();
|
||||
void channelError(const QString &reason);
|
||||
void closed();
|
||||
void finished(QSsh::SftpJobId job, const SftpError errorType = SftpError::NoError, const QString &error = QString());
|
||||
void dataAvailable(QSsh::SftpJobId job, const QString &data);
|
||||
void fileInfoAvailable(QSsh::SftpJobId job, const QList<QSsh::SftpFileInfo> &fileInfoList);
|
||||
void transferProgress(QSsh::SftpJobId job, quint64 progress, quint64 total);
|
||||
|
||||
private:
|
||||
typedef QMap<SftpJobId, AbstractSftpOperation::Ptr> JobMap;
|
||||
|
||||
SftpChannelPrivate(quint32 channelId, SshSendFacility &sendFacility,
|
||||
SftpChannel *sftp);
|
||||
SftpJobId createJob(const AbstractSftpOperation::Ptr &job);
|
||||
|
||||
virtual void handleChannelSuccess();
|
||||
virtual void handleChannelFailure();
|
||||
|
||||
virtual void handleOpenSuccessInternal();
|
||||
virtual void handleOpenFailureInternal(const QString &reason);
|
||||
virtual void handleChannelDataInternal(const QByteArray &data);
|
||||
virtual void handleChannelExtendedDataInternal(quint32 type,
|
||||
const QByteArray &data);
|
||||
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
|
||||
virtual void handleExitSignal(const SshChannelExitSignal &signal);
|
||||
|
||||
virtual void closeHook();
|
||||
|
||||
void handleCurrentPacket();
|
||||
void handleServerVersion();
|
||||
void handleHandle();
|
||||
void handleStatus();
|
||||
void handleName();
|
||||
void handleReadData();
|
||||
void handleAttrs();
|
||||
|
||||
void handleDownloadDir(SftpListDir::Ptr op, const QList<SftpFileInfo> & fileInfoList);
|
||||
|
||||
void handleStatusGeneric(JobMap::Iterator it,
|
||||
const SftpStatusResponse &response);
|
||||
void handleMkdirStatus(JobMap::Iterator it,
|
||||
const SftpStatusResponse &response);
|
||||
void handleLsStatus(JobMap::Iterator it,
|
||||
const SftpStatusResponse &response);
|
||||
void handleGetStatus(JobMap::Iterator it,
|
||||
const SftpStatusResponse &response);
|
||||
void handlePutStatus(JobMap::Iterator it,
|
||||
const SftpStatusResponse &response);
|
||||
|
||||
void handleLsHandle(JobMap::Iterator it);
|
||||
void handleCreateFileHandle(JobMap::Iterator it);
|
||||
void handleGetHandle(JobMap::Iterator it);
|
||||
void handlePutHandle(JobMap::Iterator it);
|
||||
|
||||
void spawnReadRequests(const SftpDownload::Ptr &job);
|
||||
void spawnWriteRequests(JobMap::Iterator it);
|
||||
void sendReadRequest(const SftpDownload::Ptr &job, quint32 requestId);
|
||||
void sendWriteRequest(JobMap::Iterator it);
|
||||
void finishTransferRequest(JobMap::Iterator it);
|
||||
void removeTransferRequest(JobMap::Iterator it);
|
||||
void reportRequestError(const AbstractSftpOperationWithHandle::Ptr &job, const SftpError errorType,
|
||||
const QString &error);
|
||||
void sendTransferCloseHandle(const AbstractSftpTransfer::Ptr &job,
|
||||
quint32 requestId);
|
||||
|
||||
void attributesToFileInfo(const SftpFileAttributes &attributes, SftpFileInfo &fileInfo) const;
|
||||
|
||||
JobMap::Iterator lookupJob(SftpJobId id);
|
||||
JobMap m_jobs;
|
||||
SftpOutgoingPacket m_outgoingPacket;
|
||||
SftpIncomingPacket m_incomingPacket;
|
||||
QByteArray m_incomingData;
|
||||
SftpJobId m_nextJobId;
|
||||
SftpState m_sftpState;
|
||||
SftpChannel *m_sftp;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // SFTPCHANNEL_P_H
|
||||
@@ -1,33 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "sftpdefs.h"
|
||||
|
||||
namespace QSsh { const SftpJobId SftpInvalidJob = 0; }
|
||||
@@ -1,119 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SFTPDEFS_H
|
||||
#define SFTPDEFS_H
|
||||
|
||||
#include "ssh_global.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
|
||||
/*!
|
||||
* \namespace QSsh
|
||||
* \brief The namespace used for the entire library
|
||||
*/
|
||||
namespace QSsh {
|
||||
|
||||
|
||||
/*!
|
||||
*\brief Unique ID used for tracking individual jobs.
|
||||
*/
|
||||
typedef quint32 SftpJobId;
|
||||
|
||||
/*!
|
||||
Special ID representing an invalid job, e. g. if a requested job could not be started.
|
||||
*/
|
||||
QSSH_EXPORT extern const SftpJobId SftpInvalidJob;
|
||||
|
||||
|
||||
/*!
|
||||
* \brief The behavior when uploading a file and the remote path already exists
|
||||
*/
|
||||
enum SftpOverwriteMode {
|
||||
/*! Overwrite any existing files */
|
||||
SftpOverwriteExisting,
|
||||
|
||||
/*! Append new content if the file already exists */
|
||||
SftpAppendToExisting,
|
||||
|
||||
/*! If the file or directory already exists skip it */
|
||||
SftpSkipExisting
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The type of a remote file.
|
||||
*/
|
||||
enum SftpFileType { FileTypeRegular, FileTypeDirectory, FileTypeOther, FileTypeUnknown };
|
||||
|
||||
/*!
|
||||
* \brief Possible errors.
|
||||
*/
|
||||
enum SftpError { NoError, EndOfFile, FileNotFound, PermissionDenied, GenericFailure, BadMessage, NoConnection, ConnectionLost, UnsupportedOperation };
|
||||
|
||||
/*!
|
||||
\brief Contains information about a remote file.
|
||||
*/
|
||||
class QSSH_EXPORT SftpFileInfo
|
||||
{
|
||||
public:
|
||||
SftpFileInfo() : type(FileTypeUnknown), sizeValid(false), permissionsValid(false) { }
|
||||
|
||||
/// The remote file name, only file attribute required by the RFC to be present so this is always set
|
||||
QString name;
|
||||
|
||||
/// The type of file
|
||||
SftpFileType type = FileTypeUnknown;
|
||||
|
||||
/// The remote file size in bytes.
|
||||
quint64 size = 0;
|
||||
|
||||
/// The permissions set on the file, might be empty as the RFC allows an SFTP server not to support any file attributes beyond the name.
|
||||
QFileDevice::Permissions permissions{};
|
||||
|
||||
/// Last time file was accessed.
|
||||
quint32 atime = 0;
|
||||
|
||||
/// Last time file was modified.
|
||||
quint32 mtime = 0;
|
||||
|
||||
/// If the timestamps (\ref atime and \ref mtime) are valid, the RFC allows an SFTP server not to support any file attributes beyond the name.
|
||||
bool timestampsValid = false;
|
||||
|
||||
/// The RFC allows an SFTP server not to support any file attributes beyond the name.
|
||||
bool sizeValid = false;
|
||||
|
||||
/// The RFC allows an SFTP server not to support any file attributes beyond the name.
|
||||
bool permissionsValid = false;
|
||||
};
|
||||
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // SFTPDEFS_H
|
||||
@@ -1,401 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
#include "sftpfilesystemmodel.h"
|
||||
|
||||
#include "sftpchannel.h"
|
||||
#include "sshconnection.h"
|
||||
#include "sshconnectionmanager.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QHash>
|
||||
#include <QIcon>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
namespace {
|
||||
|
||||
class SftpDirNode;
|
||||
class SftpFileNode
|
||||
{
|
||||
public:
|
||||
SftpFileNode() : parent(nullptr) { }
|
||||
virtual ~SftpFileNode() { }
|
||||
|
||||
QString path;
|
||||
SftpFileInfo fileInfo;
|
||||
SftpDirNode *parent;
|
||||
};
|
||||
|
||||
class SftpDirNode : public SftpFileNode
|
||||
{
|
||||
public:
|
||||
SftpDirNode() : lsState(LsNotYetCalled) { }
|
||||
~SftpDirNode() { qDeleteAll(children); }
|
||||
|
||||
enum { LsNotYetCalled, LsRunning, LsFinished } lsState;
|
||||
QList<SftpFileNode *> children;
|
||||
};
|
||||
|
||||
typedef QHash<SftpJobId, SftpDirNode *> DirNodeHash;
|
||||
|
||||
SftpFileNode *indexToFileNode(const QModelIndex &index)
|
||||
{
|
||||
return static_cast<SftpFileNode *>(index.internalPointer());
|
||||
}
|
||||
|
||||
SftpDirNode *indexToDirNode(const QModelIndex &index)
|
||||
{
|
||||
SftpFileNode * const fileNode = indexToFileNode(index);
|
||||
QSSH_ASSERT(fileNode);
|
||||
return dynamic_cast<SftpDirNode *>(fileNode);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class SftpFileSystemModelPrivate
|
||||
{
|
||||
public:
|
||||
SshConnection *sshConnection;
|
||||
SftpChannel::Ptr sftpChannel;
|
||||
QString rootDirectory;
|
||||
SftpFileNode *rootNode;
|
||||
SftpJobId statJobId;
|
||||
DirNodeHash lsOps;
|
||||
QList<SftpJobId> externalJobs;
|
||||
};
|
||||
} // namespace Internal
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
SftpFileSystemModel::SftpFileSystemModel(QObject *parent)
|
||||
: QAbstractItemModel(parent), d(new SftpFileSystemModelPrivate)
|
||||
{
|
||||
d->sshConnection = nullptr;
|
||||
d->rootDirectory = QLatin1Char('/');
|
||||
d->rootNode = nullptr;
|
||||
d->statJobId = SftpInvalidJob;
|
||||
}
|
||||
|
||||
SftpFileSystemModel::~SftpFileSystemModel()
|
||||
{
|
||||
shutDown();
|
||||
delete d;
|
||||
}
|
||||
|
||||
void SftpFileSystemModel::setSshConnection(const SshConnectionParameters &sshParams)
|
||||
{
|
||||
QSSH_ASSERT_AND_RETURN(!d->sshConnection);
|
||||
d->sshConnection = QSsh::acquireConnection(sshParams);
|
||||
connect(d->sshConnection, &SshConnection::error,
|
||||
this, &SftpFileSystemModel::handleSshConnectionFailure);
|
||||
if (d->sshConnection->state() == SshConnection::Connected) {
|
||||
handleSshConnectionEstablished();
|
||||
return;
|
||||
}
|
||||
connect(d->sshConnection, &SshConnection::connected,
|
||||
this, &SftpFileSystemModel::handleSshConnectionEstablished);
|
||||
if (d->sshConnection->state() == SshConnection::Unconnected)
|
||||
d->sshConnection->connectToHost();
|
||||
}
|
||||
|
||||
void SftpFileSystemModel::setRootDirectory(const QString &path)
|
||||
{
|
||||
beginResetModel();
|
||||
d->rootDirectory = path;
|
||||
delete d->rootNode;
|
||||
d->rootNode = nullptr;
|
||||
d->lsOps.clear();
|
||||
d->statJobId = SftpInvalidJob;
|
||||
endResetModel();
|
||||
statRootDirectory();
|
||||
}
|
||||
|
||||
QString SftpFileSystemModel::rootDirectory() const
|
||||
{
|
||||
return d->rootDirectory;
|
||||
}
|
||||
|
||||
SftpJobId SftpFileSystemModel::downloadFile(const QModelIndex &index, const QString &targetFilePath)
|
||||
{
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(d->rootNode, SftpInvalidJob);
|
||||
const SftpFileNode * const fileNode = indexToFileNode(index);
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(fileNode, SftpInvalidJob);
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(fileNode->fileInfo.type == FileTypeRegular, SftpInvalidJob);
|
||||
const SftpJobId jobId = d->sftpChannel->downloadFile(fileNode->path, targetFilePath,
|
||||
SftpOverwriteExisting);
|
||||
if (jobId != SftpInvalidJob)
|
||||
d->externalJobs << jobId;
|
||||
return jobId;
|
||||
}
|
||||
|
||||
int SftpFileSystemModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return 2; // type + name
|
||||
}
|
||||
|
||||
QVariant SftpFileSystemModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.internalPointer()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const SftpFileNode * const node = indexToFileNode(index);
|
||||
if (index.column() == 0 && role == Qt::DecorationRole) {
|
||||
switch (node->fileInfo.type) {
|
||||
case FileTypeRegular:
|
||||
case FileTypeOther:
|
||||
return QIcon(QStringLiteral(":/ssh/images/unknownfile.png"));
|
||||
case FileTypeDirectory:
|
||||
return QIcon(QStringLiteral(":/ssh/images/dir.png"));
|
||||
case FileTypeUnknown:
|
||||
return QIcon(QStringLiteral(":/ssh/images/help.png")); // Shows a question mark.
|
||||
}
|
||||
}
|
||||
if (index.column() == 1) {
|
||||
if (role == Qt::DisplayRole)
|
||||
return node->fileInfo.name;
|
||||
if (role == PathRole)
|
||||
return node->path;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::ItemFlags SftpFileSystemModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
}
|
||||
|
||||
QVariant SftpFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation != Qt::Horizontal)
|
||||
return QVariant();
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
if (section == 0)
|
||||
return tr("File Type");
|
||||
if (section == 1)
|
||||
return tr("File Name");
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QModelIndex SftpFileSystemModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (row < 0 || row >= rowCount(parent) || column < 0 || column >= columnCount(parent))
|
||||
return QModelIndex();
|
||||
if (!d->rootNode)
|
||||
return QModelIndex();
|
||||
if (!parent.isValid())
|
||||
return createIndex(row, column, d->rootNode);
|
||||
const SftpDirNode * const parentNode = indexToDirNode(parent);
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(parentNode, QModelIndex());
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(row < parentNode->children.count(), QModelIndex());
|
||||
SftpFileNode * const childNode = parentNode->children.at(row);
|
||||
return createIndex(row, column, childNode);
|
||||
}
|
||||
|
||||
QModelIndex SftpFileSystemModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
if (!child.isValid()) // Don't assert on this, since the model tester tries it.
|
||||
return QModelIndex();
|
||||
|
||||
const SftpFileNode * const childNode = indexToFileNode(child);
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(childNode, QModelIndex());
|
||||
if (childNode == d->rootNode)
|
||||
return QModelIndex();
|
||||
SftpDirNode * const parentNode = childNode->parent;
|
||||
if (parentNode == d->rootNode)
|
||||
return createIndex(0, 0, d->rootNode);
|
||||
const SftpDirNode * const grandParentNode = parentNode->parent;
|
||||
QSSH_ASSERT_AND_RETURN_VALUE(grandParentNode, QModelIndex());
|
||||
return createIndex(grandParentNode->children.indexOf(parentNode), 0, parentNode);
|
||||
}
|
||||
|
||||
int SftpFileSystemModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!d->rootNode)
|
||||
return 1; // fake it until we make it, otherwise QTreeView isn't happy
|
||||
if (!parent.isValid())
|
||||
return 1;
|
||||
if (parent.column() != 0)
|
||||
return 0;
|
||||
SftpDirNode * const dirNode = indexToDirNode(parent);
|
||||
if (!dirNode)
|
||||
return 0;
|
||||
if (dirNode->lsState != SftpDirNode::LsNotYetCalled)
|
||||
return dirNode->children.count();
|
||||
d->lsOps.insert(d->sftpChannel->listDirectory(dirNode->path), dirNode);
|
||||
dirNode->lsState = SftpDirNode::LsRunning;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SftpFileSystemModel::statRootDirectory()
|
||||
{
|
||||
if (!d->sftpChannel) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->statJobId = d->sftpChannel->statFile(d->rootDirectory);
|
||||
}
|
||||
|
||||
void SftpFileSystemModel::shutDown()
|
||||
{
|
||||
if (d->sftpChannel) {
|
||||
disconnect(d->sftpChannel.data(), nullptr, this, nullptr);
|
||||
d->sftpChannel->closeChannel();
|
||||
d->sftpChannel.clear();
|
||||
}
|
||||
if (d->sshConnection) {
|
||||
disconnect(d->sshConnection, nullptr, this, nullptr);
|
||||
QSsh::releaseConnection(d->sshConnection);
|
||||
d->sshConnection = nullptr;
|
||||
}
|
||||
delete d->rootNode;
|
||||
d->rootNode = nullptr;
|
||||
}
|
||||
|
||||
void SftpFileSystemModel::handleSshConnectionFailure()
|
||||
{
|
||||
emit connectionError(d->sshConnection->errorString());
|
||||
beginResetModel();
|
||||
shutDown();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void SftpFileSystemModel::handleSftpChannelInitialized()
|
||||
{
|
||||
connect(d->sftpChannel.data(),
|
||||
&SftpChannel::fileInfoAvailable,
|
||||
this, &SftpFileSystemModel::handleFileInfo);
|
||||
connect(d->sftpChannel.data(), &SftpChannel::finished,
|
||||
this, &SftpFileSystemModel::handleSftpJobFinished);
|
||||
statRootDirectory();
|
||||
}
|
||||
|
||||
void SftpFileSystemModel::handleSshConnectionEstablished()
|
||||
{
|
||||
d->sftpChannel = d->sshConnection->createSftpChannel();
|
||||
connect(d->sftpChannel.data(), &SftpChannel::initialized,
|
||||
this, &SftpFileSystemModel::handleSftpChannelInitialized);
|
||||
connect(d->sftpChannel.data(), &SftpChannel::channelError,
|
||||
this, &SftpFileSystemModel::handleSftpChannelError);
|
||||
d->sftpChannel->initialize();
|
||||
}
|
||||
|
||||
void SftpFileSystemModel::handleSftpChannelError(const QString &reason)
|
||||
{
|
||||
emit connectionError(reason);
|
||||
beginResetModel();
|
||||
shutDown();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void SftpFileSystemModel::handleFileInfo(SftpJobId jobId, const QList<SftpFileInfo> &fileInfoList)
|
||||
{
|
||||
if (jobId == d->statJobId) {
|
||||
QSSH_ASSERT_AND_RETURN(!d->rootNode);
|
||||
beginInsertRows(QModelIndex(), 0, 0);
|
||||
d->rootNode = new SftpDirNode;
|
||||
d->rootNode->path = d->rootDirectory;
|
||||
d->rootNode->fileInfo = fileInfoList.first();
|
||||
d->rootNode->fileInfo.name = d->rootDirectory == QLatin1String("/")
|
||||
? d->rootDirectory : QFileInfo(d->rootDirectory).fileName();
|
||||
endInsertRows();
|
||||
return;
|
||||
}
|
||||
SftpDirNode * const parentNode = d->lsOps.value(jobId);
|
||||
QSSH_ASSERT_AND_RETURN(parentNode);
|
||||
QList<SftpFileInfo> filteredList;
|
||||
foreach (const SftpFileInfo &fi, fileInfoList) {
|
||||
if (fi.name != QLatin1String(".") && fi.name != QLatin1String(".."))
|
||||
filteredList << fi;
|
||||
}
|
||||
if (filteredList.isEmpty())
|
||||
return;
|
||||
|
||||
if (parentNode->parent) {
|
||||
QModelIndex parentIndex = createIndex(parentNode->parent->children.indexOf(parentNode), 0, parentNode);
|
||||
beginInsertRows(parentIndex, rowCount(parentIndex), rowCount(parentIndex) + filteredList.count());
|
||||
} else {
|
||||
// root node
|
||||
beginInsertRows(QModelIndex(), 0, 1);
|
||||
}
|
||||
|
||||
foreach (const SftpFileInfo &fileInfo, filteredList) {
|
||||
SftpFileNode *childNode;
|
||||
if (fileInfo.type == FileTypeDirectory)
|
||||
childNode = new SftpDirNode;
|
||||
else
|
||||
childNode = new SftpFileNode;
|
||||
childNode->path = parentNode->path;
|
||||
if (!childNode->path.endsWith(QLatin1Char('/')))
|
||||
childNode->path += QLatin1Char('/');
|
||||
childNode->path += fileInfo.name;
|
||||
childNode->fileInfo = fileInfo;
|
||||
childNode->parent = parentNode;
|
||||
parentNode->children << childNode;
|
||||
}
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void SftpFileSystemModel::handleSftpJobFinished(SftpJobId jobId, const SftpError error, const QString &errorMessage)
|
||||
{
|
||||
Q_UNUSED(error);
|
||||
|
||||
if (jobId == d->statJobId) {
|
||||
d->statJobId = SftpInvalidJob;
|
||||
if (!errorMessage.isEmpty())
|
||||
emit sftpOperationFailed(tr("Error getting \"stat\" info about \"%1\": %2")
|
||||
.arg(rootDirectory(), errorMessage));
|
||||
return;
|
||||
}
|
||||
|
||||
DirNodeHash::Iterator it = d->lsOps.find(jobId);
|
||||
if (it != d->lsOps.end()) {
|
||||
QSSH_ASSERT(it.value()->lsState == SftpDirNode::LsRunning);
|
||||
it.value()->lsState = SftpDirNode::LsFinished;
|
||||
if (!errorMessage.isEmpty())
|
||||
emit sftpOperationFailed(tr("Error listing contents of directory \"%1\": %2")
|
||||
.arg(it.value()->path, errorMessage));
|
||||
d->lsOps.erase(it);
|
||||
return;
|
||||
}
|
||||
|
||||
const int jobIndex = d->externalJobs.indexOf(jobId);
|
||||
QSSH_ASSERT_AND_RETURN(jobIndex != -1);
|
||||
d->externalJobs.removeAt(jobIndex);
|
||||
emit sftpOperationFinished(jobId, errorMessage);
|
||||
}
|
||||
|
||||
} // namespace QSsh
|
||||
@@ -1,107 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
#ifndef SFTPFILESYSTEMMODEL_H
|
||||
#define SFTPFILESYSTEMMODEL_H
|
||||
|
||||
#include "sftpdefs.h"
|
||||
|
||||
#include "ssh_global.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
namespace QSsh {
|
||||
class SshConnectionParameters;
|
||||
|
||||
namespace Internal { class SftpFileSystemModelPrivate; }
|
||||
|
||||
// Very simple read-only model. Symbolic links are not followed.
|
||||
class QSSH_EXPORT SftpFileSystemModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SftpFileSystemModel(QObject *parent = nullptr);
|
||||
~SftpFileSystemModel();
|
||||
|
||||
/*
|
||||
* Once this is called, an SFTP connection is established and the model is populated.
|
||||
* The effect of additional calls is undefined.
|
||||
*/
|
||||
void setSshConnection(const SshConnectionParameters &sshParams);
|
||||
|
||||
void setRootDirectory(const QString &path); // Default is "/".
|
||||
QString rootDirectory() const;
|
||||
|
||||
SftpJobId downloadFile(const QModelIndex &index, const QString &targetFilePath);
|
||||
|
||||
// Use this to get the full path of a file or directory.
|
||||
static const int PathRole = Qt::UserRole;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
|
||||
signals:
|
||||
/*
|
||||
* E.g. "Permission denied". Note that this can happen without direct user intervention,
|
||||
* due to e.g. the view calling rowCount() on a non-readable directory. This signal should
|
||||
* therefore not result in a message box or similar, since it might occur very often.
|
||||
*/
|
||||
void sftpOperationFailed(const QString &errorMessage);
|
||||
|
||||
/*
|
||||
* This error is not recoverable. The model will not have any content after
|
||||
* the signal has been emitted.
|
||||
*/
|
||||
void connectionError(const QString &errorMessage);
|
||||
|
||||
// Success <=> error.isEmpty().
|
||||
void sftpOperationFinished(QSsh::SftpJobId, const QString &error);
|
||||
|
||||
private:
|
||||
void handleSshConnectionEstablished();
|
||||
void handleSshConnectionFailure();
|
||||
void handleSftpChannelInitialized();
|
||||
void handleSftpChannelError(const QString &reason);
|
||||
void handleFileInfo(QSsh::SftpJobId jobId, const QList<QSsh::SftpFileInfo> &fileInfoList);
|
||||
void handleSftpJobFinished(QSsh::SftpJobId jobId, const SftpError error, const QString &errorMessage);
|
||||
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
|
||||
QModelIndex parent(const QModelIndex &child) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
void statRootDirectory();
|
||||
void shutDown();
|
||||
|
||||
Internal::SftpFileSystemModelPrivate * const d;
|
||||
};
|
||||
|
||||
} // namespace QSsh;
|
||||
|
||||
#endif // SFTPFILESYSTEMMODEL_H
|
||||
@@ -1,223 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "sftpincomingpacket_p.h"
|
||||
|
||||
#include "sshexception_p.h"
|
||||
#include "sshlogging_p.h"
|
||||
#include "sshpacketparser_p.h"
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
SftpIncomingPacket::SftpIncomingPacket() : m_length(0)
|
||||
{
|
||||
}
|
||||
|
||||
void SftpIncomingPacket::consumeData(QByteArray &newData)
|
||||
{
|
||||
qCDebug(sshLog, "%s: current data size = %d, new data size = %d", Q_FUNC_INFO,
|
||||
m_data.size(), newData.size());
|
||||
|
||||
if (isComplete() || dataSize() + newData.size() < sizeof m_length)
|
||||
return;
|
||||
|
||||
if (dataSize() < sizeof m_length) {
|
||||
moveFirstBytes(m_data, newData, sizeof m_length - m_data.size());
|
||||
m_length = SshPacketParser::asUint32(m_data, static_cast<quint32>(0));
|
||||
if (m_length < static_cast<quint32>(TypeOffset + 1)
|
||||
|| m_length > MaxPacketSize) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Invalid length field in SFTP packet.");
|
||||
}
|
||||
}
|
||||
|
||||
moveFirstBytes(m_data, newData,
|
||||
qMin<quint32>(m_length - dataSize() + 4, newData.size()));
|
||||
}
|
||||
|
||||
void SftpIncomingPacket::moveFirstBytes(QByteArray &target, QByteArray &source,
|
||||
int n)
|
||||
{
|
||||
target.append(source.left(n));
|
||||
source.remove(0, n);
|
||||
}
|
||||
|
||||
bool SftpIncomingPacket::isComplete() const
|
||||
{
|
||||
return m_length == dataSize() - 4;
|
||||
}
|
||||
|
||||
void SftpIncomingPacket::clear()
|
||||
{
|
||||
m_data.clear();
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
quint32 SftpIncomingPacket::extractServerVersion() const
|
||||
{
|
||||
Q_ASSERT(isComplete());
|
||||
Q_ASSERT(type() == SSH_FXP_VERSION);
|
||||
try {
|
||||
return SshPacketParser::asUint32(m_data, TypeOffset + 1);
|
||||
} catch (const SshPacketParseException &) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Invalid SSH_FXP_VERSION packet.");
|
||||
}
|
||||
}
|
||||
|
||||
SftpHandleResponse SftpIncomingPacket::asHandleResponse() const
|
||||
{
|
||||
Q_ASSERT(isComplete());
|
||||
Q_ASSERT(type() == SSH_FXP_HANDLE);
|
||||
try {
|
||||
SftpHandleResponse response;
|
||||
quint32 offset = RequestIdOffset;
|
||||
response.requestId = SshPacketParser::asUint32(m_data, &offset);
|
||||
response.handle = SshPacketParser::asString(m_data, &offset);
|
||||
return response;
|
||||
} catch (const SshPacketParseException &) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Invalid SSH_FXP_HANDLE packet");
|
||||
}
|
||||
}
|
||||
|
||||
SftpStatusResponse SftpIncomingPacket::asStatusResponse() const
|
||||
{
|
||||
Q_ASSERT(isComplete());
|
||||
Q_ASSERT(type() == SSH_FXP_STATUS);
|
||||
try {
|
||||
SftpStatusResponse response;
|
||||
quint32 offset = RequestIdOffset;
|
||||
response.requestId = SshPacketParser::asUint32(m_data, &offset);
|
||||
response.status = static_cast<SftpStatusCode>(SshPacketParser::asUint32(m_data, &offset));
|
||||
response.errorString = SshPacketParser::asUserString(m_data, &offset);
|
||||
response.language = SshPacketParser::asString(m_data, &offset);
|
||||
return response;
|
||||
} catch (const SshPacketParseException &) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Invalid SSH_FXP_STATUS packet.");
|
||||
}
|
||||
}
|
||||
|
||||
SftpNameResponse SftpIncomingPacket::asNameResponse() const
|
||||
{
|
||||
Q_ASSERT(isComplete());
|
||||
Q_ASSERT(type() == SSH_FXP_NAME);
|
||||
try {
|
||||
SftpNameResponse response;
|
||||
quint32 offset = RequestIdOffset;
|
||||
response.requestId = SshPacketParser::asUint32(m_data, &offset);
|
||||
const quint32 count = SshPacketParser::asUint32(m_data, &offset);
|
||||
for (quint32 i = 0; i < count; ++i)
|
||||
response.files << asFile(offset);
|
||||
return response;
|
||||
} catch (const SshPacketParseException &) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Invalid SSH_FXP_NAME packet.");
|
||||
}
|
||||
}
|
||||
|
||||
SftpDataResponse SftpIncomingPacket::asDataResponse() const
|
||||
{
|
||||
Q_ASSERT(isComplete());
|
||||
Q_ASSERT(type() == SSH_FXP_DATA);
|
||||
try {
|
||||
SftpDataResponse response;
|
||||
quint32 offset = RequestIdOffset;
|
||||
response.requestId = SshPacketParser::asUint32(m_data, &offset);
|
||||
response.data = SshPacketParser::asString(m_data, &offset);
|
||||
return response;
|
||||
} catch (const SshPacketParseException &) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Invalid SSH_FXP_DATA packet.");
|
||||
}
|
||||
}
|
||||
|
||||
SftpAttrsResponse SftpIncomingPacket::asAttrsResponse() const
|
||||
{
|
||||
Q_ASSERT(isComplete());
|
||||
Q_ASSERT(type() == SSH_FXP_ATTRS);
|
||||
try {
|
||||
SftpAttrsResponse response;
|
||||
quint32 offset = RequestIdOffset;
|
||||
response.requestId = SshPacketParser::asUint32(m_data, &offset);
|
||||
response.attrs = asFileAttributes(offset);
|
||||
return response;
|
||||
} catch (const SshPacketParseException &) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Invalid SSH_FXP_ATTRS packet.");
|
||||
}
|
||||
}
|
||||
|
||||
SftpFile SftpIncomingPacket::asFile(quint32 &offset) const
|
||||
{
|
||||
SftpFile file;
|
||||
file.fileName
|
||||
= QString::fromUtf8(SshPacketParser::asString(m_data, &offset));
|
||||
file.longName
|
||||
= QString::fromUtf8(SshPacketParser::asString(m_data, &offset));
|
||||
file.attributes = asFileAttributes(offset);
|
||||
return file;
|
||||
}
|
||||
|
||||
SftpFileAttributes SftpIncomingPacket::asFileAttributes(quint32 &offset) const
|
||||
{
|
||||
SftpFileAttributes attributes;
|
||||
const quint32 flags = SshPacketParser::asUint32(m_data, &offset);
|
||||
attributes.sizePresent = flags & SSH_FILEXFER_ATTR_SIZE;
|
||||
attributes.timesPresent = flags & SSH_FILEXFER_ATTR_ACMODTIME;
|
||||
attributes.uidAndGidPresent = flags & SSH_FILEXFER_ATTR_UIDGID;
|
||||
attributes.permissionsPresent = flags & SSH_FILEXFER_ATTR_PERMISSIONS;
|
||||
if (attributes.sizePresent) {
|
||||
attributes.size = SshPacketParser::asUint64(m_data, &offset);
|
||||
}
|
||||
if (attributes.uidAndGidPresent) {
|
||||
attributes.uid = SshPacketParser::asUint32(m_data, &offset);
|
||||
attributes.gid = SshPacketParser::asUint32(m_data, &offset);
|
||||
}
|
||||
if (attributes.permissionsPresent)
|
||||
attributes.permissions = SshPacketParser::asUint32(m_data, &offset);
|
||||
if (attributes.timesPresent) {
|
||||
attributes.atime = SshPacketParser::asUint32(m_data, &offset);
|
||||
attributes.mtime = SshPacketParser::asUint32(m_data, &offset);
|
||||
}
|
||||
if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
|
||||
const quint32 count = SshPacketParser::asUint32(m_data, &offset);
|
||||
for (quint32 i = 0; i < count; ++i) {
|
||||
SshPacketParser::asString(m_data, &offset);
|
||||
SshPacketParser::asString(m_data, &offset);
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
@@ -1,112 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SFTPINCOMINGPACKET_P_H
|
||||
#define SFTPINCOMINGPACKET_P_H
|
||||
|
||||
#include "sftppacket_p.h"
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
struct SftpHandleResponse {
|
||||
quint32 requestId;
|
||||
QByteArray handle;
|
||||
};
|
||||
|
||||
struct SftpStatusResponse {
|
||||
quint32 requestId;
|
||||
SftpStatusCode status;
|
||||
QString errorString;
|
||||
QByteArray language;
|
||||
};
|
||||
|
||||
struct SftpFileAttributes {
|
||||
bool sizePresent;
|
||||
bool timesPresent;
|
||||
bool uidAndGidPresent;
|
||||
bool permissionsPresent;
|
||||
quint64 size;
|
||||
quint32 uid;
|
||||
quint32 gid;
|
||||
quint32 permissions;
|
||||
quint32 atime;
|
||||
quint32 mtime;
|
||||
};
|
||||
|
||||
struct SftpFile {
|
||||
QString fileName;
|
||||
QString longName; // Not present in later RFCs, so we don't expose this to the user.
|
||||
SftpFileAttributes attributes;
|
||||
};
|
||||
|
||||
struct SftpNameResponse {
|
||||
quint32 requestId;
|
||||
QList<SftpFile> files;
|
||||
};
|
||||
|
||||
struct SftpDataResponse {
|
||||
quint32 requestId;
|
||||
QByteArray data;
|
||||
};
|
||||
|
||||
struct SftpAttrsResponse {
|
||||
quint32 requestId;
|
||||
SftpFileAttributes attrs;
|
||||
};
|
||||
|
||||
class SftpIncomingPacket : public AbstractSftpPacket
|
||||
{
|
||||
public:
|
||||
SftpIncomingPacket();
|
||||
|
||||
void consumeData(QByteArray &data);
|
||||
void clear();
|
||||
bool isComplete() const;
|
||||
quint32 extractServerVersion() const;
|
||||
SftpHandleResponse asHandleResponse() const;
|
||||
SftpStatusResponse asStatusResponse() const;
|
||||
SftpNameResponse asNameResponse() const;
|
||||
SftpDataResponse asDataResponse() const;
|
||||
SftpAttrsResponse asAttrsResponse() const;
|
||||
|
||||
private:
|
||||
void moveFirstBytes(QByteArray &target, QByteArray &source, int n);
|
||||
|
||||
SftpFileAttributes asFileAttributes(quint32 &offset) const;
|
||||
SftpFile asFile(quint32 &offset) const;
|
||||
|
||||
quint32 m_length;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // SFTPINCOMINGPACKET_P_H
|
||||
@@ -1,236 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "sftpoperation_p.h"
|
||||
|
||||
#include "sftpoutgoingpacket_p.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
AbstractSftpOperation::AbstractSftpOperation(SftpJobId jobId) : jobId(jobId)
|
||||
{
|
||||
}
|
||||
|
||||
AbstractSftpOperation::~AbstractSftpOperation() { }
|
||||
|
||||
|
||||
SftpStatFile::SftpStatFile(SftpJobId jobId, const QString &path)
|
||||
: AbstractSftpOperation(jobId), path(path)
|
||||
{
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpStatFile::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
return packet.generateStat(path, jobId);
|
||||
}
|
||||
|
||||
SftpMakeDir::SftpMakeDir(SftpJobId jobId, const QString &path,
|
||||
const SftpUploadDir::Ptr &parentJob)
|
||||
: AbstractSftpOperation(jobId), parentJob(parentJob), remoteDir(path)
|
||||
{
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpMakeDir::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
return packet.generateMkDir(remoteDir, jobId);
|
||||
}
|
||||
|
||||
|
||||
SftpRmDir::SftpRmDir(SftpJobId id, const QString &path)
|
||||
: AbstractSftpOperation(id), remoteDir(path)
|
||||
{
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpRmDir::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
return packet.generateRmDir(remoteDir, jobId);
|
||||
}
|
||||
|
||||
|
||||
SftpRm::SftpRm(SftpJobId jobId, const QString &path)
|
||||
: AbstractSftpOperation(jobId), remoteFile(path) {}
|
||||
|
||||
SftpOutgoingPacket &SftpRm::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
return packet.generateRm(remoteFile, jobId);
|
||||
}
|
||||
|
||||
|
||||
SftpRename::SftpRename(SftpJobId jobId, const QString &oldPath,
|
||||
const QString &newPath)
|
||||
: AbstractSftpOperation(jobId), oldPath(oldPath), newPath(newPath)
|
||||
{
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpRename::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
return packet.generateRename(oldPath, newPath, jobId);
|
||||
}
|
||||
|
||||
|
||||
SftpCreateLink::SftpCreateLink(SftpJobId jobId, const QString &filePath, const QString &target)
|
||||
: AbstractSftpOperation(jobId), filePath(filePath), target(target)
|
||||
{
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpCreateLink::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
return packet.generateCreateLink(filePath, target, jobId);
|
||||
}
|
||||
|
||||
|
||||
AbstractSftpOperationWithHandle::AbstractSftpOperationWithHandle(SftpJobId jobId,
|
||||
const QString &remotePath)
|
||||
: AbstractSftpOperation(jobId),
|
||||
remotePath(remotePath), state(Inactive), hasError(false)
|
||||
{
|
||||
}
|
||||
|
||||
AbstractSftpOperationWithHandle::~AbstractSftpOperationWithHandle() { }
|
||||
|
||||
|
||||
SftpListDir::SftpListDir(SftpJobId jobId, const QString &path,
|
||||
const QSharedPointer<SftpDownloadDir> &parentJob)
|
||||
: AbstractSftpOperationWithHandle(jobId, path), parentJob(parentJob)
|
||||
{
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpListDir::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
state = OpenRequested;
|
||||
return packet.generateOpenDir(remotePath, jobId);
|
||||
}
|
||||
|
||||
|
||||
SftpCreateFile::SftpCreateFile(SftpJobId jobId, const QString &path,
|
||||
SftpOverwriteMode mode)
|
||||
: AbstractSftpOperationWithHandle(jobId, path), mode(mode)
|
||||
{
|
||||
}
|
||||
|
||||
SftpOutgoingPacket & SftpCreateFile::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
state = OpenRequested;
|
||||
return packet.generateOpenFileForWriting(remotePath, mode,
|
||||
SftpOutgoingPacket::DefaultPermissions, jobId);
|
||||
}
|
||||
|
||||
|
||||
const int AbstractSftpTransfer::MaxInFlightCount = 10; // Experimentally found to be enough.
|
||||
|
||||
AbstractSftpTransfer::AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath,
|
||||
const QSharedPointer<QIODevice> &localFile)
|
||||
: AbstractSftpOperationWithHandle(jobId, remotePath),
|
||||
localFile(localFile), fileSize(0), offset(0), inFlightCount(0),
|
||||
statRequested(false)
|
||||
{
|
||||
}
|
||||
|
||||
AbstractSftpTransfer::~AbstractSftpTransfer() {}
|
||||
|
||||
void AbstractSftpTransfer::calculateInFlightCount(quint32 chunkSize)
|
||||
{
|
||||
if (fileSize == 0) {
|
||||
inFlightCount = 1;
|
||||
} else {
|
||||
inFlightCount = fileSize / chunkSize;
|
||||
if (fileSize % chunkSize)
|
||||
++inFlightCount;
|
||||
if (inFlightCount > MaxInFlightCount)
|
||||
inFlightCount = MaxInFlightCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SftpDownload::SftpDownload(SftpJobId jobId, const QString &remotePath,
|
||||
const QSharedPointer<QIODevice> &localFile, SftpOverwriteMode mode,
|
||||
const QSharedPointer<QSsh::Internal::SftpDownloadDir> &parentJob)
|
||||
: AbstractSftpTransfer(jobId, remotePath, localFile), eofId(SftpInvalidJob), mode(mode),
|
||||
parentJob(parentJob)
|
||||
{
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpDownload::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
state = OpenRequested;
|
||||
return packet.generateOpenFileForReading(remotePath, jobId);
|
||||
}
|
||||
|
||||
|
||||
SftpUploadFile::SftpUploadFile(SftpJobId jobId, const QString &remotePath,
|
||||
const QSharedPointer<QIODevice> &localFile, SftpOverwriteMode mode,
|
||||
const SftpUploadDir::Ptr &parentJob)
|
||||
: AbstractSftpTransfer(jobId, remotePath, localFile),
|
||||
parentJob(parentJob), mode(mode)
|
||||
{
|
||||
fileSize = localFile->size();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpUploadFile::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
state = OpenRequested;
|
||||
quint32 permissions = 0;
|
||||
QFileDevice *fileDevice = qobject_cast<QFileDevice*>(localFile.data());
|
||||
if (fileDevice) {
|
||||
const QFile::Permissions &qtPermissions = fileDevice->permissions();
|
||||
if (qtPermissions & QFile::ExeOther)
|
||||
permissions |= 1 << 0;
|
||||
if (qtPermissions & QFile::WriteOther)
|
||||
permissions |= 1 << 1;
|
||||
if (qtPermissions & QFile::ReadOther)
|
||||
permissions |= 1 << 2;
|
||||
if (qtPermissions & QFile::ExeGroup)
|
||||
permissions |= 1<< 3;
|
||||
if (qtPermissions & QFile::WriteGroup)
|
||||
permissions |= 1<< 4;
|
||||
if (qtPermissions & QFile::ReadGroup)
|
||||
permissions |= 1<< 5;
|
||||
if (qtPermissions & QFile::ExeOwner)
|
||||
permissions |= 1<< 6;
|
||||
if (qtPermissions & QFile::WriteOwner)
|
||||
permissions |= 1<< 7;
|
||||
if (qtPermissions & QFile::ReadOwner)
|
||||
permissions |= 1<< 8;
|
||||
} else {
|
||||
// write owner
|
||||
permissions |= 1<< 7;
|
||||
// read owner
|
||||
permissions |= 1<< 8;
|
||||
}
|
||||
return packet.generateOpenFileForWriting(remotePath, mode, permissions, jobId);
|
||||
}
|
||||
|
||||
SftpUploadDir::~SftpUploadDir() {}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
@@ -1,290 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SFTPOPERATION_P_H
|
||||
#define SFTPOPERATION_P_H
|
||||
|
||||
#include "sftpdefs.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QSharedPointer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QIODevice;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
class SftpOutgoingPacket;
|
||||
|
||||
struct AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<AbstractSftpOperation> Ptr;
|
||||
enum Type {
|
||||
StatFile, ListDir, MakeDir, RmDir, Rm, Rename, CreateLink, CreateFile, Download, UploadFile
|
||||
};
|
||||
|
||||
AbstractSftpOperation(SftpJobId jobId);
|
||||
virtual ~AbstractSftpOperation();
|
||||
virtual Type type() const = 0;
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet) = 0;
|
||||
|
||||
const SftpJobId jobId;
|
||||
|
||||
private:
|
||||
AbstractSftpOperation(const AbstractSftpOperation &);
|
||||
AbstractSftpOperation &operator=(const AbstractSftpOperation &);
|
||||
};
|
||||
|
||||
struct SftpUploadDir;
|
||||
struct SftpDownloadDir;
|
||||
|
||||
struct SftpStatFile : public AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<SftpStatFile> Ptr;
|
||||
|
||||
SftpStatFile(SftpJobId jobId, const QString &path);
|
||||
virtual Type type() const { return StatFile; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
const QString path;
|
||||
};
|
||||
|
||||
struct SftpMakeDir : public AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<SftpMakeDir> Ptr;
|
||||
|
||||
SftpMakeDir(SftpJobId jobId, const QString &path,
|
||||
const QSharedPointer<SftpUploadDir> &parentJob = QSharedPointer<SftpUploadDir>());
|
||||
virtual Type type() const { return MakeDir; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
const QSharedPointer<SftpUploadDir> parentJob;
|
||||
const QString remoteDir;
|
||||
};
|
||||
|
||||
struct SftpRmDir : public AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<SftpRmDir> Ptr;
|
||||
|
||||
SftpRmDir(SftpJobId id, const QString &path);
|
||||
virtual Type type() const { return RmDir; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
const QString remoteDir;
|
||||
};
|
||||
|
||||
struct SftpRm : public AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<SftpRm> Ptr;
|
||||
|
||||
SftpRm(SftpJobId jobId, const QString &path);
|
||||
virtual Type type() const { return Rm; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
const QString remoteFile;
|
||||
};
|
||||
|
||||
struct SftpRename : public AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<SftpRename> Ptr;
|
||||
|
||||
SftpRename(SftpJobId jobId, const QString &oldPath, const QString &newPath);
|
||||
virtual Type type() const { return Rename; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
const QString oldPath;
|
||||
const QString newPath;
|
||||
};
|
||||
|
||||
struct SftpCreateLink : public AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<SftpCreateLink> Ptr;
|
||||
|
||||
SftpCreateLink(SftpJobId jobId, const QString &filePath, const QString &target);
|
||||
virtual Type type() const { return CreateLink; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
const QString filePath;
|
||||
const QString target;
|
||||
};
|
||||
|
||||
|
||||
struct AbstractSftpOperationWithHandle : public AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<AbstractSftpOperationWithHandle> Ptr;
|
||||
enum State { Inactive, OpenRequested, Open, CloseRequested };
|
||||
|
||||
AbstractSftpOperationWithHandle(SftpJobId jobId, const QString &remotePath);
|
||||
~AbstractSftpOperationWithHandle();
|
||||
|
||||
const QString remotePath;
|
||||
QByteArray remoteHandle;
|
||||
State state;
|
||||
bool hasError;
|
||||
};
|
||||
|
||||
|
||||
struct SftpListDir : public AbstractSftpOperationWithHandle
|
||||
{
|
||||
typedef QSharedPointer<SftpListDir> Ptr;
|
||||
|
||||
SftpListDir(SftpJobId jobId, const QString &path,
|
||||
const QSharedPointer<SftpDownloadDir> &parentJob = QSharedPointer<SftpDownloadDir>());
|
||||
virtual Type type() const { return ListDir; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
const QSharedPointer<SftpDownloadDir> parentJob;
|
||||
};
|
||||
|
||||
|
||||
struct SftpCreateFile : public AbstractSftpOperationWithHandle
|
||||
{
|
||||
typedef QSharedPointer<SftpCreateFile> Ptr;
|
||||
|
||||
SftpCreateFile(SftpJobId jobId, const QString &path, SftpOverwriteMode mode);
|
||||
virtual Type type() const { return CreateFile; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
const SftpOverwriteMode mode;
|
||||
};
|
||||
|
||||
struct AbstractSftpTransfer : public AbstractSftpOperationWithHandle
|
||||
{
|
||||
typedef QSharedPointer<AbstractSftpTransfer> Ptr;
|
||||
|
||||
AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath,
|
||||
const QSharedPointer<QIODevice> &localFile);
|
||||
~AbstractSftpTransfer();
|
||||
void calculateInFlightCount(quint32 chunkSize);
|
||||
|
||||
static const int MaxInFlightCount;
|
||||
|
||||
const QSharedPointer<QIODevice> localFile;
|
||||
quint64 fileSize;
|
||||
quint64 offset;
|
||||
int inFlightCount;
|
||||
bool statRequested;
|
||||
};
|
||||
|
||||
struct SftpDownload : public AbstractSftpTransfer
|
||||
{
|
||||
typedef QSharedPointer<SftpDownload> Ptr;
|
||||
SftpDownload(SftpJobId jobId, const QString &remotePath,
|
||||
const QSharedPointer<QIODevice> &localFile, SftpOverwriteMode mode,
|
||||
const QSharedPointer<SftpDownloadDir> &parentJob = QSharedPointer<SftpDownloadDir>());
|
||||
virtual Type type() const { return Download; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
QMap<quint32, quint64> offsets;
|
||||
SftpJobId eofId;
|
||||
SftpOverwriteMode mode;
|
||||
const QSharedPointer<QSsh::Internal::SftpDownloadDir> parentJob;
|
||||
};
|
||||
|
||||
struct SftpUploadFile : public AbstractSftpTransfer
|
||||
{
|
||||
typedef QSharedPointer<SftpUploadFile> Ptr;
|
||||
|
||||
SftpUploadFile(SftpJobId jobId, const QString &remotePath,
|
||||
const QSharedPointer<QIODevice> &localFile, SftpOverwriteMode mode,
|
||||
const QSharedPointer<SftpUploadDir> &parentJob = QSharedPointer<SftpUploadDir>());
|
||||
virtual Type type() const { return UploadFile; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
const QSharedPointer<SftpUploadDir> parentJob;
|
||||
SftpOverwriteMode mode;
|
||||
};
|
||||
|
||||
// Composite operation.
|
||||
struct SftpUploadDir
|
||||
{
|
||||
typedef QSharedPointer<SftpUploadDir> Ptr;
|
||||
|
||||
struct Dir {
|
||||
Dir(const QString &l, const QString &r) : localDir(l), remoteDir(r) {}
|
||||
QString localDir;
|
||||
QString remoteDir;
|
||||
};
|
||||
|
||||
SftpUploadDir(SftpJobId jobId) : jobId(jobId), hasError(false) {}
|
||||
~SftpUploadDir();
|
||||
|
||||
void setError()
|
||||
{
|
||||
hasError = true;
|
||||
uploadsInProgress.clear();
|
||||
mkdirsInProgress.clear();
|
||||
}
|
||||
|
||||
const SftpJobId jobId;
|
||||
bool hasError;
|
||||
QList<SftpUploadFile::Ptr> uploadsInProgress;
|
||||
QMap<SftpMakeDir::Ptr, Dir> mkdirsInProgress;
|
||||
};
|
||||
|
||||
// Composite operation.
|
||||
struct SftpDownloadDir
|
||||
{
|
||||
typedef QSharedPointer<SftpDownloadDir> Ptr;
|
||||
|
||||
struct Dir {
|
||||
Dir() {}
|
||||
Dir(const QString &l, const QString &r) : localDir(l), remoteDir(r) {}
|
||||
QString localDir;
|
||||
QString remoteDir;
|
||||
};
|
||||
|
||||
SftpDownloadDir(SftpJobId jobId, SftpOverwriteMode mode)
|
||||
: jobId(jobId), hasError(false), mode(mode) {}
|
||||
|
||||
~SftpDownloadDir() {}
|
||||
|
||||
void setError()
|
||||
{
|
||||
hasError = true;
|
||||
downloadsInProgress.clear();
|
||||
lsdirsInProgress.clear();
|
||||
}
|
||||
|
||||
const SftpJobId jobId;
|
||||
bool hasError;
|
||||
SftpOverwriteMode mode;
|
||||
QList<SftpDownload::Ptr> downloadsInProgress;
|
||||
QMap<SftpListDir::Ptr, Dir> lsdirsInProgress;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // SFTPOPERATION_P_H
|
||||
@@ -1,225 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "sftpoutgoingpacket_p.h"
|
||||
|
||||
#include "sshlogging_p.h"
|
||||
#include "sshpacket_p.h"
|
||||
|
||||
#include <QtEndian>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
namespace {
|
||||
const quint32 DefaultAttributes = 0;
|
||||
const quint32 SSH_FXF_READ = 0x00000001;
|
||||
const quint32 SSH_FXF_WRITE = 0x00000002;
|
||||
const quint32 SSH_FXF_APPEND = 0x00000004;
|
||||
const quint32 SSH_FXF_CREAT = 0x00000008;
|
||||
const quint32 SSH_FXF_TRUNC = 0x00000010;
|
||||
const quint32 SSH_FXF_EXCL = 0x00000020;
|
||||
}
|
||||
|
||||
SftpOutgoingPacket::SftpOutgoingPacket()
|
||||
{
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateInit(quint32 version)
|
||||
{
|
||||
return init(SSH_FXP_INIT, 0).appendInt(version).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateStat(const QString &path, quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_LSTAT, requestId).appendString(path).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateOpenDir(const QString &path,
|
||||
quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_OPENDIR, requestId).appendString(path).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateReadDir(const QByteArray &handle,
|
||||
quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_READDIR, requestId).appendString(handle).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateCloseHandle(const QByteArray &handle,
|
||||
quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_CLOSE, requestId).appendString(handle).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateMkDir(const QString &path,
|
||||
quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_MKDIR, requestId).appendString(path)
|
||||
.appendInt(DefaultAttributes).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateRmDir(const QString &path,
|
||||
quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_RMDIR, requestId).appendString(path).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateRm(const QString &path,
|
||||
quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_REMOVE, requestId).appendString(path).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateRename(const QString &oldPath,
|
||||
const QString &newPath, quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_RENAME, requestId).appendString(oldPath)
|
||||
.appendString(newPath).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFileForWriting(const QString &path,
|
||||
SftpOverwriteMode mode, quint32 permissions, quint32 requestId)
|
||||
{
|
||||
QList<quint32> attributes;
|
||||
if (permissions != DefaultPermissions)
|
||||
attributes << SSH_FILEXFER_ATTR_PERMISSIONS << permissions;
|
||||
else
|
||||
attributes << DefaultAttributes;
|
||||
return generateOpenFile(path, Write, mode, attributes, requestId);
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFileForReading(const QString &path,
|
||||
quint32 requestId)
|
||||
{
|
||||
// Note: Overwrite mode is irrelevant and will be ignored.
|
||||
return generateOpenFile(path, Read, SftpSkipExisting, QList<quint32>() << DefaultAttributes,
|
||||
requestId);
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateReadFile(const QByteArray &handle,
|
||||
quint64 offset, quint32 length, quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_READ, requestId).appendString(handle).appendInt64(offset)
|
||||
.appendInt(length).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateFstat(const QByteArray &handle,
|
||||
quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_FSTAT, requestId).appendString(handle).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateWriteFile(const QByteArray &handle,
|
||||
quint64 offset, const QByteArray &data, quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_WRITE, requestId).appendString(handle)
|
||||
.appendInt64(offset).appendString(data).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateCreateLink(const QString &filePath,
|
||||
const QString &target, quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_SYMLINK, requestId).appendString(filePath).appendString(target).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFile(const QString &path,
|
||||
OpenType openType, SftpOverwriteMode mode, const QList<quint32> &attributes, quint32 requestId)
|
||||
{
|
||||
quint32 pFlags = 0;
|
||||
switch (openType) {
|
||||
case Read:
|
||||
pFlags = SSH_FXF_READ;
|
||||
break;
|
||||
case Write:
|
||||
pFlags = SSH_FXF_WRITE | SSH_FXF_CREAT;
|
||||
switch (mode) {
|
||||
case SftpOverwriteExisting: pFlags |= SSH_FXF_TRUNC; break;
|
||||
case SftpAppendToExisting: pFlags |= SSH_FXF_APPEND; break;
|
||||
case SftpSkipExisting: pFlags |= SSH_FXF_EXCL; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
init(SSH_FXP_OPEN, requestId).appendString(path).appendInt(pFlags);
|
||||
foreach (const quint32 attribute, attributes)
|
||||
appendInt(attribute);
|
||||
return finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::init(SftpPacketType type,
|
||||
quint32 requestId)
|
||||
{
|
||||
m_data.resize(TypeOffset + 1);
|
||||
m_data[TypeOffset] = type;
|
||||
if (type != SSH_FXP_INIT) {
|
||||
appendInt(requestId);
|
||||
qCDebug(sshLog, "Generating SFTP packet of type %d with request id %u", type, requestId);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::appendInt(quint32 val)
|
||||
{
|
||||
m_data.append(AbstractSshPacket::encodeInt(val));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::appendInt64(quint64 value)
|
||||
{
|
||||
m_data.append(AbstractSshPacket::encodeInt(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::appendString(const QString &string)
|
||||
{
|
||||
m_data.append(AbstractSshPacket::encodeString(string.toUtf8()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::appendString(const QByteArray &string)
|
||||
{
|
||||
m_data += AbstractSshPacket::encodeString(string);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::finalize()
|
||||
{
|
||||
AbstractSshPacket::setLengthField(m_data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const quint32 SftpOutgoingPacket::DefaultPermissions = std::numeric_limits<quint32>::max();
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
@@ -1,92 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SFTPOUTGOINGPACKET_P_H
|
||||
#define SFTPOUTGOINGPACKET_P_H
|
||||
|
||||
#include "sftppacket_p.h"
|
||||
#include "sftpdefs.h"
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
class SftpOutgoingPacket : public AbstractSftpPacket
|
||||
{
|
||||
public:
|
||||
SftpOutgoingPacket();
|
||||
SftpOutgoingPacket &generateInit(quint32 version);
|
||||
SftpOutgoingPacket &generateStat(const QString &path, quint32 requestId);
|
||||
SftpOutgoingPacket &generateOpenDir(const QString &path, quint32 requestId);
|
||||
SftpOutgoingPacket &generateReadDir(const QByteArray &handle,
|
||||
quint32 requestId);
|
||||
SftpOutgoingPacket &generateCloseHandle(const QByteArray &handle,
|
||||
quint32 requestId);
|
||||
SftpOutgoingPacket &generateMkDir(const QString &path, quint32 requestId);
|
||||
SftpOutgoingPacket &generateRmDir(const QString &path, quint32 requestId);
|
||||
SftpOutgoingPacket &generateRm(const QString &path, quint32 requestId);
|
||||
SftpOutgoingPacket &generateRename(const QString &oldPath,
|
||||
const QString &newPath, quint32 requestId);
|
||||
SftpOutgoingPacket &generateOpenFileForWriting(const QString &path,
|
||||
SftpOverwriteMode mode, quint32 permissions, quint32 requestId);
|
||||
SftpOutgoingPacket &generateOpenFileForReading(const QString &path,
|
||||
quint32 requestId);
|
||||
SftpOutgoingPacket &generateReadFile(const QByteArray &handle,
|
||||
quint64 offset, quint32 length, quint32 requestId);
|
||||
SftpOutgoingPacket &generateFstat(const QByteArray &handle,
|
||||
quint32 requestId);
|
||||
SftpOutgoingPacket &generateWriteFile(const QByteArray &handle,
|
||||
quint64 offset, const QByteArray &data, quint32 requestId);
|
||||
|
||||
// Note: OpenSSH's SFTP server has a bug that reverses the filePath and target
|
||||
// arguments, so this operation is not portable.
|
||||
SftpOutgoingPacket &generateCreateLink(const QString &filePath, const QString &target,
|
||||
quint32 requestId);
|
||||
|
||||
static const quint32 DefaultPermissions;
|
||||
|
||||
private:
|
||||
static QByteArray encodeString(const QString &string);
|
||||
|
||||
enum OpenType { Read, Write };
|
||||
SftpOutgoingPacket &generateOpenFile(const QString &path, OpenType openType,
|
||||
SftpOverwriteMode mode, const QList<quint32> &attributes, quint32 requestId);
|
||||
|
||||
SftpOutgoingPacket &init(SftpPacketType type, quint32 requestId);
|
||||
SftpOutgoingPacket &appendInt(quint32 value);
|
||||
SftpOutgoingPacket &appendInt64(quint64 value);
|
||||
SftpOutgoingPacket &appendString(const QString &string);
|
||||
SftpOutgoingPacket &appendString(const QByteArray &string);
|
||||
SftpOutgoingPacket &finalize();
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // SFTPOUTGOINGPACKET_P_H
|
||||
@@ -1,57 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "sftppacket_p.h"
|
||||
|
||||
#include "sshpacketparser_p.h"
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
// There's no "standard" or negotiation between server and client for this, so
|
||||
// just use the same as openssh's sftp implementation
|
||||
const quint32 AbstractSftpPacket::MaxDataSize = 32768;
|
||||
const quint32 AbstractSftpPacket::MaxPacketSize = 256 * 1024;
|
||||
|
||||
const int AbstractSftpPacket::TypeOffset = 4;
|
||||
const int AbstractSftpPacket::RequestIdOffset = TypeOffset + 1;
|
||||
const int AbstractSftpPacket::PayloadOffset = RequestIdOffset + 4;
|
||||
|
||||
AbstractSftpPacket::AbstractSftpPacket()
|
||||
{
|
||||
}
|
||||
|
||||
quint32 AbstractSftpPacket::requestId() const
|
||||
{
|
||||
return SshPacketParser::asUint32(m_data, RequestIdOffset);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
@@ -1,117 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SFTPPACKET_P_H
|
||||
#define SFTPPACKET_P_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
enum SftpPacketType {
|
||||
SSH_FXP_INIT = 1,
|
||||
SSH_FXP_VERSION = 2,
|
||||
SSH_FXP_OPEN = 3,
|
||||
SSH_FXP_CLOSE = 4,
|
||||
SSH_FXP_READ = 5,
|
||||
SSH_FXP_WRITE = 6,
|
||||
SSH_FXP_LSTAT = 7,
|
||||
SSH_FXP_FSTAT = 8,
|
||||
SSH_FXP_SETSTAT = 9,
|
||||
SSH_FXP_FSETSTAT = 10,
|
||||
SSH_FXP_OPENDIR = 11,
|
||||
SSH_FXP_READDIR = 12,
|
||||
SSH_FXP_REMOVE = 13,
|
||||
SSH_FXP_MKDIR = 14,
|
||||
SSH_FXP_RMDIR = 15,
|
||||
SSH_FXP_REALPATH = 16,
|
||||
SSH_FXP_STAT = 17,
|
||||
SSH_FXP_RENAME = 18,
|
||||
SSH_FXP_READLINK = 19,
|
||||
SSH_FXP_SYMLINK = 20, // Removed from later protocol versions. Try not to use.
|
||||
|
||||
SSH_FXP_STATUS = 101,
|
||||
SSH_FXP_HANDLE = 102,
|
||||
SSH_FXP_DATA = 103,
|
||||
SSH_FXP_NAME = 104,
|
||||
SSH_FXP_ATTRS = 105,
|
||||
|
||||
SSH_FXP_EXTENDED = 200,
|
||||
SSH_FXP_EXTENDED_REPLY = 201
|
||||
};
|
||||
|
||||
enum SftpStatusCode {
|
||||
SSH_FX_OK = 0,
|
||||
SSH_FX_EOF = 1,
|
||||
SSH_FX_NO_SUCH_FILE = 2,
|
||||
SSH_FX_PERMISSION_DENIED = 3,
|
||||
SSH_FX_FAILURE = 4,
|
||||
SSH_FX_BAD_MESSAGE = 5,
|
||||
SSH_FX_NO_CONNECTION = 6,
|
||||
SSH_FX_CONNECTION_LOST = 7,
|
||||
SSH_FX_OP_UNSUPPORTED = 8
|
||||
};
|
||||
|
||||
enum SftpAttributeType {
|
||||
SSH_FILEXFER_ATTR_SIZE = 0x00000001,
|
||||
SSH_FILEXFER_ATTR_UIDGID = 0x00000002,
|
||||
SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004,
|
||||
SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008,
|
||||
SSH_FILEXFER_ATTR_EXTENDED = 0x80000000
|
||||
};
|
||||
|
||||
class AbstractSftpPacket
|
||||
{
|
||||
public:
|
||||
AbstractSftpPacket();
|
||||
quint32 requestId() const;
|
||||
const QByteArray &rawData() const { return m_data; }
|
||||
SftpPacketType type() const { return static_cast<SftpPacketType>(m_data.at(TypeOffset)); }
|
||||
|
||||
static const quint32 MaxDataSize; // "Pure" data size per read/writepacket.
|
||||
static const quint32 MaxPacketSize;
|
||||
|
||||
protected:
|
||||
quint32 dataSize() const { return static_cast<quint32>(m_data.size()); }
|
||||
|
||||
static const int TypeOffset;
|
||||
static const int RequestIdOffset;
|
||||
static const int PayloadOffset;
|
||||
|
||||
QByteArray m_data;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // SFTPPACKET_P_H
|
||||
@@ -1,54 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SSH_GLOBAL_H
|
||||
#define SSH_GLOBAL_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// For static cmake building removing dll export/import
|
||||
# define QSSH_EXPORT
|
||||
#else
|
||||
|
||||
#if defined(QTCSSH_LIBRARY)
|
||||
# define QSSH_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define QSSH_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define QSSH_PRINT_WARNING qWarning("Soft assert at %s:%d", __FILE__, __LINE__)
|
||||
#define QSSH_ASSERT(cond) do { if (!(cond)) { QSSH_PRINT_WARNING; } } while (false)
|
||||
#define QSSH_ASSERT_AND_RETURN(cond) do { if (!(cond)) { QSSH_PRINT_WARNING; return; } } while (false)
|
||||
#define QSSH_ASSERT_AND_RETURN_VALUE(cond, value) do { if (!(cond)) { QSSH_PRINT_WARNING; return value; } } while (false)
|
||||
|
||||
#endif // SSH_GLOBAL_H
|
||||
@@ -1,313 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "sshagent_p.h"
|
||||
|
||||
#include "sshlogging_p.h"
|
||||
#include "sshpacket_p.h"
|
||||
#include "sshpacketparser_p.h"
|
||||
#include "ssh_global.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QtEndian>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
// https://github.com/openssh/openssh-portable/blob/V_7_2/PROTOCOL.agent
|
||||
enum PacketType {
|
||||
SSH_AGENT_FAILURE = 5,
|
||||
SSH2_AGENTC_REQUEST_IDENTITIES = 11,
|
||||
SSH2_AGENTC_SIGN_REQUEST = 13,
|
||||
SSH2_AGENT_IDENTITIES_ANSWER = 12,
|
||||
SSH2_AGENT_SIGN_RESPONSE = 14,
|
||||
};
|
||||
|
||||
// TODO: Remove once we require 5.7, where the endianness functions have a sane input type.
|
||||
template<typename T> static T fromBigEndian(const QByteArray &ba)
|
||||
{
|
||||
return qFromBigEndian<T>(reinterpret_cast<const uchar *>(ba.constData()));
|
||||
}
|
||||
|
||||
void SshAgent::refreshKeysImpl()
|
||||
{
|
||||
if (state() != Connected)
|
||||
return;
|
||||
const auto keysRequestIt = std::find_if(m_pendingRequests.constBegin(),
|
||||
m_pendingRequests.constEnd(), [](const Request &r) { return r.isKeysRequest(); });
|
||||
if (keysRequestIt != m_pendingRequests.constEnd()) {
|
||||
qCDebug(sshLog) << "keys request already pending, not adding another one";
|
||||
return;
|
||||
}
|
||||
qCDebug(sshLog) << "queueing keys request";
|
||||
m_pendingRequests << Request();
|
||||
sendNextRequest();
|
||||
}
|
||||
|
||||
void SshAgent::requestSignatureImpl(const QByteArray &key, uint token)
|
||||
{
|
||||
if (state() != Connected)
|
||||
return;
|
||||
const QByteArray data = m_dataToSign.take(qMakePair(key, token));
|
||||
QSSH_ASSERT(!data.isEmpty());
|
||||
qCDebug(sshLog) << "queueing signature request";
|
||||
m_pendingRequests.enqueue(Request(key, data, token));
|
||||
sendNextRequest();
|
||||
}
|
||||
|
||||
void SshAgent::sendNextRequest()
|
||||
{
|
||||
if (m_pendingRequests.isEmpty())
|
||||
return;
|
||||
if (m_outgoingPacket.isComplete())
|
||||
return;
|
||||
if (hasError())
|
||||
return;
|
||||
const Request &request = m_pendingRequests.head();
|
||||
m_outgoingPacket = request.isKeysRequest() ? generateKeysPacket() : generateSigPacket(request);
|
||||
sendPacket();
|
||||
}
|
||||
|
||||
SshAgent::Packet SshAgent::generateKeysPacket()
|
||||
{
|
||||
qCDebug(sshLog) << "requesting keys from agent";
|
||||
Packet p;
|
||||
p.size = 1;
|
||||
p.data += char(SSH2_AGENTC_REQUEST_IDENTITIES);
|
||||
return p;
|
||||
}
|
||||
|
||||
SshAgent::Packet SshAgent::generateSigPacket(const SshAgent::Request &request)
|
||||
{
|
||||
qCDebug(sshLog) << "requesting signature from agent for key" << request.key << "and token"
|
||||
<< request.token;
|
||||
Packet p;
|
||||
p.data += char(SSH2_AGENTC_SIGN_REQUEST);
|
||||
p.data += AbstractSshPacket::encodeString(request.key);
|
||||
p.data += AbstractSshPacket::encodeString(request.dataToSign);
|
||||
p.data += AbstractSshPacket::encodeInt(quint32(0));
|
||||
p.size = p.data.count();
|
||||
return p;
|
||||
}
|
||||
|
||||
SshAgent::~SshAgent()
|
||||
{
|
||||
m_agentSocket.disconnect(this);
|
||||
}
|
||||
|
||||
void SshAgent::storeDataToSign(const QByteArray &key, const QByteArray &data, uint token)
|
||||
{
|
||||
instance().m_dataToSign.insert(qMakePair(key, token), data);
|
||||
}
|
||||
|
||||
void SshAgent::removeDataToSign(const QByteArray &key, uint token)
|
||||
{
|
||||
instance().m_dataToSign.remove(qMakePair(key, token));
|
||||
}
|
||||
|
||||
SshAgent &QSsh::Internal::SshAgent::instance()
|
||||
{
|
||||
static SshAgent agent;
|
||||
return agent;
|
||||
}
|
||||
|
||||
SshAgent::SshAgent()
|
||||
{
|
||||
connect(&m_agentSocket, &QLocalSocket::connected, this, &SshAgent::handleConnected);
|
||||
connect(&m_agentSocket, &QLocalSocket::disconnected, this, &SshAgent::handleDisconnected);
|
||||
connect(&m_agentSocket, SIGNAL(error(QAbstractSocket::SocketError)), this,
|
||||
SLOT(handleSocketError()));
|
||||
connect(&m_agentSocket, &QLocalSocket::readyRead, this, &SshAgent::handleIncomingData);
|
||||
QTimer::singleShot(0, this, &SshAgent::connectToServer);
|
||||
}
|
||||
|
||||
void SshAgent::connectToServer()
|
||||
{
|
||||
const QByteArray serverAddress = qgetenv("SSH_AUTH_SOCK");
|
||||
if (serverAddress.isEmpty()) {
|
||||
qCDebug(sshLog) << "agent failure: socket address unknown";
|
||||
m_error = tr("Cannot connect to ssh-agent: SSH_AUTH_SOCK is not set.");
|
||||
emit errorOccurred();
|
||||
return;
|
||||
}
|
||||
qCDebug(sshLog) << "connecting to ssh-agent socket" << serverAddress;
|
||||
m_state = Connecting;
|
||||
m_agentSocket.connectToServer(QString::fromLocal8Bit(serverAddress));
|
||||
}
|
||||
|
||||
void SshAgent::handleConnected()
|
||||
{
|
||||
m_state = Connected;
|
||||
qCDebug(sshLog) << "connection to ssh-agent established";
|
||||
refreshKeys();
|
||||
}
|
||||
|
||||
void SshAgent::handleDisconnected()
|
||||
{
|
||||
qCDebug(sshLog) << "lost connection to ssh-agent";
|
||||
m_error = tr("Lost connection to ssh-agent for unknown reason.");
|
||||
setDisconnected();
|
||||
}
|
||||
|
||||
void SshAgent::handleSocketError()
|
||||
{
|
||||
qCDebug(sshLog) << "agent socket error" << m_agentSocket.error();
|
||||
m_error = m_agentSocket.errorString();
|
||||
setDisconnected();
|
||||
}
|
||||
|
||||
void SshAgent::handleIncomingData()
|
||||
{
|
||||
qCDebug(sshLog) << "getting data from agent";
|
||||
m_incomingData += m_agentSocket.readAll();
|
||||
while (!hasError() && !m_incomingData.isEmpty()) {
|
||||
if (m_incomingPacket.size == 0) {
|
||||
if (m_incomingData.count() < int(sizeof m_incomingPacket.size))
|
||||
break;
|
||||
m_incomingPacket.size = fromBigEndian<quint32>(m_incomingData);
|
||||
m_incomingData.remove(0, sizeof m_incomingPacket.size);
|
||||
}
|
||||
const int bytesToTake = qMin<quint32>(m_incomingPacket.size - m_incomingPacket.data.count(),
|
||||
m_incomingData.count());
|
||||
m_incomingPacket.data += m_incomingData.left(bytesToTake);
|
||||
m_incomingData.remove(0, bytesToTake);
|
||||
if (m_incomingPacket.isComplete())
|
||||
handleIncomingPacket();
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SshAgent::handleIncomingPacket()
|
||||
{
|
||||
try {
|
||||
qCDebug(sshLog) << "received packet from agent:" << m_incomingPacket.data.toHex();
|
||||
const char messageType = m_incomingPacket.data.at(0);
|
||||
switch (messageType) {
|
||||
case SSH2_AGENT_IDENTITIES_ANSWER:
|
||||
handleIdentitiesPacket();
|
||||
break;
|
||||
case SSH2_AGENT_SIGN_RESPONSE:
|
||||
handleSignaturePacket();
|
||||
break;
|
||||
case SSH_AGENT_FAILURE:
|
||||
if (m_pendingRequests.isEmpty()) {
|
||||
qCWarning(sshLog) << "unexpected failure message from agent";
|
||||
} else {
|
||||
const Request request = m_pendingRequests.dequeue();
|
||||
if (request.isSignatureRequest()) {
|
||||
qCWarning(sshLog) << "agent failed to sign message for key"
|
||||
<< request.key.toHex();
|
||||
emit signatureAvailable(request.key, QByteArray(), request.token);
|
||||
} else {
|
||||
qCWarning(sshLog) << "agent failed to retrieve key list";
|
||||
if (m_keys.isEmpty()) {
|
||||
m_error = tr("ssh-agent failed to retrieve keys.");
|
||||
setDisconnected();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qCWarning(sshLog) << "unexpected message type from agent:" << messageType;
|
||||
}
|
||||
} catch (const SshPacketParseException &) {
|
||||
qCWarning(sshLog()) << "received malformed packet from agent";
|
||||
handleProtocolError();
|
||||
}
|
||||
m_incomingPacket.invalidate();
|
||||
m_incomingPacket.size = 0;
|
||||
m_outgoingPacket.invalidate();
|
||||
sendNextRequest();
|
||||
}
|
||||
|
||||
void SshAgent::handleIdentitiesPacket()
|
||||
{
|
||||
qCDebug(sshLog) << "got keys packet from agent";
|
||||
if (m_pendingRequests.isEmpty() || !m_pendingRequests.dequeue().isKeysRequest()) {
|
||||
qCDebug(sshLog) << "packet was not requested";
|
||||
handleProtocolError();
|
||||
return;
|
||||
}
|
||||
quint32 offset = 1;
|
||||
const auto keyCount = SshPacketParser::asUint32(m_incomingPacket.data, &offset);
|
||||
qCDebug(sshLog) << "packet contains" << keyCount << "keys";
|
||||
QList<QByteArray> newKeys;
|
||||
for (quint32 i = 0; i < keyCount; ++i) {
|
||||
const QByteArray key = SshPacketParser::asString(m_incomingPacket.data, &offset);
|
||||
quint32 keyOffset = 0;
|
||||
const QByteArray algoName = SshPacketParser::asString(key, &keyOffset);
|
||||
SshPacketParser::asString(key, &keyOffset); // rest of key blob
|
||||
SshPacketParser::asString(m_incomingPacket.data, &offset); // comment
|
||||
qCDebug(sshLog) << "adding key of type" << algoName;
|
||||
newKeys << key;
|
||||
}
|
||||
|
||||
m_keys = newKeys;
|
||||
emit keysUpdated();
|
||||
}
|
||||
|
||||
void SshAgent::handleSignaturePacket()
|
||||
{
|
||||
qCDebug(sshLog) << "got signature packet from agent";
|
||||
if (m_pendingRequests.isEmpty()) {
|
||||
qCDebug(sshLog) << "signature packet was not requested";
|
||||
handleProtocolError();
|
||||
return;
|
||||
}
|
||||
const Request request = m_pendingRequests.dequeue();
|
||||
if (!request.isSignatureRequest()) {
|
||||
qCDebug(sshLog) << "signature packet was not requested";
|
||||
handleProtocolError();
|
||||
return;
|
||||
}
|
||||
const QByteArray signature = SshPacketParser::asString(m_incomingPacket.data, 1);
|
||||
qCDebug(sshLog) << "signature for key" << request.key.toHex() << "is" << signature.toHex();
|
||||
emit signatureAvailable(request.key, signature, request.token);
|
||||
}
|
||||
|
||||
void SshAgent::handleProtocolError()
|
||||
{
|
||||
m_error = tr("Protocol error when talking to ssh-agent.");
|
||||
setDisconnected();
|
||||
}
|
||||
|
||||
void SshAgent::setDisconnected()
|
||||
{
|
||||
m_state = Unconnected;
|
||||
m_agentSocket.disconnect(this);
|
||||
emit errorOccurred();
|
||||
}
|
||||
|
||||
void SshAgent::sendPacket()
|
||||
{
|
||||
const quint32 sizeMsb = qToBigEndian(m_outgoingPacket.size);
|
||||
m_agentSocket.write(reinterpret_cast<const char *>(&sizeMsb), sizeof sizeMsb);
|
||||
m_agentSocket.write(m_outgoingPacket.data);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
@@ -1,125 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QLocalSocket>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QQueue>
|
||||
#include <QString>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
class SshAgent : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum State { Unconnected, Connecting, Connected, };
|
||||
|
||||
~SshAgent();
|
||||
static State state() { return instance().m_state; }
|
||||
static bool hasError() { return !instance().m_error.isEmpty(); }
|
||||
static QString errorString() { return instance().m_error; }
|
||||
static QList<QByteArray> publicKeys() { return instance().m_keys; }
|
||||
|
||||
static void refreshKeys() { instance().refreshKeysImpl(); }
|
||||
static void storeDataToSign(const QByteArray &key, const QByteArray &data, uint token);
|
||||
static void removeDataToSign(const QByteArray &key, uint token);
|
||||
static void requestSignature(const QByteArray &key, uint token) {
|
||||
instance().requestSignatureImpl(key, token);
|
||||
}
|
||||
|
||||
static SshAgent &instance();
|
||||
|
||||
signals:
|
||||
void errorOccurred();
|
||||
void keysUpdated();
|
||||
|
||||
// Empty signature means signing failure.
|
||||
void signatureAvailable(const QByteArray &key, const QByteArray &signature, uint token);
|
||||
|
||||
private:
|
||||
struct Request {
|
||||
Request() { }
|
||||
Request(const QByteArray &k, const QByteArray &d, uint t)
|
||||
: key(k), dataToSign(d), token(t) { }
|
||||
|
||||
bool isKeysRequest() const { return !isSignatureRequest(); }
|
||||
bool isSignatureRequest() const { return !key.isEmpty(); }
|
||||
|
||||
QByteArray key;
|
||||
QByteArray dataToSign;
|
||||
uint token = 0;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
bool isComplete() const { return size != 0 && int(size) == data.count(); }
|
||||
void invalidate() { size = 0; data.clear(); }
|
||||
|
||||
quint32 size = 0;
|
||||
QByteArray data;
|
||||
};
|
||||
|
||||
SshAgent();
|
||||
void connectToServer();
|
||||
void refreshKeysImpl();
|
||||
void requestSignatureImpl(const QByteArray &key, uint token);
|
||||
|
||||
void sendNextRequest();
|
||||
Packet generateKeysPacket();
|
||||
Packet generateSigPacket(const Request &request);
|
||||
|
||||
void handleConnected();
|
||||
void handleDisconnected();
|
||||
void handleSocketError();
|
||||
void handleIncomingData();
|
||||
void handleIncomingPacket();
|
||||
void handleIdentitiesPacket();
|
||||
void handleSignaturePacket();
|
||||
|
||||
void handleProtocolError();
|
||||
void setDisconnected();
|
||||
|
||||
void sendPacket();
|
||||
|
||||
State m_state = Unconnected;
|
||||
QString m_error;
|
||||
QList<QByteArray> m_keys;
|
||||
QHash<QPair<QByteArray, uint>, QByteArray> m_dataToSign;
|
||||
QLocalSocket m_agentSocket;
|
||||
QByteArray m_incomingData;
|
||||
Packet m_incomingPacket;
|
||||
Packet m_outgoingPacket;
|
||||
|
||||
QQueue<Request> m_pendingRequests;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
@@ -1,172 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef BYTEARRAYCONVERSIONS_P_H
|
||||
#define BYTEARRAYCONVERSIONS_P_H
|
||||
|
||||
#include "sshcapabilities_p.h"
|
||||
#include "sshexception_p.h"
|
||||
|
||||
#include <botan_all.h>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
inline const Botan::byte *convertByteArray(const QByteArray &a)
|
||||
{
|
||||
return reinterpret_cast<const Botan::byte *>(a.constData());
|
||||
}
|
||||
|
||||
inline Botan::byte *convertByteArray(QByteArray &a)
|
||||
{
|
||||
return reinterpret_cast<Botan::byte *>(a.data());
|
||||
}
|
||||
|
||||
inline QByteArray convertByteArray(const Botan::secure_vector<Botan::byte> &v)
|
||||
{
|
||||
return QByteArray(reinterpret_cast<const char *>(v.data()), static_cast<int>(v.size()));
|
||||
}
|
||||
|
||||
inline QByteArray convertByteArray(const std::vector<uint8_t> &v)
|
||||
{
|
||||
return QByteArray(reinterpret_cast<const char *>(v.data()), v.size());
|
||||
}
|
||||
|
||||
inline const char *botanKeyExchangeAlgoName(const QByteArray &rfcAlgoName)
|
||||
{
|
||||
if (rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1)
|
||||
return "modp/ietf/1024";
|
||||
if (rfcAlgoName == SshCapabilities::DiffieHellmanGroup14Sha1)
|
||||
return "modp/ietf/2048";
|
||||
if (rfcAlgoName == SshCapabilities::EcdhNistp256)
|
||||
return "secp256r1";
|
||||
if (rfcAlgoName == SshCapabilities::EcdhNistp384)
|
||||
return "secp384r1";
|
||||
if (rfcAlgoName == SshCapabilities::EcdhNistp521)
|
||||
return "secp521r1";
|
||||
throw SshClientException(SshInternalError, SSH_TR("Unexpected key exchange algorithm \"%1\"")
|
||||
.arg(QString::fromLatin1(rfcAlgoName)));
|
||||
}
|
||||
|
||||
inline const char *botanCipherAlgoName(const QByteArray &rfcAlgoName)
|
||||
{
|
||||
|
||||
if (rfcAlgoName == SshCapabilities::CryptAlgoAes128Cbc) {
|
||||
return "CBC(AES-128)";
|
||||
}
|
||||
if (rfcAlgoName == SshCapabilities::CryptAlgoAes128Ctr) {
|
||||
return "CTR(AES-128)";
|
||||
}
|
||||
if (rfcAlgoName == SshCapabilities::CryptAlgo3DesCbc) {
|
||||
return "CBC(TripleDES)";
|
||||
}
|
||||
if (rfcAlgoName == SshCapabilities::CryptAlgo3DesCtr) {
|
||||
return "CTR(TripleDES)";
|
||||
}
|
||||
if (rfcAlgoName == SshCapabilities::CryptAlgoAes192Ctr) {
|
||||
return "CBR(AES-192)";
|
||||
}
|
||||
if (rfcAlgoName == SshCapabilities::CryptAlgoAes256Ctr) {
|
||||
return "CTR(AES-256)";
|
||||
}
|
||||
throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"")
|
||||
.arg(QString::fromLatin1(rfcAlgoName)));
|
||||
}
|
||||
|
||||
|
||||
inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName)
|
||||
{
|
||||
|
||||
if (rfcAlgoName == SshCapabilities::CryptAlgoAes128Cbc
|
||||
|| rfcAlgoName == SshCapabilities::CryptAlgoAes128Ctr) {
|
||||
return "AES-128";
|
||||
}
|
||||
if (rfcAlgoName == SshCapabilities::CryptAlgo3DesCbc
|
||||
|| rfcAlgoName == SshCapabilities::CryptAlgo3DesCtr) {
|
||||
return "TripleDES";
|
||||
}
|
||||
if (rfcAlgoName == SshCapabilities::CryptAlgoAes192Ctr) {
|
||||
return "AES-192";
|
||||
}
|
||||
if (rfcAlgoName == SshCapabilities::CryptAlgoAes256Ctr) {
|
||||
return "AES-256";
|
||||
}
|
||||
throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"")
|
||||
.arg(QString::fromLatin1(rfcAlgoName)));
|
||||
}
|
||||
|
||||
inline const char *botanEmsaAlgoName(const QByteArray &rfcAlgoName)
|
||||
{
|
||||
if (rfcAlgoName == SshCapabilities::PubKeyDss)
|
||||
return "EMSA1(SHA-1)";
|
||||
if (rfcAlgoName == SshCapabilities::PubKeyRsa)
|
||||
return "EMSA3(SHA-1)";
|
||||
if (rfcAlgoName == SshCapabilities::PubKeyEcdsa256)
|
||||
return "EMSA1(SHA-256)";
|
||||
if (rfcAlgoName == SshCapabilities::PubKeyEcdsa384)
|
||||
return "EMSA1_BSI(SHA-384)";
|
||||
if (rfcAlgoName == SshCapabilities::PubKeyEcdsa521)
|
||||
return "EMSA1_BSI(SHA-512)";
|
||||
throw SshClientException(SshInternalError, SSH_TR("Unexpected host key algorithm \"%1\"")
|
||||
.arg(QString::fromLatin1(rfcAlgoName)));
|
||||
}
|
||||
|
||||
inline const char *botanHMacAlgoName(const QByteArray &rfcAlgoName)
|
||||
{
|
||||
if (rfcAlgoName == SshCapabilities::HMacSha1)
|
||||
return "SHA-1";
|
||||
if (rfcAlgoName == SshCapabilities::HMacSha256)
|
||||
return "SHA-256";
|
||||
if (rfcAlgoName == SshCapabilities::HMacSha384)
|
||||
return "SHA-384";
|
||||
if (rfcAlgoName == SshCapabilities::HMacSha512)
|
||||
return "SHA-512";
|
||||
throw SshClientException(SshInternalError, SSH_TR("Unexpected hashing algorithm \"%1\"")
|
||||
.arg(QString::fromLatin1(rfcAlgoName)));
|
||||
}
|
||||
|
||||
inline quint32 botanHMacKeyLen(const QByteArray &rfcAlgoName)
|
||||
{
|
||||
if (rfcAlgoName == SshCapabilities::HMacSha1)
|
||||
return 20;
|
||||
if (rfcAlgoName == SshCapabilities::HMacSha256)
|
||||
return 32;
|
||||
if (rfcAlgoName == SshCapabilities::HMacSha384)
|
||||
return 48;
|
||||
if (rfcAlgoName == SshCapabilities::HMacSha512)
|
||||
return 64;
|
||||
throw SshClientException(SshInternalError, SSH_TR("Unexpected hashing algorithm \"%1\"")
|
||||
.arg(QString::fromLatin1(rfcAlgoName)));
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // BYTEARRAYCONVERSIONS_P_H
|
||||
@@ -1,177 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "sshcapabilities_p.h"
|
||||
|
||||
#include "sshexception_p.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
namespace {
|
||||
QByteArray listAsByteArray(const QList<QByteArray> &list)
|
||||
{
|
||||
QByteArray array;
|
||||
foreach(const QByteArray &elem, list)
|
||||
array += elem + ',';
|
||||
if (!array.isEmpty())
|
||||
array.remove(array.count() - 1, 1);
|
||||
return array;
|
||||
}
|
||||
} // anonymous namspace
|
||||
|
||||
const QByteArray SshCapabilities::DiffieHellmanGroup1Sha1("diffie-hellman-group1-sha1");
|
||||
const QByteArray SshCapabilities::DiffieHellmanGroup14Sha1("diffie-hellman-group14-sha1");
|
||||
const QByteArray SshCapabilities::EcdhKexNamePrefix("ecdh-sha2-nistp");
|
||||
const QByteArray SshCapabilities::EcdhNistp256 = EcdhKexNamePrefix + "256";
|
||||
const QByteArray SshCapabilities::EcdhNistp384 = EcdhKexNamePrefix + "384";
|
||||
const QByteArray SshCapabilities::EcdhNistp521 = EcdhKexNamePrefix + "521";
|
||||
const QList<QByteArray> SshCapabilities::KeyExchangeMethods = QList<QByteArray>()
|
||||
<< SshCapabilities::EcdhNistp256
|
||||
<< SshCapabilities::EcdhNistp384
|
||||
<< SshCapabilities::EcdhNistp521
|
||||
<< SshCapabilities::DiffieHellmanGroup1Sha1
|
||||
<< SshCapabilities::DiffieHellmanGroup14Sha1;
|
||||
|
||||
const QByteArray SshCapabilities::PubKeyDss("ssh-dss");
|
||||
const QByteArray SshCapabilities::PubKeyRsa("ssh-rsa");
|
||||
const QByteArray SshCapabilities::PubKeyEcdsaPrefix("ecdsa-sha2-nistp");
|
||||
const QByteArray SshCapabilities::PubKeyEcdsa256 = SshCapabilities::PubKeyEcdsaPrefix + "256";
|
||||
const QByteArray SshCapabilities::PubKeyEcdsa384 = SshCapabilities::PubKeyEcdsaPrefix + "384";
|
||||
const QByteArray SshCapabilities::PubKeyEcdsa521 = SshCapabilities::PubKeyEcdsaPrefix + "521";
|
||||
const QList<QByteArray> SshCapabilities::PublicKeyAlgorithms = QList<QByteArray>()
|
||||
<< SshCapabilities::PubKeyEcdsa256
|
||||
<< SshCapabilities::PubKeyEcdsa384
|
||||
<< SshCapabilities::PubKeyEcdsa521
|
||||
<< SshCapabilities::PubKeyRsa
|
||||
<< SshCapabilities::PubKeyDss;
|
||||
|
||||
const QByteArray SshCapabilities::CryptAlgo3DesCbc("3des-cbc");
|
||||
const QByteArray SshCapabilities::CryptAlgo3DesCtr("3des-ctr");
|
||||
const QByteArray SshCapabilities::CryptAlgoAes128Cbc("aes128-cbc");
|
||||
const QByteArray SshCapabilities::CryptAlgoAes128Ctr("aes128-ctr");
|
||||
const QByteArray SshCapabilities::CryptAlgoAes192Ctr("aes192-ctr");
|
||||
const QByteArray SshCapabilities::CryptAlgoAes256Ctr("aes256-ctr");
|
||||
const QList<QByteArray> SshCapabilities::EncryptionAlgorithms
|
||||
= QList<QByteArray>() << SshCapabilities::CryptAlgoAes256Ctr
|
||||
<< SshCapabilities::CryptAlgoAes192Ctr
|
||||
<< SshCapabilities::CryptAlgoAes128Ctr
|
||||
<< SshCapabilities::CryptAlgo3DesCtr
|
||||
<< SshCapabilities::CryptAlgoAes128Cbc
|
||||
<< SshCapabilities::CryptAlgo3DesCbc;
|
||||
|
||||
const QByteArray SshCapabilities::HMacSha1("hmac-sha1");
|
||||
const QByteArray SshCapabilities::HMacSha196("hmac-sha1-96");
|
||||
const QByteArray SshCapabilities::HMacSha256("hmac-sha2-256");
|
||||
const QByteArray SshCapabilities::HMacSha384("hmac-sha2-384");
|
||||
const QByteArray SshCapabilities::HMacSha512("hmac-sha2-512");
|
||||
const QList<QByteArray> SshCapabilities::MacAlgorithms
|
||||
= QList<QByteArray>() /* << SshCapabilities::HMacSha196 */
|
||||
<< SshCapabilities::HMacSha256
|
||||
<< SshCapabilities::HMacSha384
|
||||
<< SshCapabilities::HMacSha512
|
||||
<< SshCapabilities::HMacSha1;
|
||||
|
||||
const QList<QByteArray> SshCapabilities::CompressionAlgorithms
|
||||
= QList<QByteArray>() << "none";
|
||||
|
||||
const QByteArray SshCapabilities::SshConnectionService("ssh-connection");
|
||||
|
||||
QList<QByteArray> SshCapabilities::commonCapabilities(const QList<QByteArray> &myCapabilities,
|
||||
const QList<QByteArray> &serverCapabilities, const QByteArray &group)
|
||||
{
|
||||
QList<QByteArray> capabilities;
|
||||
foreach (const QByteArray &myCapability, myCapabilities) {
|
||||
if (serverCapabilities.contains(myCapability))
|
||||
capabilities << myCapability;
|
||||
}
|
||||
|
||||
if (!capabilities.isEmpty())
|
||||
return capabilities;
|
||||
|
||||
throw SshServerException(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
|
||||
"Server and client capabilities do not match.",
|
||||
QCoreApplication::translate("SshConnection",
|
||||
"Server and client %1 capabilities don't match.\n"
|
||||
"Client list: %2\n"
|
||||
"Server list: %3")
|
||||
.arg(QString::fromLatin1(group))
|
||||
.arg(QString::fromLocal8Bit(listAsByteArray(myCapabilities).data()))
|
||||
.arg(QString::fromLocal8Bit(listAsByteArray(serverCapabilities).data())));
|
||||
|
||||
}
|
||||
|
||||
QByteArray SshCapabilities::findBestMatch(const QList<QByteArray> &myCapabilities,
|
||||
const QList<QByteArray> &serverCapabilities, const QByteArray &group)
|
||||
{
|
||||
return commonCapabilities(myCapabilities, serverCapabilities, group).first();
|
||||
}
|
||||
|
||||
int SshCapabilities::ecdsaIntegerWidthInBytes(const QByteArray &ecdsaAlgo)
|
||||
{
|
||||
if (ecdsaAlgo == PubKeyEcdsa256)
|
||||
return 32;
|
||||
if (ecdsaAlgo == PubKeyEcdsa384)
|
||||
return 48;
|
||||
if (ecdsaAlgo == PubKeyEcdsa521)
|
||||
return 66;
|
||||
throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa algorithm \"%1\"")
|
||||
.arg(QString::fromLatin1(ecdsaAlgo)));
|
||||
}
|
||||
|
||||
QByteArray SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(int keyWidthInBytes)
|
||||
{
|
||||
if (keyWidthInBytes <= 32)
|
||||
return PubKeyEcdsa256;
|
||||
if (keyWidthInBytes <= 48)
|
||||
return PubKeyEcdsa384;
|
||||
if (keyWidthInBytes <= 66)
|
||||
return PubKeyEcdsa521;
|
||||
throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa key size (%1 bytes)")
|
||||
.arg(keyWidthInBytes));
|
||||
}
|
||||
|
||||
const char *SshCapabilities::oid(const QByteArray &ecdsaAlgo)
|
||||
{
|
||||
if (ecdsaAlgo == PubKeyEcdsa256)
|
||||
return "secp256r1";
|
||||
if (ecdsaAlgo == PubKeyEcdsa384)
|
||||
return "secp384r1";
|
||||
if (ecdsaAlgo == PubKeyEcdsa521)
|
||||
return "secp521r1";
|
||||
throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa algorithm \"%1\"")
|
||||
.arg(QString::fromLatin1(ecdsaAlgo)));
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
@@ -1,91 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef CAPABILITIES_P_H
|
||||
#define CAPABILITIES_P_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
class SshCapabilities
|
||||
{
|
||||
public:
|
||||
static const QByteArray DiffieHellmanGroup1Sha1;
|
||||
static const QByteArray DiffieHellmanGroup14Sha1;
|
||||
static const QByteArray EcdhKexNamePrefix;
|
||||
static const QByteArray EcdhNistp256;
|
||||
static const QByteArray EcdhNistp384;
|
||||
static const QByteArray EcdhNistp521; // sic
|
||||
static const QList<QByteArray> KeyExchangeMethods;
|
||||
|
||||
static const QByteArray PubKeyDss;
|
||||
static const QByteArray PubKeyRsa;
|
||||
static const QByteArray PubKeyEcdsaPrefix;
|
||||
static const QByteArray PubKeyEcdsa256;
|
||||
static const QByteArray PubKeyEcdsa384;
|
||||
static const QByteArray PubKeyEcdsa521;
|
||||
static const QList<QByteArray> PublicKeyAlgorithms;
|
||||
|
||||
static const QByteArray CryptAlgo3DesCbc;
|
||||
static const QByteArray CryptAlgo3DesCtr;
|
||||
static const QByteArray CryptAlgoAes128Cbc;
|
||||
static const QByteArray CryptAlgoAes128Ctr;
|
||||
static const QByteArray CryptAlgoAes192Ctr;
|
||||
static const QByteArray CryptAlgoAes256Ctr;
|
||||
static const QList<QByteArray> EncryptionAlgorithms;
|
||||
|
||||
static const QByteArray HMacSha1;
|
||||
static const QByteArray HMacSha196;
|
||||
static const QByteArray HMacSha256;
|
||||
static const QByteArray HMacSha384;
|
||||
static const QByteArray HMacSha512;
|
||||
static const QList<QByteArray> MacAlgorithms;
|
||||
|
||||
static const QList<QByteArray> CompressionAlgorithms;
|
||||
|
||||
static const QByteArray SshConnectionService;
|
||||
|
||||
static QList<QByteArray> commonCapabilities(const QList<QByteArray> &myCapabilities,
|
||||
const QList<QByteArray> &serverCapabilities, const QByteArray &group);
|
||||
static QByteArray findBestMatch(const QList<QByteArray> &myCapabilities,
|
||||
const QList<QByteArray> &serverCapabilities, const QByteArray &group);
|
||||
|
||||
static int ecdsaIntegerWidthInBytes(const QByteArray &ecdsaAlgo);
|
||||
static QByteArray ecdsaPubKeyAlgoForKeyWidth(int keyWidthInBytes);
|
||||
static const char *oid(const QByteArray &ecdsaAlgo);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // CAPABILITIES_P_H
|
||||
@@ -1,277 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "sshchannel_p.h"
|
||||
|
||||
#include "sshincomingpacket_p.h"
|
||||
#include "sshsendfacility_p.h"
|
||||
#include "sshlogging_p.h"
|
||||
|
||||
#include <botan_all.h>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
const quint32 NoChannel = 0xffffffffu;
|
||||
|
||||
AbstractSshChannel::AbstractSshChannel(quint32 channelId,
|
||||
SshSendFacility &sendFacility)
|
||||
: m_sendFacility(sendFacility),
|
||||
m_localChannel(channelId), m_remoteChannel(NoChannel),
|
||||
m_localWindowSize(initialWindowSize()), m_remoteWindowSize(0),
|
||||
m_state(Inactive)
|
||||
{
|
||||
m_timeoutTimer.setTimerType(Qt::VeryCoarseTimer);
|
||||
m_timeoutTimer.setSingleShot(true);
|
||||
connect(&m_timeoutTimer, &QTimer::timeout, this, &AbstractSshChannel::timeout);
|
||||
}
|
||||
|
||||
AbstractSshChannel::~AbstractSshChannel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AbstractSshChannel::setChannelState(ChannelState state)
|
||||
{
|
||||
m_state = state;
|
||||
if (state == Closed)
|
||||
closeHook();
|
||||
}
|
||||
|
||||
void AbstractSshChannel::requestSessionStart()
|
||||
{
|
||||
// Note: We are just being paranoid here about the Botan exceptions,
|
||||
// which are extremely unlikely to happen, because if there was a problem
|
||||
// with our cryptography stuff, it would have hit us before, on
|
||||
// establishing the connection.
|
||||
try {
|
||||
m_sendFacility.sendSessionPacket(m_localChannel, initialWindowSize(), maxPacketSize());
|
||||
setChannelState(SessionRequested);
|
||||
m_timeoutTimer.start(ReplyTimeout);
|
||||
} catch (const std::exception &e) {
|
||||
qCWarning(sshLog, "Botan error: %s", e.what());
|
||||
closeChannel();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractSshChannel::sendData(const QByteArray &data)
|
||||
{
|
||||
try {
|
||||
m_sendBuffer += data;
|
||||
flushSendBuffer();
|
||||
} catch (const std::exception &e) {
|
||||
qCWarning(sshLog, "Botan error: %s", e.what());
|
||||
closeChannel();
|
||||
}
|
||||
}
|
||||
|
||||
quint32 AbstractSshChannel::initialWindowSize()
|
||||
{
|
||||
return maxPacketSize();
|
||||
}
|
||||
|
||||
quint32 AbstractSshChannel::maxPacketSize()
|
||||
{
|
||||
return 16 * 1024 * 1024;
|
||||
}
|
||||
|
||||
void AbstractSshChannel::handleWindowAdjust(quint64 bytesToAdd)
|
||||
{
|
||||
checkChannelActive();
|
||||
|
||||
const quint64 newValue = m_remoteWindowSize + bytesToAdd;
|
||||
if (newValue > 0xffffffffu) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Illegal window size requested.");
|
||||
}
|
||||
|
||||
m_remoteWindowSize = newValue;
|
||||
flushSendBuffer();
|
||||
}
|
||||
|
||||
void AbstractSshChannel::flushSendBuffer()
|
||||
{
|
||||
while (true) {
|
||||
const quint32 bytesToSend = qMin(m_remoteMaxPacketSize,
|
||||
qMin<quint32>(m_remoteWindowSize, m_sendBuffer.size()));
|
||||
if (bytesToSend == 0)
|
||||
break;
|
||||
const QByteArray &data = m_sendBuffer.left(bytesToSend);
|
||||
m_sendFacility.sendChannelDataPacket(m_remoteChannel, data);
|
||||
m_sendBuffer.remove(0, bytesToSend);
|
||||
m_remoteWindowSize -= bytesToSend;
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractSshChannel::handleOpenSuccess(quint32 remoteChannelId,
|
||||
quint32 remoteWindowSize, quint32 remoteMaxPacketSize)
|
||||
{
|
||||
const ChannelState oldState = m_state;
|
||||
switch (oldState) {
|
||||
case CloseRequested: // closeChannel() was called while we were in SessionRequested state
|
||||
case SessionRequested:
|
||||
break; // Ok, continue.
|
||||
default:
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet.");
|
||||
}
|
||||
|
||||
m_timeoutTimer.stop();
|
||||
|
||||
qCDebug(sshLog, "Channel opened. remote channel id: %u, remote window size: %u, "
|
||||
"remote max packet size: %u",
|
||||
remoteChannelId, remoteWindowSize, remoteMaxPacketSize);
|
||||
m_remoteChannel = remoteChannelId;
|
||||
m_remoteWindowSize = remoteWindowSize;
|
||||
m_remoteMaxPacketSize = remoteMaxPacketSize;
|
||||
setChannelState(SessionEstablished);
|
||||
if (oldState == CloseRequested)
|
||||
closeChannel();
|
||||
else
|
||||
handleOpenSuccessInternal();
|
||||
}
|
||||
|
||||
void AbstractSshChannel::handleOpenFailure(const QString &reason)
|
||||
{
|
||||
switch (m_state) {
|
||||
case SessionRequested:
|
||||
break; // Ok, continue.
|
||||
case CloseRequested:
|
||||
return; // Late server reply; we requested a channel close in the meantime.
|
||||
default:
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE packet.");
|
||||
}
|
||||
|
||||
m_timeoutTimer.stop();
|
||||
|
||||
qCDebug(sshLog, "Channel open request failed for channel %u", m_localChannel);
|
||||
handleOpenFailureInternal(reason);
|
||||
}
|
||||
|
||||
void AbstractSshChannel::handleChannelEof()
|
||||
{
|
||||
if (m_state == Inactive || m_state == Closed) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Unexpected SSH_MSG_CHANNEL_EOF message.");
|
||||
}
|
||||
m_localWindowSize = 0;
|
||||
emit eof();
|
||||
}
|
||||
|
||||
void AbstractSshChannel::handleChannelClose()
|
||||
{
|
||||
qCDebug(sshLog, "Receiving CLOSE for channel %u", m_localChannel);
|
||||
if (channelState() == Inactive || channelState() == Closed) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Unexpected SSH_MSG_CHANNEL_CLOSE message.");
|
||||
}
|
||||
closeChannel();
|
||||
setChannelState(Closed);
|
||||
}
|
||||
|
||||
void AbstractSshChannel::handleChannelData(const QByteArray &data)
|
||||
{
|
||||
const int bytesToDeliver = handleChannelOrExtendedChannelData(data);
|
||||
handleChannelDataInternal(bytesToDeliver == data.size()
|
||||
? data : data.left(bytesToDeliver));
|
||||
}
|
||||
|
||||
void AbstractSshChannel::handleChannelExtendedData(quint32 type, const QByteArray &data)
|
||||
{
|
||||
const int bytesToDeliver = handleChannelOrExtendedChannelData(data);
|
||||
handleChannelExtendedDataInternal(type, bytesToDeliver == data.size()
|
||||
? data : data.left(bytesToDeliver));
|
||||
}
|
||||
|
||||
void AbstractSshChannel::handleChannelRequest(const SshIncomingPacket &packet)
|
||||
{
|
||||
checkChannelActive();
|
||||
const QByteArray &requestType = packet.extractChannelRequestType();
|
||||
if (requestType == SshIncomingPacket::ExitStatusType)
|
||||
handleExitStatus(packet.extractChannelExitStatus());
|
||||
else if (requestType == SshIncomingPacket::ExitSignalType)
|
||||
handleExitSignal(packet.extractChannelExitSignal());
|
||||
else if (requestType != "eow@openssh.com") // Suppress warning for this one, as it's sent all the time.
|
||||
qCWarning(sshLog, "Ignoring unknown request type '%s'", requestType.data());
|
||||
}
|
||||
|
||||
int AbstractSshChannel::handleChannelOrExtendedChannelData(const QByteArray &data)
|
||||
{
|
||||
checkChannelActive();
|
||||
|
||||
const int bytesToDeliver = qMin<quint32>(data.size(), maxDataSize());
|
||||
if (bytesToDeliver != data.size())
|
||||
qCWarning(sshLog, "Misbehaving server does not respect local window, clipping.");
|
||||
|
||||
m_localWindowSize -= bytesToDeliver;
|
||||
if (m_localWindowSize < maxPacketSize()) {
|
||||
m_localWindowSize += maxPacketSize();
|
||||
m_sendFacility.sendWindowAdjustPacket(m_remoteChannel, maxPacketSize());
|
||||
}
|
||||
return bytesToDeliver;
|
||||
}
|
||||
|
||||
void AbstractSshChannel::closeChannel()
|
||||
{
|
||||
if (m_state == CloseRequested) {
|
||||
m_timeoutTimer.stop();
|
||||
} else if (m_state != Closed) {
|
||||
if (m_state == Inactive) {
|
||||
setChannelState(Closed);
|
||||
} else {
|
||||
const ChannelState oldState = m_state;
|
||||
setChannelState(CloseRequested);
|
||||
if (m_remoteChannel != NoChannel) {
|
||||
m_sendFacility.sendChannelEofPacket(m_remoteChannel);
|
||||
m_sendFacility.sendChannelClosePacket(m_remoteChannel);
|
||||
} else {
|
||||
QSSH_ASSERT(oldState == SessionRequested);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractSshChannel::checkChannelActive() const
|
||||
{
|
||||
if (channelState() == Inactive || channelState() == Closed)
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Channel not open.");
|
||||
}
|
||||
|
||||
quint32 AbstractSshChannel::maxDataSize() const
|
||||
{
|
||||
return qMin(m_localWindowSize, maxPacketSize());
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
@@ -1,125 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SSHCHANNEL_P_H
|
||||
#define SSHCHANNEL_P_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
struct SshChannelExitSignal;
|
||||
struct SshChannelExitStatus;
|
||||
class SshIncomingPacket;
|
||||
class SshSendFacility;
|
||||
|
||||
class AbstractSshChannel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ChannelState {
|
||||
Inactive, SessionRequested, SessionEstablished, CloseRequested, Closed
|
||||
};
|
||||
|
||||
quint32 localChannelId() const { return m_localChannel; }
|
||||
quint32 remoteChannel() const { return m_remoteChannel; }
|
||||
|
||||
virtual void handleChannelSuccess() = 0;
|
||||
virtual void handleChannelFailure() = 0;
|
||||
|
||||
void handleOpenSuccess(quint32 remoteChannelId, quint32 remoteWindowSize,
|
||||
quint32 remoteMaxPacketSize);
|
||||
void handleOpenFailure(const QString &reason);
|
||||
void handleWindowAdjust(quint64 bytesToAdd);
|
||||
void handleChannelEof();
|
||||
void handleChannelClose();
|
||||
void handleChannelData(const QByteArray &data);
|
||||
void handleChannelExtendedData(quint32 type, const QByteArray &data);
|
||||
void handleChannelRequest(const SshIncomingPacket &packet);
|
||||
|
||||
void closeChannel();
|
||||
|
||||
virtual ~AbstractSshChannel();
|
||||
|
||||
static const int ReplyTimeout = 10000; // milli seconds
|
||||
ChannelState channelState() const { return m_state; }
|
||||
|
||||
signals:
|
||||
void timeout();
|
||||
void eof();
|
||||
|
||||
protected:
|
||||
AbstractSshChannel(quint32 channelId, SshSendFacility &sendFacility);
|
||||
|
||||
void setChannelState(ChannelState state);
|
||||
|
||||
void requestSessionStart();
|
||||
void sendData(const QByteArray &data);
|
||||
|
||||
static quint32 initialWindowSize();
|
||||
static quint32 maxPacketSize();
|
||||
|
||||
quint32 maxDataSize() const;
|
||||
void checkChannelActive() const;
|
||||
|
||||
SshSendFacility &m_sendFacility;
|
||||
QTimer m_timeoutTimer;
|
||||
|
||||
private:
|
||||
virtual void handleOpenSuccessInternal() = 0;
|
||||
virtual void handleOpenFailureInternal(const QString &reason) = 0;
|
||||
virtual void handleChannelDataInternal(const QByteArray &data) = 0;
|
||||
virtual void handleChannelExtendedDataInternal(quint32 type,
|
||||
const QByteArray &data) = 0;
|
||||
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus) = 0;
|
||||
virtual void handleExitSignal(const SshChannelExitSignal &signal) = 0;
|
||||
|
||||
virtual void closeHook() = 0;
|
||||
|
||||
void flushSendBuffer();
|
||||
int handleChannelOrExtendedChannelData(const QByteArray &data);
|
||||
|
||||
const quint32 m_localChannel;
|
||||
quint32 m_remoteChannel;
|
||||
quint32 m_localWindowSize;
|
||||
quint32 m_remoteWindowSize;
|
||||
quint32 m_remoteMaxPacketSize;
|
||||
ChannelState m_state;
|
||||
QByteArray m_sendBuffer;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // SSHCHANNEL_P_H
|
||||
@@ -1,412 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "sshchannelmanager_p.h"
|
||||
|
||||
#include "sftpchannel.h"
|
||||
#include "sftpchannel_p.h"
|
||||
#include "sshdirecttcpiptunnel.h"
|
||||
#include "sshdirecttcpiptunnel_p.h"
|
||||
#include "sshforwardedtcpiptunnel.h"
|
||||
#include "sshforwardedtcpiptunnel_p.h"
|
||||
#include "sshincomingpacket_p.h"
|
||||
#include "sshlogging_p.h"
|
||||
#include "sshremoteprocess.h"
|
||||
#include "sshremoteprocess_p.h"
|
||||
#include "sshsendfacility_p.h"
|
||||
#include "sshtcpipforwardserver.h"
|
||||
#include "sshtcpipforwardserver_p.h"
|
||||
#include "sshx11channel_p.h"
|
||||
#include "sshx11inforetriever_p.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
|
||||
SshChannelManager::SshChannelManager(SshSendFacility &sendFacility,
|
||||
QObject *parent)
|
||||
: QObject(parent), m_sendFacility(sendFacility), m_nextLocalChannelId(0)
|
||||
{
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelRequest(const SshIncomingPacket &packet)
|
||||
{
|
||||
lookupChannel(packet.extractRecipientChannel())
|
||||
->handleChannelRequest(packet);
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelOpen(const SshIncomingPacket &packet)
|
||||
{
|
||||
const SshChannelOpenGeneric channelOpen = packet.extractChannelOpen();
|
||||
if (channelOpen.channelType == SshIncomingPacket::ForwardedTcpIpType) {
|
||||
handleChannelOpenForwardedTcpIp(channelOpen);
|
||||
return;
|
||||
}
|
||||
if (channelOpen.channelType == "x11") {
|
||||
handleChannelOpenX11(channelOpen);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
m_sendFacility.sendChannelOpenFailurePacket(channelOpen.commonData.remoteChannel,
|
||||
SSH_OPEN_UNKNOWN_CHANNEL_TYPE, QByteArray());
|
||||
} catch (const std::exception &e) {
|
||||
qCWarning(sshLog, "Botan error: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelOpenFailure(const SshIncomingPacket &packet)
|
||||
{
|
||||
const SshChannelOpenFailure &failure = packet.extractChannelOpenFailure();
|
||||
ChannelIterator it = lookupChannelAsIterator(failure.localChannel);
|
||||
try {
|
||||
it.value()->handleOpenFailure(failure.reasonString);
|
||||
} catch (const SshServerException &e) {
|
||||
removeChannel(it);
|
||||
throw;
|
||||
}
|
||||
removeChannel(it);
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelOpenConfirmation(const SshIncomingPacket &packet)
|
||||
{
|
||||
const SshChannelOpenConfirmation &confirmation
|
||||
= packet.extractChannelOpenConfirmation();
|
||||
lookupChannel(confirmation.localChannel)->handleOpenSuccess(confirmation.remoteChannel,
|
||||
confirmation.remoteWindowSize, confirmation.remoteMaxPacketSize);
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelSuccess(const SshIncomingPacket &packet)
|
||||
{
|
||||
lookupChannel(packet.extractRecipientChannel())->handleChannelSuccess();
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelFailure(const SshIncomingPacket &packet)
|
||||
{
|
||||
lookupChannel(packet.extractRecipientChannel())->handleChannelFailure();
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelWindowAdjust(const SshIncomingPacket &packet)
|
||||
{
|
||||
const SshChannelWindowAdjust adjust = packet.extractWindowAdjust();
|
||||
lookupChannel(adjust.localChannel)->handleWindowAdjust(adjust.bytesToAdd);
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelData(const SshIncomingPacket &packet)
|
||||
{
|
||||
const SshChannelData &data = packet.extractChannelData();
|
||||
lookupChannel(data.localChannel)->handleChannelData(data.data);
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelExtendedData(const SshIncomingPacket &packet)
|
||||
{
|
||||
const SshChannelExtendedData &data = packet.extractChannelExtendedData();
|
||||
lookupChannel(data.localChannel)->handleChannelExtendedData(data.type, data.data);
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelEof(const SshIncomingPacket &packet)
|
||||
{
|
||||
AbstractSshChannel * const channel
|
||||
= lookupChannel(packet.extractRecipientChannel(), true);
|
||||
if (channel)
|
||||
channel->handleChannelEof();
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelClose(const SshIncomingPacket &packet)
|
||||
{
|
||||
const quint32 channelId = packet.extractRecipientChannel();
|
||||
|
||||
ChannelIterator it = lookupChannelAsIterator(channelId, true);
|
||||
if (it != m_channels.end()) {
|
||||
it.value()->handleChannelClose();
|
||||
removeChannel(it);
|
||||
}
|
||||
}
|
||||
|
||||
void SshChannelManager::handleRequestSuccess(const SshIncomingPacket &packet)
|
||||
{
|
||||
if (m_waitingForwardServers.isEmpty()) {
|
||||
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Unexpected request success packet.",
|
||||
tr("Unexpected request success packet."));
|
||||
}
|
||||
SshTcpIpForwardServer::Ptr server = m_waitingForwardServers.takeFirst();
|
||||
if (server->state() == SshTcpIpForwardServer::Closing) {
|
||||
server->setClosed();
|
||||
} else if (server->state() == SshTcpIpForwardServer::Initializing) {
|
||||
quint16 port = server->port();
|
||||
if (port == 0)
|
||||
port = packet.extractRequestSuccess().bindPort;
|
||||
server->setListening(port);
|
||||
m_listeningForwardServers.append(server);
|
||||
} else {
|
||||
QSSH_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
void SshChannelManager::handleRequestFailure(const SshIncomingPacket &packet)
|
||||
{
|
||||
Q_UNUSED(packet);
|
||||
if (m_waitingForwardServers.isEmpty()) {
|
||||
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Unexpected request failure packet.",
|
||||
tr("Unexpected request failure packet."));
|
||||
}
|
||||
SshTcpIpForwardServer::Ptr tunnel = m_waitingForwardServers.takeFirst();
|
||||
tunnel->setClosed();
|
||||
}
|
||||
|
||||
SshChannelManager::ChannelIterator SshChannelManager::lookupChannelAsIterator(quint32 channelId,
|
||||
bool allowNotFound)
|
||||
{
|
||||
ChannelIterator it = m_channels.find(channelId);
|
||||
if (it == m_channels.end() && !allowNotFound) {
|
||||
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Invalid channel id.",
|
||||
tr("Invalid channel id %1").arg(channelId));
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
AbstractSshChannel *SshChannelManager::lookupChannel(quint32 channelId,
|
||||
bool allowNotFound)
|
||||
{
|
||||
ChannelIterator it = lookupChannelAsIterator(channelId, allowNotFound);
|
||||
return it == m_channels.end() ? nullptr : it.value();
|
||||
}
|
||||
|
||||
QSsh::SshRemoteProcess::Ptr SshChannelManager::createRemoteProcess(const QByteArray &command)
|
||||
{
|
||||
SshRemoteProcess::Ptr proc(new SshRemoteProcess(command, m_nextLocalChannelId++, m_sendFacility));
|
||||
insertChannel(proc->d, proc);
|
||||
connect(proc->d, &SshRemoteProcessPrivate::destroyed, this, [this] {
|
||||
m_x11ForwardingRequests.removeOne(static_cast<SshRemoteProcessPrivate *>(sender()));
|
||||
});
|
||||
connect(proc->d, &SshRemoteProcessPrivate::x11ForwardingRequested, this,
|
||||
[this, proc = proc->d](const QString &displayName) {
|
||||
if (!x11DisplayName().isEmpty()) {
|
||||
if (x11DisplayName() != displayName) {
|
||||
proc->failToStart(tr("Cannot forward to display %1 on SSH connection that is "
|
||||
"already forwarding to display %2.")
|
||||
.arg(displayName, x11DisplayName()));
|
||||
return;
|
||||
}
|
||||
if (!m_x11DisplayInfo.cookie.isEmpty())
|
||||
proc->startProcess(m_x11DisplayInfo);
|
||||
else
|
||||
m_x11ForwardingRequests << proc;
|
||||
return;
|
||||
}
|
||||
m_x11DisplayInfo.displayName = displayName;
|
||||
m_x11ForwardingRequests << proc;
|
||||
auto * const x11InfoRetriever = new SshX11InfoRetriever(displayName, this);
|
||||
const auto failureHandler = [this](const QString &errorMessage) {
|
||||
for (SshRemoteProcessPrivate * const proc : qAsConst(m_x11ForwardingRequests))
|
||||
proc->failToStart(errorMessage);
|
||||
m_x11ForwardingRequests.clear();
|
||||
};
|
||||
connect(x11InfoRetriever, &SshX11InfoRetriever::failure, this, failureHandler);
|
||||
const auto successHandler = [this](const X11DisplayInfo &displayInfo) {
|
||||
m_x11DisplayInfo = displayInfo;
|
||||
for (SshRemoteProcessPrivate * const proc : qAsConst(m_x11ForwardingRequests))
|
||||
proc->startProcess(displayInfo);
|
||||
m_x11ForwardingRequests.clear();
|
||||
};
|
||||
connect(x11InfoRetriever, &SshX11InfoRetriever::success, this, successHandler);
|
||||
qCDebug(sshLog) << "starting x11 info retriever";
|
||||
x11InfoRetriever->start();
|
||||
});
|
||||
return proc;
|
||||
}
|
||||
|
||||
QSsh::SshRemoteProcess::Ptr SshChannelManager::createRemoteShell()
|
||||
{
|
||||
SshRemoteProcess::Ptr proc(new SshRemoteProcess(m_nextLocalChannelId++, m_sendFacility));
|
||||
insertChannel(proc->d, proc);
|
||||
return proc;
|
||||
}
|
||||
|
||||
QSsh::SftpChannel::Ptr SshChannelManager::createSftpChannel()
|
||||
{
|
||||
SftpChannel::Ptr sftp(new SftpChannel(m_nextLocalChannelId++, m_sendFacility));
|
||||
insertChannel(sftp->d, sftp);
|
||||
return sftp;
|
||||
}
|
||||
|
||||
SshDirectTcpIpTunnel::Ptr SshChannelManager::createDirectTunnel(const QString &originatingHost,
|
||||
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
|
||||
{
|
||||
SshDirectTcpIpTunnel::Ptr tunnel(new SshDirectTcpIpTunnel(m_nextLocalChannelId++,
|
||||
originatingHost, originatingPort, remoteHost, remotePort, m_sendFacility));
|
||||
insertChannel(tunnel->d, tunnel);
|
||||
return tunnel;
|
||||
}
|
||||
|
||||
SshTcpIpForwardServer::Ptr SshChannelManager::createForwardServer(const QString &remoteHost,
|
||||
quint16 remotePort)
|
||||
{
|
||||
SshTcpIpForwardServer::Ptr server(new SshTcpIpForwardServer(remoteHost, remotePort,
|
||||
m_sendFacility));
|
||||
connect(server.data(), &SshTcpIpForwardServer::stateChanged,
|
||||
this, [this, server](SshTcpIpForwardServer::State state) {
|
||||
switch (state) {
|
||||
case SshTcpIpForwardServer::Closing:
|
||||
m_listeningForwardServers.removeOne(server);
|
||||
Q_FALLTHROUGH();
|
||||
case SshTcpIpForwardServer::Initializing:
|
||||
m_waitingForwardServers.append(server);
|
||||
break;
|
||||
case SshTcpIpForwardServer::Listening:
|
||||
case SshTcpIpForwardServer::Inactive:
|
||||
break;
|
||||
}
|
||||
});
|
||||
return server;
|
||||
}
|
||||
|
||||
void SshChannelManager::insertChannel(AbstractSshChannel *priv,
|
||||
const QSharedPointer<QObject> &pub)
|
||||
{
|
||||
connect(priv, &AbstractSshChannel::timeout, this, &SshChannelManager::timeout);
|
||||
m_channels.insert(priv->localChannelId(), priv);
|
||||
m_sessions.insert(priv, pub);
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelOpenForwardedTcpIp(
|
||||
const SshChannelOpenGeneric &channelOpenGeneric)
|
||||
{
|
||||
const SshChannelOpenForwardedTcpIp channelOpen
|
||||
= SshIncomingPacket::extractChannelOpenForwardedTcpIp(channelOpenGeneric);
|
||||
|
||||
SshTcpIpForwardServer::Ptr server;
|
||||
|
||||
foreach (const SshTcpIpForwardServer::Ptr &candidate, m_listeningForwardServers) {
|
||||
if (candidate->port() == channelOpen.remotePort
|
||||
&& candidate->bindAddress().toUtf8() == channelOpen.remoteAddress) {
|
||||
server = candidate;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (server.isNull()) {
|
||||
// Apparently the server knows a remoteAddress we are not aware of. There are plenty of ways
|
||||
// to make that happen: /etc/hosts on the server, different writings for localhost,
|
||||
// different DNS servers, ...
|
||||
// Rather than trying to figure that out, we just use the first listening forwarder with the
|
||||
// same port.
|
||||
foreach (const SshTcpIpForwardServer::Ptr &candidate, m_listeningForwardServers) {
|
||||
if (candidate->port() == channelOpen.remotePort) {
|
||||
server = candidate;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (server.isNull()) {
|
||||
try {
|
||||
m_sendFacility.sendChannelOpenFailurePacket(channelOpen.common.remoteChannel,
|
||||
SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
|
||||
QByteArray());
|
||||
} catch (const std::exception &e) {
|
||||
qCWarning(sshLog, "Botan error: %s", e.what());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SshForwardedTcpIpTunnel::Ptr tunnel(new SshForwardedTcpIpTunnel(m_nextLocalChannelId++,
|
||||
m_sendFacility));
|
||||
tunnel->d->handleOpenSuccess(channelOpen.common.remoteChannel,
|
||||
channelOpen.common.remoteWindowSize,
|
||||
channelOpen.common.remoteMaxPacketSize);
|
||||
tunnel->open(QIODevice::ReadWrite);
|
||||
server->setNewConnection(tunnel);
|
||||
insertChannel(tunnel->d, tunnel);
|
||||
}
|
||||
|
||||
void SshChannelManager::handleChannelOpenX11(const SshChannelOpenGeneric &channelOpenGeneric)
|
||||
{
|
||||
qCDebug(sshLog) << "incoming X11 channel open request";
|
||||
const SshChannelOpenX11 channelOpen
|
||||
= SshIncomingPacket::extractChannelOpenX11(channelOpenGeneric);
|
||||
if (m_x11DisplayInfo.cookie.isEmpty()) {
|
||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||
"Server attempted to open an unrequested X11 channel.");
|
||||
}
|
||||
SshX11Channel * const x11Channel = new SshX11Channel(m_x11DisplayInfo,
|
||||
m_nextLocalChannelId++,
|
||||
m_sendFacility);
|
||||
x11Channel->setParent(this);
|
||||
x11Channel->handleOpenSuccess(channelOpen.common.remoteChannel,
|
||||
channelOpen.common.remoteWindowSize,
|
||||
channelOpen.common.remoteMaxPacketSize);
|
||||
insertChannel(x11Channel, QSharedPointer<QObject>());
|
||||
}
|
||||
|
||||
int SshChannelManager::closeAllChannels(CloseAllMode mode)
|
||||
{
|
||||
int count = 0;
|
||||
for (ChannelIterator it = m_channels.begin(); it != m_channels.end(); ++it) {
|
||||
AbstractSshChannel * const channel = it.value();
|
||||
QSSH_ASSERT(channel->channelState() != AbstractSshChannel::Closed);
|
||||
if (channel->channelState() != AbstractSshChannel::CloseRequested) {
|
||||
channel->closeChannel();
|
||||
++count;
|
||||
}
|
||||
}
|
||||
if (mode == CloseAllAndReset) {
|
||||
m_channels.clear();
|
||||
m_sessions.clear();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int SshChannelManager::channelCount() const
|
||||
{
|
||||
return m_channels.count();
|
||||
}
|
||||
|
||||
void SshChannelManager::removeChannel(ChannelIterator it)
|
||||
{
|
||||
if (it == m_channels.end()) {
|
||||
throw SshClientException(SshInternalError,
|
||||
QLatin1String("Internal error: Unexpected channel lookup failure"));
|
||||
}
|
||||
const int removeCount = m_sessions.remove(it.value());
|
||||
if (removeCount != 1) {
|
||||
throw SshClientException(SshInternalError,
|
||||
QString::fromLatin1("Internal error: Unexpected session count %1 for channel.")
|
||||
.arg(removeCount));
|
||||
}
|
||||
m_channels.erase(it);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
@@ -1,117 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SSHCHANNELLAYER_P_H
|
||||
#define SSHCHANNELLAYER_P_H
|
||||
|
||||
#include "sshx11displayinfo_p.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
namespace QSsh {
|
||||
class SftpChannel;
|
||||
class SshDirectTcpIpTunnel;
|
||||
class SshRemoteProcess;
|
||||
class SshTcpIpForwardServer;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class AbstractSshChannel;
|
||||
struct SshChannelOpenGeneric;
|
||||
class SshIncomingPacket;
|
||||
class SshSendFacility;
|
||||
class SshRemoteProcessPrivate;
|
||||
|
||||
class SshChannelManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SshChannelManager(SshSendFacility &sendFacility, QObject *parent);
|
||||
|
||||
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
|
||||
QSharedPointer<SshRemoteProcess> createRemoteShell();
|
||||
QSharedPointer<SftpChannel> createSftpChannel();
|
||||
QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
|
||||
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
|
||||
QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
|
||||
quint16 remotePort);
|
||||
|
||||
int channelCount() const;
|
||||
enum CloseAllMode { CloseAllRegular, CloseAllAndReset };
|
||||
int closeAllChannels(CloseAllMode mode);
|
||||
QString x11DisplayName() const { return m_x11DisplayInfo.displayName; }
|
||||
|
||||
void handleChannelRequest(const SshIncomingPacket &packet);
|
||||
void handleChannelOpen(const SshIncomingPacket &packet);
|
||||
void handleChannelOpenFailure(const SshIncomingPacket &packet);
|
||||
void handleChannelOpenConfirmation(const SshIncomingPacket &packet);
|
||||
void handleChannelSuccess(const SshIncomingPacket &packet);
|
||||
void handleChannelFailure(const SshIncomingPacket &packet);
|
||||
void handleChannelWindowAdjust(const SshIncomingPacket &packet);
|
||||
void handleChannelData(const SshIncomingPacket &packet);
|
||||
void handleChannelExtendedData(const SshIncomingPacket &packet);
|
||||
void handleChannelEof(const SshIncomingPacket &packet);
|
||||
void handleChannelClose(const SshIncomingPacket &packet);
|
||||
void handleRequestSuccess(const SshIncomingPacket &packet);
|
||||
void handleRequestFailure(const SshIncomingPacket &packet);
|
||||
|
||||
signals:
|
||||
void timeout();
|
||||
|
||||
private:
|
||||
typedef QHash<quint32, AbstractSshChannel *>::Iterator ChannelIterator;
|
||||
|
||||
ChannelIterator lookupChannelAsIterator(quint32 channelId,
|
||||
bool allowNotFound = false);
|
||||
AbstractSshChannel *lookupChannel(quint32 channelId,
|
||||
bool allowNotFound = false);
|
||||
void removeChannel(ChannelIterator it);
|
||||
void insertChannel(AbstractSshChannel *priv,
|
||||
const QSharedPointer<QObject> &pub);
|
||||
|
||||
void handleChannelOpenForwardedTcpIp(const SshChannelOpenGeneric &channelOpenGeneric);
|
||||
void handleChannelOpenX11(const SshChannelOpenGeneric &channelOpenGeneric);
|
||||
|
||||
SshSendFacility &m_sendFacility;
|
||||
QHash<quint32, AbstractSshChannel *> m_channels;
|
||||
QHash<AbstractSshChannel *, QSharedPointer<QObject> > m_sessions;
|
||||
quint32 m_nextLocalChannelId;
|
||||
QList<QSharedPointer<SshTcpIpForwardServer>> m_waitingForwardServers;
|
||||
QList<QSharedPointer<SshTcpIpForwardServer>> m_listeningForwardServers;
|
||||
QList<SshRemoteProcessPrivate *> m_x11ForwardingRequests;
|
||||
X11DisplayInfo m_x11DisplayInfo;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // SSHCHANNELLAYER_P_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,298 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SSHCONNECTION_H
|
||||
#define SSHCONNECTION_H
|
||||
|
||||
#include "ssherrors.h"
|
||||
#include "sshhostkeydatabase.h"
|
||||
|
||||
#include "ssh_global.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QFlags>
|
||||
#include <QMetaType>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QHostAddress>
|
||||
#include <QUrl>
|
||||
|
||||
namespace QSsh {
|
||||
class SftpChannel;
|
||||
class SshDirectTcpIpTunnel;
|
||||
class SshRemoteProcess;
|
||||
class SshTcpIpForwardServer;
|
||||
|
||||
namespace Internal {
|
||||
class SshConnectionPrivate;
|
||||
} // namespace Internal
|
||||
|
||||
/*!
|
||||
* \brief Flags that control various general behavior
|
||||
*/
|
||||
enum SshConnectionOption {
|
||||
/// Set this to ignore the system defined proxy
|
||||
SshIgnoreDefaultProxy = 0x1,
|
||||
|
||||
/// Fail instead of warn if the remote host violates the standard
|
||||
SshEnableStrictConformanceChecks = 0x2,
|
||||
|
||||
/// Set the QAbstractSocket::LowDelayOption, which is the same as TCP_NODELAY
|
||||
SshLowDelaySocket = 0x4
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(SshConnectionOptions, SshConnectionOption)
|
||||
|
||||
/*!
|
||||
* \brief How strict to be when checking the remote key
|
||||
*/
|
||||
enum SshHostKeyCheckingMode {
|
||||
/// Ignore the remote key
|
||||
SshHostKeyCheckingNone,
|
||||
|
||||
/// Fail connection if either there is no key stored for this host or the key is not the same as earlier
|
||||
SshHostKeyCheckingStrict,
|
||||
|
||||
/// Allow connecting if there is no stored key for the host, but fail if the key has changed
|
||||
SshHostKeyCheckingAllowNoMatch,
|
||||
|
||||
/// Continue connection if the key doesn't match the stored key for the host
|
||||
SshHostKeyCheckingAllowMismatch
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Class to use to specify parameters used during connection.
|
||||
*/
|
||||
class QSSH_EXPORT SshConnectionParameters
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* \brief What kinds of authentication to attempt
|
||||
*/
|
||||
enum AuthenticationType {
|
||||
AuthenticationTypePassword, ///< Only attempt to connect using the password set with setPassword().
|
||||
AuthenticationTypePublicKey, ///< Only attempt to authenticate with public key
|
||||
|
||||
/// Only attempt keyboard interactive authentication.
|
||||
/// For now this only changes what to send to the server,
|
||||
/// we will still just try to use the password set here.
|
||||
AuthenticationTypeKeyboardInteractive,
|
||||
|
||||
/// Any method using the password set with setPassword().
|
||||
/// Some servers disable \a "password", others disable \a "keyboard-interactive"
|
||||
AuthenticationTypeTryAllPasswordBasedMethods,
|
||||
|
||||
/// ssh-agent authentication only
|
||||
AuthenticationTypeAgent,
|
||||
};
|
||||
|
||||
SshConnectionParameters();
|
||||
|
||||
/*!
|
||||
* \brief Returns the hostname or IP set with setHost()
|
||||
*/
|
||||
QString host() const { return url.host(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns the port set with setPort()
|
||||
*/
|
||||
int port() const { return url.port(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns the username set with setUsername()
|
||||
* \return
|
||||
*/
|
||||
QString userName() const { return url.userName(); }
|
||||
|
||||
/*!
|
||||
* \brief Returns the password set with setPassword()
|
||||
*/
|
||||
QString password() const { return url.password(); }
|
||||
|
||||
/*!
|
||||
* \brief Sets the hostname or IP to connect to
|
||||
* \param host The remote host
|
||||
*/
|
||||
void setHost(const QString &host) { url.setHost(host); }
|
||||
|
||||
/*!
|
||||
* \brief Sets the remote port to use
|
||||
* \param port
|
||||
*/
|
||||
void setPort(int port) { url.setPort(port); }
|
||||
|
||||
/*!
|
||||
* \brief Sets the username to use
|
||||
* \param name Username
|
||||
*/
|
||||
void setUserName(const QString &name) { url.setUserName(name); }
|
||||
|
||||
/*!
|
||||
* \brief Sets the password to attempt to use
|
||||
* \param password
|
||||
*/
|
||||
void setPassword(const QString &password) { url.setPassword(password); }
|
||||
|
||||
QUrl url;
|
||||
QString privateKeyFile;
|
||||
int timeout; // In seconds.
|
||||
AuthenticationType authenticationType;
|
||||
SshConnectionOptions options;
|
||||
SshHostKeyCheckingMode hostKeyCheckingMode;
|
||||
SshHostKeyDatabasePtr hostKeyDatabase;
|
||||
};
|
||||
|
||||
/// @cond
|
||||
QSSH_EXPORT bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2);
|
||||
QSSH_EXPORT bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2);
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
* \brief Network connection info.
|
||||
*/
|
||||
class QSSH_EXPORT SshConnectionInfo
|
||||
{
|
||||
public:
|
||||
SshConnectionInfo() : localPort(0), peerPort(0) {}
|
||||
SshConnectionInfo(const QHostAddress &la, quint16 lp, const QHostAddress &pa, quint16 pp)
|
||||
: localAddress(la), localPort(lp), peerAddress(pa), peerPort(pp) {}
|
||||
|
||||
QHostAddress localAddress;
|
||||
quint16 localPort;
|
||||
QHostAddress peerAddress;
|
||||
quint16 peerPort;
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
\class QSsh::SshConnection
|
||||
|
||||
\brief This class provides an SSH connection, implementing protocol version 2.0
|
||||
|
||||
See acquireConnection() which provides a pool mechanism for re-use.
|
||||
|
||||
It can spawn channels for remote execution and SFTP operations (version 3).
|
||||
It operates asynchronously (non-blocking) and is not thread-safe.
|
||||
*/
|
||||
|
||||
class QSSH_EXPORT SshConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief The current state of a connection
|
||||
*/
|
||||
enum State { Unconnected, Connecting, Connected };
|
||||
|
||||
/*!
|
||||
* \param serverInfo serverInfo connection parameters
|
||||
* \param parent Parent object.
|
||||
*/
|
||||
explicit SshConnection(const SshConnectionParameters &serverInfo, QObject *parent = nullptr);
|
||||
|
||||
void connectToHost();
|
||||
void disconnectFromHost();
|
||||
|
||||
/*!
|
||||
* \brief Current state of this connection
|
||||
*/
|
||||
State state() const;
|
||||
|
||||
/*!
|
||||
* \brief Returns the error state of the connection
|
||||
* \returns If there is no error, returns \ref SshNoError if the connection is OK
|
||||
*/
|
||||
SshError errorState() const;
|
||||
QString errorString() const;
|
||||
SshConnectionParameters connectionParameters() const;
|
||||
SshConnectionInfo connectionInfo() const;
|
||||
~SshConnection();
|
||||
|
||||
/*!
|
||||
* \brief Use this to launch remote commands
|
||||
* \param command The command to execute
|
||||
*/
|
||||
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
|
||||
|
||||
/*!
|
||||
* \brief Creates a remote interactive session with a shell
|
||||
*/
|
||||
QSharedPointer<SshRemoteProcess> createRemoteShell();
|
||||
QSharedPointer<SftpChannel> createSftpChannel();
|
||||
QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
|
||||
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
|
||||
QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
|
||||
quint16 remotePort);
|
||||
|
||||
// -1 if an error occurred, number of channels closed otherwise.
|
||||
int closeAllChannels();
|
||||
int channelCount() const;
|
||||
const QByteArray &hostKeyFingerprint() const;
|
||||
|
||||
/*!
|
||||
* \brief The X11 display name used for X11 forwarding
|
||||
* \return The name of the X11 display set for this connection
|
||||
*/
|
||||
QString x11DisplayName() const;
|
||||
|
||||
signals:
|
||||
/*!
|
||||
* \brief Emitted when ready for use
|
||||
*/
|
||||
void connected();
|
||||
|
||||
/*!
|
||||
* \brief Emitted when the connection has been closed
|
||||
*/
|
||||
void disconnected();
|
||||
|
||||
/*!
|
||||
* \brief Emitted when data has been received
|
||||
* \param message The content of the data, same as the output you would get when running \a ssh on the command line
|
||||
*/
|
||||
void dataAvailable(const QString &message);
|
||||
|
||||
/*!
|
||||
* \brief Emitted when an error occured
|
||||
*/
|
||||
void error(QSsh::SshError);
|
||||
|
||||
private:
|
||||
Internal::SshConnectionPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace QSsh
|
||||
|
||||
Q_DECLARE_METATYPE(QSsh::SshConnectionParameters::AuthenticationType)
|
||||
|
||||
#endif // SSHCONNECTION_H
|
||||
@@ -1,204 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SSHCONNECTION_P_H
|
||||
#define SSHCONNECTION_P_H
|
||||
|
||||
#include "sshconnection.h"
|
||||
#include "sshexception_p.h"
|
||||
#include "sshincomingpacket_p.h"
|
||||
#include "sshsendfacility_p.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QQueue>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QScopedPointer>
|
||||
#include <QTimer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QTcpSocket;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QSsh {
|
||||
class SftpChannel;
|
||||
class SshRemoteProcess;
|
||||
class SshDirectTcpIpTunnel;
|
||||
class SshTcpIpForwardServer;
|
||||
|
||||
namespace Internal {
|
||||
class SshChannelManager;
|
||||
|
||||
// NOTE: When you add stuff here, don't forget to update m_packetHandlers.
|
||||
enum SshStateInternal {
|
||||
SocketUnconnected, // initial and after disconnect
|
||||
SocketConnecting, // After connectToHost()
|
||||
SocketConnected, // After socket's connected() signal
|
||||
UserAuthServiceRequested,
|
||||
WaitingForAgentKeys,
|
||||
UserAuthRequested,
|
||||
ConnectionEstablished // After service has been started
|
||||
// ...
|
||||
};
|
||||
|
||||
enum SshKeyExchangeState {
|
||||
NoKeyExchange,
|
||||
KexInitSent,
|
||||
DhInitSent,
|
||||
NewKeysSent,
|
||||
KeyExchangeSuccess // After server's DH_REPLY message
|
||||
};
|
||||
|
||||
class SshConnectionPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class QSsh::SshConnection;
|
||||
public:
|
||||
SshConnectionPrivate(SshConnection *conn,
|
||||
const SshConnectionParameters &serverInfo);
|
||||
~SshConnectionPrivate();
|
||||
|
||||
void connectToHost();
|
||||
void closeConnection(SshErrorCode sshError, SshError userError,
|
||||
const QByteArray &serverErrorString, const QString &userErrorString);
|
||||
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
|
||||
QSharedPointer<SshRemoteProcess> createRemoteShell();
|
||||
QSharedPointer<SftpChannel> createSftpChannel();
|
||||
QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
|
||||
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
|
||||
QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
|
||||
quint16 remotePort);
|
||||
|
||||
SshStateInternal state() const { return m_state; }
|
||||
SshError errorState() const { return m_error; }
|
||||
QString errorString() const { return m_errorString; }
|
||||
const QByteArray &hostKeyFingerprint() const { return m_hostFingerprint; }
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
void disconnected();
|
||||
void dataAvailable(const QString &message);
|
||||
void error(QSsh::SshError);
|
||||
|
||||
private:
|
||||
void handleSocketConnected();
|
||||
void handleIncomingData();
|
||||
void handleSocketError();
|
||||
void handleSocketDisconnected();
|
||||
void handleTimeout();
|
||||
void sendKeepAlivePacket();
|
||||
|
||||
void handleAgentKeysUpdated();
|
||||
void handleSignatureFromAgent(const QByteArray &key, const QByteArray &signature, uint token);
|
||||
void tryAllAgentKeys();
|
||||
void authenticateWithPublicKey();
|
||||
void setAgentError();
|
||||
|
||||
void handleServerId();
|
||||
void handlePackets();
|
||||
void handleCurrentPacket();
|
||||
void handleKeyExchangeInitPacket();
|
||||
void handleKeyExchangeReplyPacket();
|
||||
void handleNewKeysPacket();
|
||||
void handleServiceAcceptPacket();
|
||||
void handlePasswordExpiredPacket();
|
||||
void handleUserAuthInfoRequestPacket();
|
||||
void handleUserAuthSuccessPacket();
|
||||
void handleUserAuthFailurePacket();
|
||||
void handleUserAuthKeyOkPacket();
|
||||
void handleUserAuthBannerPacket();
|
||||
void handleUnexpectedPacket();
|
||||
void handleGlobalRequest();
|
||||
void handleDebugPacket();
|
||||
void handleUnimplementedPacket();
|
||||
void handleChannelRequest();
|
||||
void handleChannelOpen();
|
||||
void handleChannelOpenFailure();
|
||||
void handleChannelOpenConfirmation();
|
||||
void handleChannelSuccess();
|
||||
void handleChannelFailure();
|
||||
void handleChannelWindowAdjust();
|
||||
void handleChannelData();
|
||||
void handleChannelExtendedData();
|
||||
void handleChannelEof();
|
||||
void handleChannelClose();
|
||||
void handleDisconnect();
|
||||
void handleRequestSuccess();
|
||||
void handleRequestFailure();
|
||||
|
||||
bool canUseSocket() const;
|
||||
void createPrivateKey();
|
||||
|
||||
void sendData(const QByteArray &data);
|
||||
|
||||
uint tokenForAgent() const;
|
||||
|
||||
typedef void (SshConnectionPrivate::*PacketHandler)();
|
||||
typedef QList<SshStateInternal> StateList;
|
||||
void setupPacketHandlers();
|
||||
void setupPacketHandler(SshPacketType type, const StateList &states,
|
||||
PacketHandler handler);
|
||||
|
||||
typedef QPair<StateList, PacketHandler> HandlerInStates;
|
||||
QHash<SshPacketType, HandlerInStates> m_packetHandlers;
|
||||
|
||||
static const quint64 InvalidSeqNr;
|
||||
|
||||
QTcpSocket *m_socket;
|
||||
SshStateInternal m_state;
|
||||
SshKeyExchangeState m_keyExchangeState;
|
||||
SshIncomingPacket m_incomingPacket;
|
||||
SshSendFacility m_sendFacility;
|
||||
SshChannelManager * const m_channelManager;
|
||||
const SshConnectionParameters m_connParams;
|
||||
QByteArray m_incomingData;
|
||||
SshError m_error;
|
||||
QString m_errorString;
|
||||
QScopedPointer<SshKeyExchange> m_keyExchange;
|
||||
QByteArray m_hostFingerprint;
|
||||
QTimer m_timeoutTimer;
|
||||
QTimer m_keepAliveTimer;
|
||||
bool m_ignoreNextPacket;
|
||||
SshConnection *m_conn;
|
||||
quint64 m_lastInvalidMsgSeqNr;
|
||||
QByteArray m_serverId;
|
||||
QByteArray m_agentSignature;
|
||||
QQueue<QByteArray> m_pendingKeyChecks;
|
||||
QByteArray m_agentKeyToUse;
|
||||
bool m_serverHasSentDataBeforeId;
|
||||
bool m_triedAllPasswordBasedMethods;
|
||||
bool m_agentKeysUpToDate;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QSsh
|
||||
|
||||
#endif // SSHCONNECTION_P_H
|
||||
@@ -1,276 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "sshconnectionmanager.h"
|
||||
|
||||
#include "sshconnection.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
namespace QSsh {
|
||||
namespace Internal {
|
||||
class UnaquiredConnection {
|
||||
public:
|
||||
UnaquiredConnection(SshConnection *conn) : connection(conn), scheduledForRemoval(false) {}
|
||||
|
||||
SshConnection *connection;
|
||||
bool scheduledForRemoval;
|
||||
};
|
||||
bool operator==(UnaquiredConnection c1, UnaquiredConnection c2) {
|
||||
return c1.connection == c2.connection;
|
||||
}
|
||||
bool operator!=(UnaquiredConnection c1, UnaquiredConnection c2) {
|
||||
return !(c1 == c2);
|
||||
}
|
||||
|
||||
class SshConnectionManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SshConnectionManager()
|
||||
{
|
||||
moveToThread(QCoreApplication::instance()->thread());
|
||||
connect(&m_removalTimer, &QTimer::timeout,
|
||||
this, &SshConnectionManager::removeInactiveConnections);
|
||||
m_removalTimer.setTimerType(Qt::VeryCoarseTimer);
|
||||
m_removalTimer.start(150000); // For a total timeout of five minutes.
|
||||
}
|
||||
|
||||
~SshConnectionManager()
|
||||
{
|
||||
foreach (const UnaquiredConnection &connection, m_unacquiredConnections) {
|
||||
disconnect(connection.connection, nullptr, this, nullptr);
|
||||
delete connection.connection;
|
||||
}
|
||||
|
||||
QSSH_ASSERT(m_acquiredConnections.isEmpty());
|
||||
QSSH_ASSERT(m_deprecatedConnections.isEmpty());
|
||||
}
|
||||
|
||||
SshConnection *acquireConnection(const SshConnectionParameters &sshParams)
|
||||
{
|
||||
QMutexLocker locker(&m_listMutex);
|
||||
|
||||
// Check in-use connections:
|
||||
foreach (SshConnection * const connection, m_acquiredConnections) {
|
||||
if (connection->connectionParameters() != sshParams)
|
||||
continue;
|
||||
|
||||
if (connection->thread() != QThread::currentThread())
|
||||
continue;
|
||||
|
||||
if (m_deprecatedConnections.contains(connection)) // we were asked to no longer use this one...
|
||||
continue;
|
||||
|
||||
m_acquiredConnections.append(connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
// Check cached open connections:
|
||||
foreach (const UnaquiredConnection &c, m_unacquiredConnections) {
|
||||
SshConnection * const connection = c.connection;
|
||||
if (connection->state() != SshConnection::Connected
|
||||
|| connection->connectionParameters() != sshParams)
|
||||
continue;
|
||||
|
||||
if (connection->thread() != QThread::currentThread()) {
|
||||
if (connection->channelCount() != 0)
|
||||
continue;
|
||||
QMetaObject::invokeMethod(this, "switchToCallerThread",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_ARG(SshConnection *, connection),
|
||||
Q_ARG(QObject *, QThread::currentThread()));
|
||||
}
|
||||
|
||||
m_unacquiredConnections.removeOne(c);
|
||||
m_acquiredConnections.append(connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
// create a new connection:
|
||||
SshConnection * const connection = new SshConnection(sshParams);
|
||||
connect(connection, &SshConnection::disconnected,
|
||||
this, &SshConnectionManager::cleanup);
|
||||
m_acquiredConnections.append(connection);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
void releaseConnection(SshConnection *connection)
|
||||
{
|
||||
QMutexLocker locker(&m_listMutex);
|
||||
|
||||
const bool wasAquired = m_acquiredConnections.removeOne(connection);
|
||||
QSSH_ASSERT_AND_RETURN(wasAquired);
|
||||
if (m_acquiredConnections.contains(connection))
|
||||
return;
|
||||
|
||||
bool doDelete = false;
|
||||
connection->moveToThread(QCoreApplication::instance()->thread());
|
||||
if (m_deprecatedConnections.removeOne(connection)
|
||||
|| connection->state() != SshConnection::Connected) {
|
||||
doDelete = true;
|
||||
} else {
|
||||
QSSH_ASSERT_AND_RETURN(!m_unacquiredConnections.contains(UnaquiredConnection(connection)));
|
||||
|
||||
// It can happen that two or more connections with the same parameters were acquired
|
||||
// if the clients were running in different threads. Only keep one of them in
|
||||
// such a case.
|
||||
bool haveConnection = false;
|
||||
foreach (const UnaquiredConnection &c, m_unacquiredConnections) {
|
||||
if (c.connection->connectionParameters() == connection->connectionParameters()) {
|
||||
haveConnection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!haveConnection) {
|
||||
connection->closeAllChannels(); // Clean up after neglectful clients.
|
||||
m_unacquiredConnections.append(UnaquiredConnection(connection));
|
||||
} else {
|
||||
doDelete = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (doDelete) {
|
||||
disconnect(connection, nullptr, this, nullptr);
|
||||
m_deprecatedConnections.removeAll(connection);
|
||||
connection->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void forceNewConnection(const SshConnectionParameters &sshParams)
|
||||
{
|
||||
QMutexLocker locker(&m_listMutex);
|
||||
|
||||
for (int i = 0; i < m_unacquiredConnections.count(); ++i) {
|
||||
SshConnection * const connection = m_unacquiredConnections.at(i).connection;
|
||||
if (connection->connectionParameters() == sshParams) {
|
||||
disconnect(connection, nullptr, this, nullptr);
|
||||
delete connection;
|
||||
m_unacquiredConnections.removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (SshConnection * const connection, m_acquiredConnections) {
|
||||
if (connection->connectionParameters() == sshParams) {
|
||||
if (!m_deprecatedConnections.contains(connection))
|
||||
m_deprecatedConnections.append(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Q_INVOKABLE void switchToCallerThread(SshConnection *connection, QObject *threadObj)
|
||||
{
|
||||
connection->moveToThread(qobject_cast<QThread *>(threadObj));
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
QMutexLocker locker(&m_listMutex);
|
||||
|
||||
SshConnection *currentConnection = qobject_cast<SshConnection *>(sender());
|
||||
if (!currentConnection)
|
||||
return;
|
||||
|
||||
if (m_unacquiredConnections.removeOne(UnaquiredConnection(currentConnection))) {
|
||||
disconnect(currentConnection, nullptr, this, nullptr);
|
||||
currentConnection->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void removeInactiveConnections()
|
||||
{
|
||||
QMutexLocker locker(&m_listMutex);
|
||||
for (int i = m_unacquiredConnections.count() - 1; i >= 0; --i) {
|
||||
UnaquiredConnection &c = m_unacquiredConnections[i];
|
||||
if (c.scheduledForRemoval) {
|
||||
disconnect(c.connection, nullptr, this, nullptr);
|
||||
c.connection->deleteLater();
|
||||
m_unacquiredConnections.removeAt(i);
|
||||
} else {
|
||||
c.scheduledForRemoval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// We expect the number of concurrently open connections to be small.
|
||||
// If that turns out to not be the case, we can still use a data
|
||||
// structure with faster access.
|
||||
QList<UnaquiredConnection> m_unacquiredConnections;
|
||||
|
||||
// Can contain the same connection more than once; this acts as a reference count.
|
||||
QList<SshConnection *> m_acquiredConnections;
|
||||
|
||||
QList<SshConnection *> m_deprecatedConnections;
|
||||
QMutex m_listMutex;
|
||||
QTimer m_removalTimer;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
static QMutex instanceMutex;
|
||||
|
||||
static Internal::SshConnectionManager &instance()
|
||||
{
|
||||
static Internal::SshConnectionManager manager;
|
||||
return manager;
|
||||
}
|
||||
|
||||
SshConnection *acquireConnection(const SshConnectionParameters &sshParams)
|
||||
{
|
||||
QMutexLocker locker(&instanceMutex);
|
||||
return instance().acquireConnection(sshParams);
|
||||
}
|
||||
|
||||
void releaseConnection(SshConnection *connection)
|
||||
{
|
||||
QMutexLocker locker(&instanceMutex);
|
||||
instance().releaseConnection(connection);
|
||||
}
|
||||
|
||||
void forceNewConnection(const SshConnectionParameters &sshParams)
|
||||
{
|
||||
QMutexLocker locker(&instanceMutex);
|
||||
instance().forceNewConnection(sshParams);
|
||||
}
|
||||
|
||||
} // namespace QSsh
|
||||
|
||||
#include "sshconnectionmanager.moc"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user