Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b7b6e457b | ||
|
|
61c53e9d10 | ||
|
|
13fe460069 | ||
|
|
6b4e4b6822 | ||
|
|
8b9592c06e | ||
|
|
4a0301fe46 | ||
|
|
14820ad7a0 |
@@ -30,6 +30,10 @@
|
||||
{
|
||||
"title": "Bitwarden"
|
||||
},
|
||||
{
|
||||
"title": "Brave Creators",
|
||||
"slug": "brave_creators"
|
||||
},
|
||||
{
|
||||
"title": "Bybit"
|
||||
},
|
||||
@@ -57,6 +61,11 @@
|
||||
"title": "ente",
|
||||
"hex": "1DB954"
|
||||
},
|
||||
{
|
||||
"title": "Epic Games",
|
||||
"slug": "epic_games",
|
||||
"hex": "000000"
|
||||
},
|
||||
{
|
||||
"title": "Filen",
|
||||
"hex": "858585"
|
||||
@@ -69,6 +78,10 @@
|
||||
"title": "GitHub",
|
||||
"hex": "858585"
|
||||
},
|
||||
{
|
||||
"title": "GitLab",
|
||||
"slug": "gitlab"
|
||||
},
|
||||
{
|
||||
"title": "Google"
|
||||
},
|
||||
@@ -120,6 +133,9 @@
|
||||
{
|
||||
"title": "Mozilla"
|
||||
},
|
||||
{
|
||||
"title": "NextDNS"
|
||||
},
|
||||
{
|
||||
"title": "ngrok",
|
||||
"hex": "858585"
|
||||
@@ -183,6 +199,11 @@
|
||||
"title": "Revolt",
|
||||
"hex": "858585"
|
||||
},
|
||||
{
|
||||
"title": "Rust Language Forum",
|
||||
"slug": "rust_language_forum",
|
||||
"hex": "000000"
|
||||
},
|
||||
{
|
||||
"title": "service-bw"
|
||||
},
|
||||
@@ -192,6 +213,10 @@
|
||||
{
|
||||
"title": "Sipgate"
|
||||
},
|
||||
{
|
||||
"title": "Skiff",
|
||||
"hex": "EF5A3C"
|
||||
},
|
||||
{
|
||||
"title": "Snapchat"
|
||||
},
|
||||
@@ -200,6 +225,11 @@
|
||||
"slug": "standardnotes",
|
||||
"hex": "2173E6"
|
||||
},
|
||||
{
|
||||
"title": "TCPShield",
|
||||
"slug": "tcpshield",
|
||||
"hex": "FFFFFF"
|
||||
},
|
||||
{
|
||||
"title": "Techlore"
|
||||
},
|
||||
@@ -236,6 +266,11 @@
|
||||
"title": "Unity",
|
||||
"hex": "858585"
|
||||
},
|
||||
{
|
||||
"title": "Uphold",
|
||||
"slug": "uphold",
|
||||
"hex": "6FE68A"
|
||||
},
|
||||
{
|
||||
"title": "WHMCS"
|
||||
},
|
||||
@@ -250,13 +285,6 @@
|
||||
"title": "X",
|
||||
"altNames": ["twitter"],
|
||||
"slug": "x"
|
||||
},
|
||||
{
|
||||
"title": "NextDNS"
|
||||
},
|
||||
{
|
||||
"title": "Skiff",
|
||||
"hex": "EF5A3C"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
114
assets/custom-icons/icons/brave_creators.svg
Normal file
114
assets/custom-icons/icons/brave_creators.svg
Normal file
@@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
width="96"
|
||||
height="96"
|
||||
viewBox="0 0 96 96"
|
||||
xml:space="preserve"
|
||||
id="svg6"
|
||||
sodipodi:docname="brave.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview6"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="8.09375"
|
||||
inkscape:cx="48"
|
||||
inkscape:cy="48"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="991"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6" />
|
||||
<desc
|
||||
id="desc1">Created with Fabric.js 5.3.0</desc>
|
||||
<defs
|
||||
id="defs1">
|
||||
</defs>
|
||||
<g
|
||||
transform="translate(48.065,48.066)"
|
||||
id="r-F4iK9D9hoWKR6dRPdW9">
|
||||
<g
|
||||
id="g6">
|
||||
<g
|
||||
transform="translate(-0.065,-0.066)"
|
||||
id="Ii0aKVyTWvdbjVfK_ZaN0">
|
||||
<linearGradient
|
||||
id="SVGID_0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0.671"
|
||||
y1="64.319"
|
||||
x2="55.200001"
|
||||
y2="64.319">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:rgb(255,85,0);stop-opacity: 1"
|
||||
id="stop1" />
|
||||
<stop
|
||||
offset="41%"
|
||||
style="stop-color:rgb(255,85,0);stop-opacity: 1"
|
||||
id="stop2" />
|
||||
<stop
|
||||
offset="58.199999999999996%"
|
||||
style="stop-color:rgb(255,32,0);stop-opacity: 1"
|
||||
id="stop3" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:rgb(255,32,0);stop-opacity: 1"
|
||||
id="stop4" />
|
||||
</linearGradient>
|
||||
<path
|
||||
style="opacity:1;fill:url(#SVGID_0);fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-27.935,-31.934)"
|
||||
d="m 53.292,15.321 1.5,-3.676 c 0,0 -1.909,-2.043 -4.227,-4.358 C 48.248,4.972 43.34,6.334 43.34,6.334 L 37.751,0 H 18.12 l -5.589,6.334 c 0,0 -4.908,-1.362 -7.225,0.953 C 2.988,9.602 1.08,11.645 1.08,11.645 l 1.5,3.676 -1.91,5.447 c 0,0 5.614,21.236 6.272,23.83 1.295,5.106 2.181,7.08 5.862,9.668 3.68,2.587 10.36,7.08 11.45,7.762 1.091,0.68 2.455,1.84 3.682,1.84 1.227,0 2.59,-1.16 3.68,-1.84 1.091,-0.681 7.77,-5.175 11.452,-7.762 3.68,-2.587 4.567,-4.562 5.862,-9.668 0.657,-2.594 6.27,-23.83 6.27,-23.83 z"
|
||||
stroke-linecap="round"
|
||||
id="path4" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-0.064,-1.7095)"
|
||||
id="yFALuw9WCf5yfG8AbQIoW">
|
||||
<path
|
||||
style="opacity:1;fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-27.936,-30.2905)"
|
||||
d="m 34.888,11.508 c 0.818,0 6.885,-1.157 6.885,-1.157 0,0 7.189,8.68 7.189,10.536 0,1.534 -0.619,2.134 -1.347,2.842 -0.152,0.148 -0.31,0.3 -0.467,0.468 l -5.39,5.717 c -0.05786,0.06078 -0.116534,0.120787 -0.176,0.18 -0.538,0.54 -1.33,1.336 -0.772,2.658 l 0.115,0.269 c 0.613,1.432 1.37,3.2 0.407,4.99 -1.025,1.906 -2.78,3.178 -3.905,2.967 -1.124,-0.21 -3.766,-1.589 -4.737,-2.218 -0.971,-0.63 -4.05,-3.166 -4.05,-4.137 0,-0.809 2.214,-2.155 3.29,-2.81 0.214,-0.13 0.383,-0.232 0.48,-0.298 0.111,-0.075 0.297,-0.19 0.526,-0.332 0.981,-0.61 2.754,-1.71 2.799,-2.197 0.055,-0.602 0.034,-0.778 -0.758,-2.264 -0.168,-0.316 -0.365,-0.654 -0.568,-1.004 -0.754,-1.295 -1.598,-2.745 -1.41,-3.784 0.21,-1.173 2.05,-1.845 3.608,-2.415 0.194,-0.07 0.385,-0.14 0.567,-0.209 l 1.623,-0.609 c 1.556,-0.582 3.284,-1.229 3.57,-1.36 0.394,-0.181 0.292,-0.355 -0.903,-0.468 -0.193439,-0.01897 -0.386775,-0.03897 -0.58,-0.06 -1.48,-0.157 -4.209,-0.446 -5.535,-0.077 -0.261,0.073 -0.553,0.152 -0.86,0.235 -1.49,0.403 -3.317,0.897 -3.493,1.182 -0.03,0.05 -0.06,0.093 -0.089,0.133 -0.168,0.238 -0.277,0.394 -0.091,1.406 0.055,0.302 0.169,0.895 0.31,1.629 0.41,2.148 1.053,5.498 1.134,6.25 0.011,0.106 0.024,0.207 0.036,0.305 0.103,0.84 0.171,1.399 -0.805,1.622 l -0.255,0.058 c -1.102,0.252 -2.717,0.623 -3.3,0.623 -0.584,0 -2.2,-0.37 -3.302,-0.623 L 24.38,29.498 c -0.976,-0.223 -0.907,-0.782 -0.804,-1.622 0.012,-0.098 0.024,-0.2 0.035,-0.305 0.081,-0.753 0.725,-4.112 1.137,-6.259 0.14,-0.73 0.253,-1.32 0.308,-1.62 0.185,-1.012 0.076,-1.168 -0.092,-1.406 -0.03095,-0.04368 -0.06095,-0.08803 -0.09,-0.133 -0.174,-0.285 -2,-0.779 -3.491,-1.182 -0.307,-0.083 -0.6,-0.162 -0.86,-0.235 -1.327,-0.37 -4.055,-0.08 -5.535,0.077 -0.226,0.024 -0.422,0.045 -0.58,0.06 -1.196,0.113 -1.297,0.287 -0.903,0.468 0.285,0.131 2.013,0.778 3.568,1.36 0.597,0.223 1.17,0.437 1.624,0.609 0.183,0.069 0.373,0.138 0.568,0.21 1.558,0.57 3.398,1.241 3.608,2.414 0.187,1.039 -0.657,2.489 -1.41,3.784 -0.204,0.35 -0.4,0.688 -0.569,1.004 -0.791,1.486 -0.812,1.662 -0.757,2.264 0.044,0.488 1.816,1.587 2.798,2.197 0.229,0.142 0.415,0.257 0.526,0.332 0.098,0.066 0.266,0.168 0.48,0.298 1.076,0.654 3.29,2 3.29,2.81 0,0.97 -3.078,3.507 -4.05,4.137 -0.97,0.63 -3.612,2.008 -4.737,2.218 -1.124,0.21 -2.88,-1.061 -3.904,-2.966 -0.963,-1.791 -0.207,-3.559 0.406,-4.99 l 0.115,-0.27 C 15.62,31.43 14.828,30.634 14.289,30.094 14.22987,30.03478 14.171528,29.974778 14.114,29.914 L 8.724,24.197 C 8.566,24.03 8.408,23.877 8.256,23.729 7.528,23.022 6.91,22.421 6.91,20.887 c 0,-1.855 7.189,-10.536 7.189,-10.536 0,0 6.066,1.157 6.884,1.157 0.653,0 1.913,-0.433 3.227,-0.885 0.333,-0.114 0.669,-0.23 1,-0.34 1.635,-0.545 2.726,-0.549 2.726,-0.549 0,0 1.09,0.004 2.726,0.549 0.33,0.11 0.667,0.226 1,0.34 1.313,0.452 2.574,0.885 3.226,0.885 z m -1.041,30.706 c 1.282,0.66 2.192,1.128 2.536,1.343 0.445,0.278 0.174,0.803 -0.232,1.09 -0.405,0.285 -5.853,4.499 -6.381,4.965 l -0.215,0.191 c -0.509,0.459 -1.159,1.044 -1.62,1.044 -0.46,0 -1.11,-0.586 -1.62,-1.044 l -0.213,-0.191 c -0.53,-0.466 -5.977,-4.68 -6.382,-4.966 -0.405,-0.286 -0.677,-0.81 -0.232,-1.09 0.344,-0.214 1.255,-0.683 2.539,-1.344 l 1.22,-0.629 c 1.92,-0.992 4.315,-1.837 4.689,-1.837 0.373,0 2.767,0.844 4.689,1.837 0.436,0.226 0.845,0.437 1.222,0.63 z"
|
||||
stroke-linecap="round"
|
||||
id="path5" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-0.0645,-26.246)"
|
||||
id="0KuDkb-_5PZSfGEzYnH-2">
|
||||
<linearGradient
|
||||
id="SVGID_1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="6.2779999"
|
||||
y1="11.466"
|
||||
x2="50.564999"
|
||||
y2="11.466">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:rgb(255,69,42);stop-opacity: 1"
|
||||
id="stop5" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:rgb(255,32,0);stop-opacity: 1"
|
||||
id="stop6" />
|
||||
</linearGradient>
|
||||
<path
|
||||
style="opacity:1;fill:url(#SVGID_1);fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-27.9355,-5.754)"
|
||||
d="M 43.34,6.334 37.751,0 H 18.12 l -5.589,6.334 c 0,0 -4.908,-1.362 -7.225,0.953 0,0 6.544,-0.59 8.793,3.064 0,0 6.066,1.157 6.884,1.157 0.818,0 2.59,-0.68 4.226,-1.225 1.636,-0.545 2.727,-0.549 2.727,-0.549 0,0 1.09,0.004 2.726,0.549 1.636,0.545 3.408,1.225 4.226,1.225 0.818,0 6.885,-1.157 6.885,-1.157 C 44.022,6.697 50.565,7.287 50.565,7.287 48.248,4.972 43.34,6.334 43.34,6.334 Z"
|
||||
stroke-linecap="round"
|
||||
id="path6" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.1 KiB |
10
assets/custom-icons/icons/epic_games.svg
Normal file
10
assets/custom-icons/icons/epic_games.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.2 KiB |
84
assets/custom-icons/icons/gitlab.svg
Normal file
84
assets/custom-icons/icons/gitlab.svg
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
width="96"
|
||||
height="96"
|
||||
viewBox="0 0 96 96"
|
||||
xml:space="preserve"
|
||||
id="svg4"
|
||||
sodipodi:docname="gitlab.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview4"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="8.09375"
|
||||
inkscape:cx="48"
|
||||
inkscape:cy="48"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="991"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4" />
|
||||
<desc
|
||||
id="desc1">Created with Fabric.js 5.3.0</desc>
|
||||
<defs
|
||||
id="defs1">
|
||||
</defs>
|
||||
<g
|
||||
transform="matrix(2,0,0,2,47.999807,47.999999)"
|
||||
id="LlMVISacmLRypCAN8RaOa">
|
||||
<g
|
||||
id="g4">
|
||||
<g
|
||||
transform="translate(-0.00126224)"
|
||||
id="jXZGVBwYEboir0aGofEdX">
|
||||
<path
|
||||
style="opacity:1;fill:#e24329;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-15.998738,-15.999998)"
|
||||
d="M 31.4618,12.7787 31.417,12.6641 27.0667,1.31308 C 26.9783,1.09046 26.8218,0.90145 26.6197,0.773028 26.416,0.644476 26.1775,0.582308 25.937,0.595107 25.6965,0.607906 25.4659,0.695039 25.277,0.844481 25.0899,0.994513 24.955,1.1998 24.8915,1.43106 L 21.9503,10.4324 H 10.0509 L 7.10976,1.43106 C 7.04625,1.1998 6.91133,0.994513 6.72425,0.844481 6.53618,0.694035 6.30572,0.606246 6.06523,0.593431 5.82473,0.580616 5.58625,0.64342 5.38326,0.773028 5.18023,0.900924 5.02312,1.09005 4.9346,1.31308 L 0.579314,12.679 0.534448,12.792 c -0.6252016,1.637 -0.702052,3.4327 -0.218996,5.1171 0.483056,1.6844 1.499908,3.1665 2.897638,4.2233 l 0.01662,0.0116 0.03822,0.0299 6.63513,4.9668 3.28014,2.4843 1.9941,1.5104 c 0.2342,0.177 0.5198,0.2728 0.8134,0.2728 0.2935,0 0.5791,-0.0958 0.8134,-0.2728 l 1.994,-1.5104 3.2818,-2.4843 6.6734,-4.9967 0.0182,-0.0133 c 1.4025,-1.0558 2.4234,-2.5391 2.9087,-4.2262 0.4854,-1.687 0.4087,-3.4861 -0.2184,-5.1258 z"
|
||||
stroke-linecap="round"
|
||||
id="path1" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(8.0042462,3.9024)"
|
||||
id="_HnOE30YI3q64iu3Kyf5i">
|
||||
<path
|
||||
style="opacity:1;fill:#fc6d26;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-24.004246,-19.9024)"
|
||||
d="m 31.462,12.7787 -0.0448,-0.1146 c -2.1217,0.4372 -4.121,1.3364 -5.8558,2.6337 l -9.5531,7.24 c 3.2569,2.4627 6.0918,4.6029 6.0918,4.6029 l 6.6733,-4.9967 0.0183,-0.0133 c 1.399,-1.0584 2.4159,-2.543 2.8976,-4.2298 0.4817,-1.6869 0.4019,-3.4846 -0.2273,-5.1222 z"
|
||||
stroke-linecap="round"
|
||||
id="path2" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-0.00585,10.973)"
|
||||
id="AuQqbk918YYSmtG3qADkx">
|
||||
<path
|
||||
style="opacity:1;fill:#fca326;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-15.99415,-26.973)"
|
||||
d="m 9.9082,27.1407 3.2752,2.4843 1.994,1.5104 c 0.2343,0.177 0.5198,0.2728 0.8134,0.2728 0.2936,0 0.5792,-0.0958 0.8134,-0.2728 l 1.994,-1.5104 3.2819,-2.4843 c 0,0 -2.8349,-2.1402 -6.0918,-4.6029 z"
|
||||
stroke-linecap="round"
|
||||
id="path3" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-7.9959499,3.90655)"
|
||||
id="WbT8aWwyHoQxpOUXtkBeV">
|
||||
<path
|
||||
style="opacity:1;fill:#fc6d26;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-8.0040501,-19.90655)"
|
||||
d="M 6.43513,15.3045 C 4.70076,14.0067 2.70123,13.108 0.579333,12.6724 l -0.044866,0.113 c -0.6268073,1.6378 -0.704503,3.4349 -0.221388,5.1207 0.483115,1.6858 1.500881,3.169 2.900031,4.2263 l 0.01662,0.0116 0.03822,0.0299 6.63512,4.9668 6.10503,-4.6029 z"
|
||||
stroke-linecap="round"
|
||||
id="path4" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
64
assets/custom-icons/icons/rust_language_forum.svg
Normal file
64
assets/custom-icons/icons/rust_language_forum.svg
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
width="96"
|
||||
height="96"
|
||||
viewBox="0 0 96 96"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
sodipodi:docname="rust.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview2"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="8.09375"
|
||||
inkscape:cx="48"
|
||||
inkscape:cy="47.876448"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="991"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<desc
|
||||
id="desc1">Created with Fabric.js 5.3.0</desc>
|
||||
<defs
|
||||
id="defs1">
|
||||
</defs>
|
||||
<g
|
||||
transform="matrix(0.61244177,0,0,0.61244177,48.58182,48.643064)"
|
||||
id="d0KfchOoJLd1am88Nf2bl">
|
||||
<g
|
||||
id="g2">
|
||||
<g
|
||||
transform="translate(-0.95,-1.05)"
|
||||
id="CssRuECJ6utZ-6lKixFij">
|
||||
<path
|
||||
style="opacity:1;fill:#000000;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-71.05,-70.95)"
|
||||
d="M 71.05,23.68 C 44.99,23.68 23.78,44.9 23.78,70.95 23.78,97 45,118.22 71.05,118.22 97.1,118.22 118.32,97 118.32,70.95 118.32,44.9 97.1,23.68 71.05,23.68 Z m -0.07,4.2 c 1.680761,0.04353 3.02056,1.423255 3.02,3.11 0,1.717606 -1.392394,3.11 -3.11,3.11 -1.717606,0 -3.11,-1.392394 -3.11,-3.11 -3.52e-4,-0.840656 0.339633,-1.645648 0.942484,-2.231544 C 69.325335,28.172561 70.139696,27.855672 70.98,27.88 Z M 78.1,33 c 11.050222,2.069744 20.631432,8.893613 26.2,18.66 l -3.67,8.28 c -0.63,1.43 0.02,3.11 1.44,3.75 l 7.06,3.13 c 0.219,2.206835 0.24577,4.428529 0.08,6.64 h -3.93 c -0.39,0 -0.55,0.26 -0.55,0.64 v 1.8 c 0,4.24 -2.39,5.17 -4.49,5.4 -2,0.23 -4.21,-0.84 -4.49,-2.06 -1.18,-6.63 -3.14,-8.04 -6.24,-10.49 3.85,-2.44 7.85,-6.05 7.85,-10.87 0,-5.21 -3.57,-8.49 -6,-10.1 -3.42,-2.25 -7.2,-2.7 -8.22,-2.7 H 42.54 C 48.154011,38.808406 55.67907,34.5626 63.95,33 l 4.79,5.02 c 1.08,1.13 2.87,1.18 4,0.09 z M 33.9,56.02 c 1.682359,0.04871 3.020705,1.426936 3.02,3.11 0,1.717606 -1.392394,3.11 -3.11,3.11 -1.717606,0 -3.11,-1.392394 -3.11,-3.11 -3.52e-4,-0.840656 0.339633,-1.645648 0.942484,-2.231544 C 32.245335,56.312561 33.059696,55.995672 33.9,56.02 Z m 74.15,0.14 c 1.68236,0.04871 3.0207,1.426936 3.02,3.11 0,1.717606 -1.39239,3.11 -3.11,3.11 -1.71761,0 -3.11,-1.392394 -3.11,-3.11 -3.5e-4,-0.840656 0.33963,-1.645648 0.94248,-2.231544 0.60285,-0.585895 1.41722,-0.902784 2.25752,-0.878456 z m -68.29,0.5 h 5.42 V 81.1 H 34.24 C 32.88888,76.35544 32.46782,71.394402 33,66.49 l 6.7,-2.98 c 1.43,-0.64 2.08,-2.31 1.44,-3.74 z m 22.62,0.26 h 12.91 c 0.67,0 4.71,0.77 4.71,3.8 0,2.51 -3.1,3.41 -5.65,3.41 H 62.37 Z m 0,17.56 h 9.89 c 0.9,0 4.83,0.26 6.08,5.28 0.39,1.54 1.26,6.56 1.85,8.17 0.59,1.8 2.98,5.4 5.53,5.4 h 16.14 c -1.08168,1.448565 -2.26464,2.818663 -3.54,4.1 l -6.57,-1.41 c -1.53,-0.33 -3.04,0.65 -3.37,2.18 l -1.56,7.28 c -10.151161,4.59844 -21.802519,4.54367 -31.91,-0.15 L 53.36,98.05 C 53.03,96.52 51.53,95.54 50,95.87 l -6.43,1.38 c -1.193214,-1.230834 -2.302379,-2.54045 -3.32,-3.92 h 31.27 c 0.35,0 0.59,-0.06 0.59,-0.39 V 81.88 c 0,-0.32 -0.24,-0.39 -0.59,-0.39 H 62.37 Z M 47.95,99.81 c 1.682359,0.04871 3.020705,1.42694 3.02,3.11 0,1.71761 -1.392394,3.11 -3.11,3.11 -1.717606,0 -3.11,-1.39239 -3.11,-3.11 -3.52e-4,-0.84066 0.339633,-1.64565 0.942484,-2.23154 C 46.295335,100.10256 47.109696,99.785672 47.95,99.81 Z M 94,99.95 c 1.682359,0.04871 3.020705,1.42694 3.02,3.11 0,1.71761 -1.392394,3.11 -3.11,3.11 -1.717606,0 -3.11,-1.39239 -3.11,-3.11 -3.52e-4,-0.84066 0.339633,-1.64565 0.942484,-2.23154 C 92.345335,100.24256 93.159696,99.925672 94,99.95 Z"
|
||||
stroke-linecap="round"
|
||||
id="path1" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-0.95,-1.05)"
|
||||
id="Sz8Hb_caEIP6YkrZ7l00L">
|
||||
<path
|
||||
style="opacity:1;fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-71.05,-70.95)"
|
||||
d="m 115.68,70.95 c 0,11.836612 -4.70208,23.188427 -13.07182,31.55818 C 94.238427,110.87792 82.886612,115.58 71.05,115.58 c -24.648468,0 -44.63,-19.981532 -44.63,-44.63 0,-24.648468 19.981532,-44.63 44.63,-44.63 24.648468,0 44.63,19.981532 44.63,44.63 z m -0.84,-4.31 6.96,4.31 -6.96,4.31 5.98,5.59 -7.66,2.87 4.78,6.65 -8.09,1.32 3.4,7.46 -8.19,-0.29 1.88,7.98 -7.98,-1.88 0.29,8.19 -7.46,-3.4 -1.32,8.09 -6.65,-4.78 -2.87,7.66 -5.59,-5.98 -4.31,6.96 -4.31,-6.96 -5.59,5.98 -2.87,-7.66 -6.65,4.78 -1.32,-8.09 -7.46,3.4 0.29,-8.19 -7.98,1.88 1.88,-7.98 -8.19,0.29 3.4,-7.46 -8.09,-1.32 4.78,-6.65 -7.66,-2.87 5.98,-5.59 -6.96,-4.31 6.96,-4.31 -5.98,-5.59 7.66,-2.87 -4.78,-6.65 8.09,-1.32 -3.4,-7.46 8.19,0.29 -1.88,-7.98 7.98,1.88 -0.29,-8.19 7.46,3.4 1.32,-8.09 6.65,4.78 2.87,-7.66 5.59,5.98 4.31,-6.96 4.31,6.96 5.59,-5.98 2.87,7.66 6.65,-4.78 1.32,8.09 7.46,-3.4 -0.29,8.19 7.98,-1.88 -1.88,7.98 8.19,-0.29 -3.4,7.46 8.09,1.32 -4.78,6.65 7.66,2.87 z"
|
||||
stroke-linecap="round"
|
||||
id="path2" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
27
assets/custom-icons/icons/tcpshield.svg
Normal file
27
assets/custom-icons/icons/tcpshield.svg
Normal file
@@ -0,0 +1,27 @@
|
||||
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 686 802" width="686" height="802">
|
||||
<title>TCPShield</title>
|
||||
<style>
|
||||
.s0 { fill: #ffffff;stroke: #414042;stroke-miterlimit:10 }
|
||||
.s1 { fill: #ffffff }
|
||||
</style>
|
||||
<g id="Layer 1">
|
||||
<g id="Layer 2 1 ">
|
||||
</g>
|
||||
<g id="Layer 1 1 ">
|
||||
<g id="<Group>">
|
||||
<path id="<Path>" class="s0" d="m205.2 141.5c6.8-6.1 13.6-12 20.5-17.8 7.5-6.1 15-12.2 22.6-17.9 3.8-2.9 7.7-5.7 11.5-8.5 1.9-1.4 3.9-2.7 5.8-4.1 1.9-1.3 3.9-2.7 5.8-4 2-1.3 3.9-2.6 5.9-3.9 2-1.3 3.9-2.5 5.9-3.8 3.9-2.6 7.9-4.9 11.9-7.4 2-1.2 4-2.3 6-3.5l3-1.7 3-1.7q3-1.7 6-3.3c2-1.1 4-2.1 6.1-3.2 1-0.5 2-1.1 3-1.6q1.5-0.8 3-1.5c2-1 4-2 6.1-3 4.1-1.9 8.1-3.8 12.2-5.6 4.1-1.8 8.2-3.4 12.3-5.1 2-0.8 4.1-1.5 6.1-2.3 1-0.4 2-0.8 3.1-1.1 1-0.3 2.1-0.7 3.1-1 8.2-2.9 16.4-5.2 24.5-7.3 2-0.5 4.1-1 6.1-1.4 2-0.4 4.1-0.8 6.1-1.2 2-0.4 4-0.7 6.1-1.1 2-0.3 4-0.7 6-0.9 16-2.2 31.7-2.4 46.5-0.6 1.8 0.3 3.7 0.5 5.5 0.8 1.8 0.3 3.6 0.7 5.4 1 1.8 0.3 3.5 0.8 5.3 1.2 1.7 0.4 3.5 0.8 5.2 1.3q2.5 0.7 5.1 1.5c1.7 0.6 3.3 1.2 4.9 1.8q1.2 0.4 2.4 0.9c0.8 0.3 1.6 0.7 2.4 1 0.8 0.3 1.6 0.7 2.4 1 0.8 0.3 1.6 0.6 2.3 1 12.3 5.8 23.2 13 32.4 21.3 9.3 8.2 17.2 17.2 23.8 26.3 6.6 9.1 12.1 18.3 16.7 27 1.1 2.2 2.2 4.4 3.2 6.5 0.5 1.1 1.1 2.1 1.5 3.2 0.5 1.1 0.9 2.1 1.4 3.2 0.9 2.1 1.8 4.1 2.7 6.1 0.8 2 1.6 4 2.4 5.9 1.6 3.8 2.9 7.6 4.2 11 1.3 3.5 2.3 6.8 3.3 9.9 0.5 1.5 1 3 1.4 4.5 0.5 1.4 0.8 2.8 1.2 4.1 0.8 2.6 1.4 5 2 7.1 0.3 1 0.6 2.1 0.8 3.1 0.3 1 0.5 1.9 0.7 2.8 0.4 1.7 0.8 3.2 1.1 4.3 0 0.2 0.1 0.3 0.1 0.4l5.3 1.9 26.4-7.1c0 0-0.3-1.2-1-3.5-0.3-1.2-0.7-2.6-1.2-4.3-0.2-0.9-0.5-1.8-0.8-2.8-0.3-1-0.6-2-0.9-3.2-0.7-2.4-1.6-5-2.5-7.9-0.5-1.4-0.9-3-1.5-4.5-0.5-1.5-1.1-3.1-1.7-4.8-1.2-3.3-2.4-6.9-3.9-10.7-1.5-3.8-3-7.8-4.9-12-0.9-2.1-1.8-4.3-2.8-6.5-1-2.2-2.1-4.4-3.2-6.7-0.5-1.1-1.1-2.3-1.7-3.5-0.6-1.2-1.2-2.3-1.8-3.5-1.2-2.4-2.5-4.8-3.8-7.2-5.5-9.7-11.9-20-19.8-30.3-7.9-10.3-17.4-20.7-28.8-30.2-11.3-9.6-24.7-18-39.7-24.6-0.9-0.4-1.9-0.8-2.8-1.2-1-0.4-1.9-0.8-2.9-1.1-1-0.4-1.9-0.8-2.9-1.1-1-0.4-2-0.7-3-1-2-0.6-4-1.3-6-1.9-2-0.6-4.1-1.1-6.1-1.7-2-0.6-4.1-1-6.2-1.4-2.1-0.4-4.2-0.9-6.3-1.2-2.1-0.3-4.2-0.7-6.4-1-2.1-0.2-4.3-0.5-6.5-0.7-17.3-1.7-35.2-1-53 1.9-2.2 0.3-4.5 0.8-6.7 1.2-2.2 0.4-4.5 0.8-6.7 1.4-2.2 0.5-4.4 1-6.7 1.5-2.2 0.6-4.4 1.2-6.6 1.7-8.8 2.4-17.7 5.2-26.4 8.5q-1.7 0.6-3.3 1.2c-1.1 0.4-2.2 0.9-3.3 1.3-2.2 0.9-4.4 1.7-6.5 2.6-4.3 1.9-8.6 3.7-12.9 5.7-4.3 2-8.5 4.1-12.8 6.2q-3.2 1.6-6.3 3.3c-1.1 0.6-2.1 1.1-3.2 1.7-1.1 0.6-2.1 1.2-3.1 1.7-2.1 1.2-4.2 2.3-6.3 3.5-2.1 1.2-4.1 2.4-6.2 3.7l-3.1 1.8-3.1 1.9c-2.1 1.3-4.1 2.5-6.2 3.8-4.1 2.6-8.2 5.2-12.2 8-2 1.4-4.1 2.7-6 4.1q-3 2.1-6 4.2c-2 1.4-4 2.9-6 4.3-2 1.5-4 2.9-5.9 4.4-3.9 3-7.8 6-11.7 9.1-7.8 6.1-15.4 12.5-22.9 19-15 13.1-29.5 26.9-43.4 41.4q-2.4 2.5-4.8 5.1z"/>
|
||||
<path id="<Path>" class="s0" d="m157.7 674.4c-2.1-0.6-4.2-1.3-6.4-1.9-1.1-0.3-2.2-0.6-3.3-1-1.1-0.4-2.2-0.8-3.4-1.2-2.3-0.8-4.6-1.6-7-2.4-2.3-0.9-4.7-1.8-7.2-2.8-1.2-0.5-2.5-0.9-3.7-1.5-1.2-0.5-2.5-1.1-3.7-1.6-1.2-0.5-2.5-1.1-3.8-1.6-0.6-0.3-1.3-0.6-1.9-0.8-0.6-0.3-1.3-0.6-1.9-0.9-2.5-1.2-5.1-2.5-7.8-3.8q-3.9-2.1-7.8-4.2c-10.5-5.9-21.2-13-31.5-21.7-10.3-8.7-20-19.1-28.5-31.1l-0.8-1.1-0.8-1.2c-0.5-0.8-1-1.6-1.5-2.3-0.5-0.8-1-1.6-1.5-2.3-0.3-0.4-0.5-0.8-0.8-1.2l-0.7-1.2c-0.9-1.6-1.9-3.3-2.8-4.9-0.5-0.8-0.9-1.7-1.3-2.5-0.4-0.8-0.9-1.7-1.3-2.5-0.4-0.9-0.9-1.7-1.3-2.6-0.5-0.8-0.8-1.7-1.2-2.6-0.8-1.8-1.6-3.5-2.4-5.3-0.7-1.8-1.4-3.6-2.1-5.5-0.3-0.9-0.7-1.8-1-2.8-0.3-0.9-0.6-1.9-0.9-2.8-0.3-0.9-0.6-1.9-0.9-2.8l-0.5-1.4c-0.2-0.5-0.3-1-0.4-1.4-0.5-1.9-1.1-3.9-1.6-5.8-0.3-1-0.5-2-0.7-2.9-0.2-1-0.4-2-0.7-3-0.2-1-0.4-2-0.7-3-0.2-1-0.4-2-0.5-3-1.6-8-2.4-16.3-3-24.7-1-16.8 0.1-34.2 2.7-51.7 0.4-2.2 0.7-4.4 1.1-6.6q0.6-3.3 1.2-6.6 0.3-1.7 0.6-3.3c0.2-1.1 0.5-2.2 0.7-3.3q0.8-3.3 1.5-6.6c1.1-4.4 2.2-8.8 3.5-13.2q0.5-1.7 0.9-3.3c0.3-1.1 0.6-2.2 1-3.3 0.7-2.2 1.4-4.4 2-6.6 0.7-2.2 1.5-4.4 2.2-6.6 0.7-2.2 1.5-4.4 2.3-6.6q1.2-3.3 2.4-6.6c0.8-2.2 1.7-4.4 2.5-6.5l1.3-3.3 1.4-3.3c0.9-2.2 1.8-4.3 2.7-6.5 1-2.2 1.9-4.3 2.9-6.5 0.5-1.1 0.9-2.2 1.4-3.2l1.5-3.2c3.3-7.2 6.8-14.2 10.5-21.3-1.5-6.2-2.9-12.4-4.2-18.7-1.5 2.9-3 5.8-4.4 8.7-4.3 8.8-8.6 17.6-12.4 26.6l-1.5 3.3c-0.5 1.1-0.9 2.2-1.4 3.4-0.9 2.2-1.8 4.5-2.8 6.7-0.9 2.3-1.7 4.5-2.6 6.7l-1.3 3.4-1.2 3.4c-0.8 2.3-1.6 4.5-2.4 6.8-0.8 2.3-1.5 4.5-2.3 6.8-0.8 2.3-1.5 4.5-2.2 6.8-0.7 2.3-1.4 4.5-2.1 6.8-0.6 2.3-1.3 4.5-1.9 6.8-0.3 1.1-0.6 2.3-0.9 3.4-0.3 1.1-0.6 2.3-0.9 3.4-1.2 4.5-2.2 9.1-3.2 13.6-0.5 2.3-0.9 4.6-1.4 6.8-0.2 1.1-0.4 2.3-0.7 3.4-0.2 1.1-0.4 2.3-0.6 3.4-0.4 2.3-0.8 4.5-1.1 6.8-0.3 2.3-0.6 4.5-0.9 6.8-2.3 18.1-2.9 36.1-1.4 53.4 0.8 8.7 1.9 17.2 3.7 25.5 0.2 1 0.4 2.1 0.6 3.1 0.3 1 0.5 2 0.8 3.1 0.3 1 0.5 2 0.8 3 0.3 1 0.5 2 0.8 3q0.9 3 1.8 6c0.2 0.5 0.3 1 0.5 1.5l0.5 1.5c0.3 1 0.7 1.9 1 2.9 0.3 1 0.7 1.9 1 2.9 0.3 1 0.8 1.9 1.1 2.8 0.8 1.9 1.6 3.7 2.3 5.6 0.9 1.8 1.7 3.6 2.6 5.4 0.4 0.9 0.8 1.8 1.3 2.7 0.5 0.9 0.9 1.7 1.4 2.6 0.5 0.9 0.9 1.7 1.4 2.6 0.5 0.9 0.9 1.7 1.5 2.6 1 1.7 2 3.3 3 5l0.8 1.2c0.3 0.4 0.5 0.8 0.8 1.2 0.5 0.8 1.1 1.6 1.6 2.4 0.5 0.8 1.1 1.6 1.6 2.4l0.8 1.2 0.9 1.1c9.1 12.2 19.4 22.6 30.1 31.2 10.8 8.6 21.8 15.6 32.6 21.3 2.7 1.4 5.4 2.7 8 4.1 2.7 1.2 5.3 2.4 7.9 3.6 0.6 0.3 1.3 0.6 1.9 0.9 0.7 0.3 1.3 0.5 2 0.8 1.3 0.5 2.6 1 3.9 1.6 1.3 0.5 2.5 1 3.8 1.5 1.2 0.5 2.5 0.9 3.8 1.4 2.5 0.9 4.9 1.8 7.3 2.6 2.4 0.8 4.8 1.5 7.1 2.2 1.2 0.4 2.3 0.7 3.4 1.1 1.1 0.4 2.3 0.6 3.4 1 2.2 0.6 4.4 1.2 6.5 1.8 16.9 4.5 30.4 6.7 39.7 8.3 9.3 1.3 14.2 2 14.2 2 0 0-4.9-0.8-14.1-2.4-9.1-2-22.5-4.6-39.3-9.4z"/>
|
||||
</g>
|
||||
<g id="<Group>">
|
||||
<g id="<Group>">
|
||||
</g>
|
||||
<g id="<Group>">
|
||||
<path id="<Path>" class="s1" d="m294.7 337.1v326.6c19.1 18.4 35.9 32.8 48.1 42.8 12.2-10 29-24.4 48.1-42.8v-326.6h199.8c8-30.4 13.7-62.5 16.3-96.1h-528.4c2.6 33.6 8.4 65.7 16.3 96.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="<Group>">
|
||||
<path id="<Compound Path>" fill-rule="evenodd" class="s1" d="m342.8 778.5l-11-7.6c-3.2-2.2-79.3-55.6-156.2-152.6-45.3-57.1-81.4-117.4-107.3-179.4-32.5-77.8-49-158.4-49-239.5v-13.7l323.5-112.5 323.5 112.5v13.7c0 81.1-16.5 161.6-49 239.5-25.9 62-62 122.4-107.3 179.4-76.9 97-153 150.4-156.2 152.6zm-284.9-565.6c4.1 165.5 81.7 297.8 147.1 380.5 56.8 71.9 114.4 119.6 137.8 137.7 23.5-18.1 81-65.8 137.8-137.7 65.4-82.7 143-215 147.1-380.5l-284.9-99z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
44
assets/custom-icons/icons/uphold.svg
Normal file
44
assets/custom-icons/icons/uphold.svg
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
width="96"
|
||||
height="96"
|
||||
viewBox="0 0 96 96"
|
||||
xml:space="preserve"
|
||||
id="svg1"
|
||||
sodipodi:docname="uphold.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs1" /><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="8.09375"
|
||||
inkscape:cx="48"
|
||||
inkscape:cy="48"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="991"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<desc
|
||||
id="desc1">Created with Fabric.js 5.3.0</desc>
|
||||
<g
|
||||
transform="matrix(1.6496133,0,0,1.6496134,47.999993,48.000007)"
|
||||
id="RoQhZNvyF1biObpr9w5El">
|
||||
<path
|
||||
style="opacity:1;fill:#6fe68a;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
d="m 3.59732,16.89848 c -1.1,0.4 -2.3,0.5 -3.5,0.5 h -0.2 c -1.2,0 -2.4,-0.2 -3.5,-0.6 -0.6,-0.2 -1.1,0.2 -1.3,0.7 -0.2,0.6 0.2,1.2 0.7,1.3 1.3,0.4 2.7,0.6 4.1,0.6 h 0.2 c 1.4,0 2.8,-0.2 4.1,-0.6 0.5,-0.2 0.8,-0.8 0.6,-1.4 -0.2,-0.3 -0.7,-0.6 -1.2,-0.5 z m 9.1,-26.7 c 0,0 0,-0.1 0,0 -2.3,-7.3 -9.9,-11.3 -16.9,-8.9 -4,1.4 -7.2,4.7 -8.5,8.9 -1.2,3.6 -0.8,8.4 1.2,12.9 2.6,6.1 7.3,10.4 11.5,10.4 h 0.1 c 4.2,0 8.9,-4.3 11.5,-10.4 1.9,-4.5 2.3,-9.3 1.1,-12.9 m -6.2,-5.2 c -2.1,-0.1 -4.4,0.9 -6.6,2.7 -2.2,-1.8 -4.5,-2.8 -6.6,-2.7 4,-2.9 9.3,-2.9 13.2,0 m -4.8,25.9 c -1.1,0.5 -2.4,0.5 -3.5,0 -3.6,-1.7 -4.3,-8.6 -1.6,-14.9 0.8,-2 1.9,-3.8 3.3,-5.3 1.4,1.6 2.5,3.4 3.3,5.3 2.8,6.4 2.1,13.2 -1.5,14.9 m -11.4,-8.7 c -1.7,-4 -2.1,-8.2 -1.1,-11.4 0.5,-1.6 1.5,-2.8 2.7,-3.4 1.8,-0.8 4.2,-0.1 6.6,1.8 -1.5,1.8 -2.8,3.8 -3.7,5.9 -1.8,4.3 -2.2,8.8 -1.4,12.2 -1.3,-1.5 -2.3,-3.2 -3.1,-5.1 m 19.3,0 c -0.8,1.8 -1.8,3.5 -3,5.1 0.8,-3.4 0.4,-7.9 -1.4,-12.2 -0.9,-2.2 -2.2,-4.2 -3.7,-5.9 2.3,-1.9 4.7,-2.6 6.6,-1.7 1.2,0.6 2.1,1.7 2.7,3.4 0.9,3.1 0.5,7.3 -1.2,11.3 z"
|
||||
stroke-linecap="round"
|
||||
id="path1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -79,6 +79,8 @@ PODS:
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- privacy_screen (0.0.1):
|
||||
- Flutter
|
||||
- qr_code_scanner (0.2.0):
|
||||
- Flutter
|
||||
- MTBBarcodeScanner
|
||||
@@ -127,6 +129,7 @@ DEPENDENCIES:
|
||||
- open_filex (from `.symlinks/plugins/open_filex/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- privacy_screen (from `.symlinks/plugins/privacy_screen/ios`)
|
||||
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
|
||||
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
@@ -186,6 +189,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
privacy_screen:
|
||||
:path: ".symlinks/plugins/privacy_screen/ios"
|
||||
qr_code_scanner:
|
||||
:path: ".symlinks/plugins/qr_code_scanner/ios"
|
||||
sentry_flutter:
|
||||
@@ -225,6 +230,7 @@ SPEC CHECKSUMS:
|
||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e
|
||||
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9
|
||||
|
||||
@@ -18,72 +18,81 @@ class HomeEmptyStateWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.tightFor(height: 800, width: 450),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40.0, horizontal: 40),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/wallet-front-gradient.png",
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
Text(
|
||||
l10n.setupFirstAccount,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
const SizedBox(height: 64),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onScanTap,
|
||||
child: Text(l10n.importScanQrCode),
|
||||
return SingleChildScrollView(
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.tightFor(height: 800, width: 450),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40.0, horizontal: 40),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/wallet-front-gradient.png",
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onManuallySetupTap,
|
||||
child: Text(l10n.importEnterSetupKey),
|
||||
Text(
|
||||
l10n.setupFirstAccount,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 54),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
routeToPage(context, ImportCodePage());
|
||||
},
|
||||
child: Text(
|
||||
l10n.importCodes,
|
||||
textAlign: TextAlign.center,
|
||||
style: getEnteTextTheme(context).bodyFaint.copyWith(decoration: TextDecoration.underline),
|
||||
),),
|
||||
const SizedBox(height: 18),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showModalBottomSheet<void>(
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
barrierColor: Colors.black87,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const FAQQuestionsWidget();
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
l10n.faq,
|
||||
textAlign: TextAlign.center,
|
||||
style: getEnteTextTheme(context).bodyFaint.copyWith(decoration: TextDecoration.underline),
|
||||
),),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 64),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onScanTap,
|
||||
child: Text(l10n.importScanQrCode),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onManuallySetupTap,
|
||||
child: Text(l10n.importEnterSetupKey),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 54),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
routeToPage(context, ImportCodePage());
|
||||
},
|
||||
child: Text(
|
||||
l10n.importCodes,
|
||||
textAlign: TextAlign.center,
|
||||
style: getEnteTextTheme(context)
|
||||
.bodyFaint
|
||||
.copyWith(decoration: TextDecoration.underline),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showModalBottomSheet<void>(
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.background,
|
||||
barrierColor: Colors.black87,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const FAQQuestionsWidget();
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
l10n.faq,
|
||||
textAlign: TextAlign.center,
|
||||
style: getEnteTextTheme(context)
|
||||
.bodyFaint
|
||||
.copyWith(decoration: TextDecoration.underline),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -80,18 +80,25 @@ Future<int?> _processBitwardenExportFile(
|
||||
List<dynamic> jsonArray = data['items'];
|
||||
final parsedCodes = [];
|
||||
for (var item in jsonArray) {
|
||||
if (item['login']['totp'] != null) {
|
||||
var issuer = item['name'];
|
||||
var account = item['login']['username'];
|
||||
var secret = item['login']['totp'];
|
||||
if (item['login'] != null && item['login']['totp'] != null) {
|
||||
var totp = item['login']['totp'];
|
||||
|
||||
parsedCodes.add(
|
||||
Code.fromAccountAndSecret(
|
||||
Code code;
|
||||
|
||||
if (totp.contains("otpauth://")) {
|
||||
code = Code.fromRawData(totp);
|
||||
} else {
|
||||
var issuer = item['name'];
|
||||
var account = item['login']['username'];
|
||||
|
||||
code = Code.fromAccountAndSecret(
|
||||
account,
|
||||
issuer,
|
||||
secret,
|
||||
),
|
||||
);
|
||||
totp,
|
||||
);
|
||||
}
|
||||
|
||||
parsedCodes.add(code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:ente_auth/ente_theme_data.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@@ -14,6 +15,8 @@ class IconUtils {
|
||||
// Map of icon-title to the color code in HEX
|
||||
final Map<String, String> _simpleIcons = {};
|
||||
final Map<String, CustomIconData> _customIcons = {};
|
||||
// Map of icon-color to its luminance
|
||||
final Map<Color, double> _colorLuminance = {};
|
||||
|
||||
Future<void> init() async {
|
||||
await _loadJson();
|
||||
@@ -31,6 +34,7 @@ class IconUtils {
|
||||
title,
|
||||
_customIcons[title]!.color,
|
||||
width,
|
||||
context,
|
||||
);
|
||||
} else if (_simpleIcons.containsKey(title)) {
|
||||
return _getSVGIcon(
|
||||
@@ -38,6 +42,7 @@ class IconUtils {
|
||||
title,
|
||||
_simpleIcons[title],
|
||||
width,
|
||||
context,
|
||||
);
|
||||
} else if (title.isNotEmpty) {
|
||||
bool showLargeIcon = width > 24;
|
||||
@@ -63,20 +68,45 @@ class IconUtils {
|
||||
String title,
|
||||
String? color,
|
||||
double width,
|
||||
BuildContext context,
|
||||
) {
|
||||
final iconColor = _getAdaptiveColor(color, context);
|
||||
return SvgPicture.asset(
|
||||
path,
|
||||
width: width,
|
||||
semanticsLabel: title,
|
||||
colorFilter: color != null
|
||||
colorFilter: iconColor != null
|
||||
? ColorFilter.mode(
|
||||
Color(int.parse("0xFF" + color)),
|
||||
iconColor,
|
||||
BlendMode.srcIn,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Color? _getAdaptiveColor(String? hexColor, BuildContext context) {
|
||||
if (hexColor == null) return null;
|
||||
final theme = Theme.of(context).brightness;
|
||||
final color = Color(int.parse("0xFF" + hexColor));
|
||||
// Color is close to neutral-grey and it's too light or dark for theme
|
||||
if (_isCloseToNeutralGrey(color) &&
|
||||
((theme == Brightness.light && _getColorLuminance(color) > 0.70) ||
|
||||
(theme == Brightness.dark && _getColorLuminance(color) < 0.05))) {
|
||||
return Theme.of(context).colorScheme.iconColor;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
double _getColorLuminance(Color color) {
|
||||
return _colorLuminance.putIfAbsent(color, () => color.computeLuminance());
|
||||
}
|
||||
|
||||
bool _isCloseToNeutralGrey(Color color, {double tolerance = 3}) {
|
||||
return (color.red - color.green).abs() <= tolerance &&
|
||||
(color.green - color.blue).abs() <= tolerance &&
|
||||
(color.blue - color.red).abs() <= tolerance;
|
||||
}
|
||||
|
||||
Future<void> _loadJson() async {
|
||||
try {
|
||||
final simpleIconData = await rootBundle
|
||||
|
||||
BIN
migration-guides/decrypt/bin/ente-decrypt-darwin-amd64
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-darwin-amd64
Executable file
Binary file not shown.
BIN
migration-guides/decrypt/bin/ente-decrypt-darwin-arm64
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-darwin-arm64
Executable file
Binary file not shown.
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-386
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-386
Executable file
Binary file not shown.
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-amd64
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-amd64
Executable file
Binary file not shown.
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-arm
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-arm
Executable file
Binary file not shown.
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-arm64
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-arm64
Executable file
Binary file not shown.
BIN
migration-guides/decrypt/bin/ente-decrypt-windows-386.exe
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-windows-386.exe
Executable file
Binary file not shown.
BIN
migration-guides/decrypt/bin/ente-decrypt-windows-amd64.exe
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-windows-amd64.exe
Executable file
Binary file not shown.
@@ -1,13 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/jamesruan/sodium"
|
||||
"golang.org/x/crypto/argon2"
|
||||
)
|
||||
|
||||
@@ -48,23 +45,38 @@ func deriveArgonKey(password, salt string, memLimit, opsLimit int) ([]byte, erro
|
||||
// Returns:
|
||||
// - A byte slice representing the decrypted data.
|
||||
// - An error object, which is nil if no error occurs.
|
||||
func decryptChaCha20poly1305(data []byte, key []byte, nonce []byte) ([]byte, error) {
|
||||
reader := bytes.NewReader(data)
|
||||
header := sodium.SecretStreamXCPHeader{Bytes: nonce}
|
||||
decoder, err := sodium.MakeSecretStreamXCPDecoder(
|
||||
sodium.SecretStreamXCPKey{Bytes: key},
|
||||
reader,
|
||||
header)
|
||||
// func decryptChaCha20poly13052(data []byte, key []byte, nonce []byte) ([]byte, error) {
|
||||
// reader := bytes.NewReader(data)
|
||||
// header := sodium.SecretStreamXCPHeader{Bytes: nonce}
|
||||
// decoder, err := sodium.MakeSecretStreamXCPDecoder(
|
||||
// sodium.SecretStreamXCPKey{Bytes: key},
|
||||
// reader,
|
||||
// header)
|
||||
// if err != nil {
|
||||
// log.Println("Failed to make secret stream decoder", err)
|
||||
// return nil, err
|
||||
// }
|
||||
// // Buffer to store the decrypted data
|
||||
// decryptedData := make([]byte, len(data))
|
||||
// n, err := decoder.Read(decryptedData)
|
||||
// if err != nil && err != io.EOF {
|
||||
// log.Println("Failed to read from decoder", err)
|
||||
// return nil, err
|
||||
// }
|
||||
// return decryptedData[:n], nil
|
||||
// }
|
||||
|
||||
func decryptChaCha20poly13052(data []byte, key []byte, nonce []byte) ([]byte, error) {
|
||||
decryptor, err := NewDecryptor(key, nonce)
|
||||
if err != nil {
|
||||
log.Println("Failed to make secret stream decoder", err)
|
||||
return nil, err
|
||||
}
|
||||
// Buffer to store the decrypted data
|
||||
decryptedData := make([]byte, len(data))
|
||||
n, err := decoder.Read(decryptedData)
|
||||
if err != nil && err != io.EOF {
|
||||
log.Println("Failed to read from decoder", err)
|
||||
decoded, tag, err := decryptor.Pull(data)
|
||||
if tag != TagFinal {
|
||||
return nil, errors.New("invalid tag")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decryptedData[:n], nil
|
||||
return decoded, nil
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestDecryptChaCha20poly1305(t *testing.T) {
|
||||
t.Fatalf("Failed to decode cipher nonce: %v", err)
|
||||
}
|
||||
|
||||
decryptedText, err := decryptChaCha20poly1305(decodedCipherText, derivedKey, decodedCipherNonce)
|
||||
decryptedText, err := decryptChaCha20poly13052(decodedCipherText, derivedKey, decodedCipherNonce)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to decrypt: %v", err)
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -90,7 +90,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
decryptedData, err := decryptChaCha20poly1305(encryptedData, key, nonce)
|
||||
decryptedData, err := decryptChaCha20poly13052(encryptedData, key, nonce)
|
||||
if err != nil {
|
||||
fmt.Println("Error decrypting data:", err)
|
||||
return
|
||||
|
||||
@@ -2,9 +2,6 @@ module decrypt
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/jamesruan/sodium v1.0.14
|
||||
golang.org/x/crypto v0.11.0
|
||||
)
|
||||
require golang.org/x/crypto v0.11.0
|
||||
|
||||
require golang.org/x/sys v0.10.0 // indirect
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
github.com/jamesruan/sodium v1.0.14 h1:JfOHobip/lUWouxHV3PwYwu3gsLewPrDrZXO3HuBzUU=
|
||||
github.com/jamesruan/sodium v1.0.14/go.mod h1:GK2+LACf7kuVQ9k7Irk0MB2B65j5rVqkz+9ylGIggZk=
|
||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
|
||||
43
migration-guides/decrypt/release.sh
Normal file
43
migration-guides/decrypt/release.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Create a "bin" directory if it doesn't exist
|
||||
mkdir -p bin
|
||||
|
||||
# List of target operating systems
|
||||
OS_TARGETS=("windows" "linux" "darwin")
|
||||
|
||||
# Corresponding architectures for each OS
|
||||
ARCH_TARGETS=("386 amd64" "386 amd64 arm arm64" "amd64 arm64")
|
||||
|
||||
# Loop through each OS target
|
||||
for index in "${!OS_TARGETS[@]}"
|
||||
do
|
||||
OS=${OS_TARGETS[$index]}
|
||||
for ARCH in ${ARCH_TARGETS[$index]}
|
||||
do
|
||||
# Set the GOOS environment variable for the current target OS
|
||||
export GOOS="$OS"
|
||||
export GOARCH="$ARCH"
|
||||
|
||||
# Set the output binary name to "ente-decrypt" for the current OS and architecture
|
||||
BINARY_NAME="ente-decrypt-$OS-$ARCH"
|
||||
|
||||
# Add .exe extension for Windows
|
||||
if [ "$OS" == "windows" ]; then
|
||||
BINARY_NAME="ente-decrypt-$OS-$ARCH.exe"
|
||||
fi
|
||||
|
||||
# Build the binary and place it in the "bin" directory
|
||||
go build -o "bin/$BINARY_NAME" decrypt.go crypt.go stream.go
|
||||
|
||||
# Print a message indicating the build is complete for the current OS and architecture
|
||||
echo "Built for $OS ($ARCH) as bin/$BINARY_NAME"
|
||||
done
|
||||
done
|
||||
|
||||
# Clean up any environment variables
|
||||
unset GOOS
|
||||
unset GOARCH
|
||||
|
||||
# Print a message indicating the build process is complete
|
||||
echo "Build process completed for all platforms and architectures. Binaries are in the 'bin' directory."
|
||||
409
migration-guides/decrypt/stream.go
Normal file
409
migration-guides/decrypt/stream.go
Normal file
@@ -0,0 +1,409 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/chacha20"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/poly1305"
|
||||
)
|
||||
|
||||
// public constants
|
||||
const (
|
||||
//TagMessage the most common tag, that doesn't add any information about the nature of the message.
|
||||
TagMessage = 0
|
||||
// TagPush indicates that the message marks the end of a set of messages,
|
||||
// but not the end of the stream. For example, a huge JSON string sent as multiple chunks can use this tag to indicate to the application that the string is complete and that it can be decoded. But the stream itself is not closed, and more data may follow.
|
||||
TagPush = 0x01
|
||||
// TagRekey "forget" the key used to encrypt this message and the previous ones, and derive a new secret key.
|
||||
TagRekey = 0x02
|
||||
// TagFinal indicates that the message marks the end of the stream, and erases the secret key used to encrypt the previous sequence.
|
||||
TagFinal = TagPush | TagRekey
|
||||
|
||||
StreamKeyBytes = chacha20poly1305.KeySize
|
||||
StreamHeaderBytes = chacha20poly1305.NonceSizeX
|
||||
// XChaCha20Poly1305IetfABYTES links to crypto_secretstream_xchacha20poly1305_ABYTES
|
||||
XChaCha20Poly1305IetfABYTES = 16 + 1
|
||||
)
|
||||
|
||||
const cryptoCoreHchacha20InputBytes = 16
|
||||
|
||||
/* const crypto_secretstream_xchacha20poly1305_INONCEBYTES = 8 */
|
||||
const cryptoSecretStreamXchacha20poly1305Counterbytes = 4
|
||||
|
||||
var pad0 [16]byte
|
||||
|
||||
var invalidKey = errors.New("invalid key")
|
||||
var invalidInput = errors.New("invalid input")
|
||||
var cryptoFailure = errors.New("crypto failed")
|
||||
|
||||
func memZero(b []byte) {
|
||||
for i := range b {
|
||||
b[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func xorBuf(out, in []byte) {
|
||||
for i := range out {
|
||||
out[i] ^= in[i]
|
||||
}
|
||||
}
|
||||
|
||||
func bufInc(n []byte) {
|
||||
c := 1
|
||||
|
||||
for i := range n {
|
||||
c += int(n[i])
|
||||
n[i] = byte(c)
|
||||
c >>= 8
|
||||
}
|
||||
}
|
||||
|
||||
// crypto_secretstream_xchacha20poly1305_state
|
||||
type streamState struct {
|
||||
k [StreamKeyBytes]byte
|
||||
nonce [chacha20poly1305.NonceSize]byte
|
||||
pad [8]byte
|
||||
}
|
||||
|
||||
func (s *streamState) reset() {
|
||||
for i := range s.nonce {
|
||||
s.nonce[i] = 0
|
||||
}
|
||||
s.nonce[0] = 1
|
||||
}
|
||||
|
||||
type Encryptor interface {
|
||||
Push(m []byte, tag byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type Decryptor interface {
|
||||
Pull(m []byte) ([]byte, byte, error)
|
||||
}
|
||||
|
||||
type encryptor struct {
|
||||
streamState
|
||||
}
|
||||
|
||||
type decryptor struct {
|
||||
streamState
|
||||
}
|
||||
|
||||
func NewStreamKey() []byte {
|
||||
k := make([]byte, chacha20poly1305.KeySize)
|
||||
_, _ = rand.Read(k)
|
||||
return k
|
||||
}
|
||||
|
||||
func NewEncryptor(key []byte) (Encryptor, []byte, error) {
|
||||
if len(key) != StreamKeyBytes {
|
||||
return nil, nil, invalidKey
|
||||
}
|
||||
|
||||
header := make([]byte, StreamHeaderBytes)
|
||||
_, _ = rand.Read(header)
|
||||
|
||||
stream := &encryptor{}
|
||||
|
||||
k, err := chacha20.HChaCha20(key[:], header[:16])
|
||||
if err != nil {
|
||||
//fmt.Printf("error: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
copy(stream.k[:], k)
|
||||
stream.reset()
|
||||
|
||||
for i := range stream.pad {
|
||||
stream.pad[i] = 0
|
||||
}
|
||||
|
||||
for i, b := range header[cryptoCoreHchacha20InputBytes:] {
|
||||
stream.nonce[i+cryptoSecretStreamXchacha20poly1305Counterbytes] = b
|
||||
}
|
||||
// fmt.Printf("stream: %+v\n", stream.streamState)
|
||||
|
||||
return stream, header, nil
|
||||
}
|
||||
|
||||
func (s *encryptor) Push(plain []byte, tag byte) ([]byte, error) {
|
||||
var err error
|
||||
|
||||
//crypto_onetimeauth_poly1305_state poly1305_state;
|
||||
var poly *poly1305.MAC
|
||||
|
||||
//unsigned char block[64U];
|
||||
var block [64]byte
|
||||
|
||||
//unsigned char slen[8U];
|
||||
var slen [8]byte
|
||||
|
||||
//unsigned char *c;
|
||||
//unsigned char *mac;
|
||||
//
|
||||
//if (outlen_p != NULL) {
|
||||
//*outlen_p = 0U;
|
||||
//}
|
||||
|
||||
mlen := len(plain)
|
||||
//if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
|
||||
//sodium_misuse();
|
||||
//}
|
||||
|
||||
out := make([]byte, mlen+XChaCha20Poly1305IetfABYTES)
|
||||
|
||||
chacha, err := chacha20.NewUnauthenticatedCipher(s.k[:], s.nonce[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
|
||||
chacha.XORKeyStream(block[:], block[:])
|
||||
|
||||
//crypto_onetimeauth_poly1305_init(&poly1305_state, block);
|
||||
var poly_init [32]byte
|
||||
copy(poly_init[:], block[:])
|
||||
poly = poly1305.New(&poly_init)
|
||||
|
||||
// TODO add support for add data
|
||||
//sodium_memzero(block, sizeof block);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
|
||||
//(0x10 - adlen) & 0xf);
|
||||
|
||||
//memset(block, 0, sizeof block);
|
||||
//block[0] = tag;
|
||||
memZero(block[:])
|
||||
block[0] = tag
|
||||
|
||||
//
|
||||
//crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, state->nonce, 1U, state->k);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
|
||||
//out[0] = block[0];
|
||||
chacha.XORKeyStream(block[:], block[:])
|
||||
_, _ = poly.Write(block[:])
|
||||
out[0] = block[0]
|
||||
|
||||
//
|
||||
//c = out + (sizeof tag);
|
||||
c := out[1:]
|
||||
//crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
|
||||
//crypto_onetimeauth_poly1305_update (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
|
||||
chacha.XORKeyStream(c, plain)
|
||||
_, _ = poly.Write(c[:mlen])
|
||||
padlen := (0x10 - len(block) + mlen) & 0xf
|
||||
_, _ = poly.Write(pad0[:padlen])
|
||||
|
||||
//
|
||||
//STORE64_LE(slen, (uint64_t) adlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
binary.LittleEndian.PutUint64(slen[:], uint64(0))
|
||||
_, _ = poly.Write(slen[:])
|
||||
|
||||
//STORE64_LE(slen, (sizeof block) + mlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
binary.LittleEndian.PutUint64(slen[:], uint64(len(block)+mlen))
|
||||
_, _ = poly.Write(slen[:])
|
||||
|
||||
//
|
||||
//mac = c + mlen;
|
||||
//crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
|
||||
mac := c[mlen:]
|
||||
copy(mac, poly.Sum(nil))
|
||||
//sodium_memzero(&poly1305_state, sizeof poly1305_state);
|
||||
//
|
||||
|
||||
//XOR_BUF(STATE_INONCE(state), mac, crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
//sodium_increment(STATE_COUNTER(state), crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
|
||||
xorBuf(s.nonce[cryptoSecretStreamXchacha20poly1305Counterbytes:], mac)
|
||||
bufInc(s.nonce[:cryptoSecretStreamXchacha20poly1305Counterbytes])
|
||||
|
||||
// TODO
|
||||
//if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
|
||||
//sodium_is_zero(STATE_COUNTER(state),
|
||||
//crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
|
||||
//crypto_secretstream_xchacha20poly1305_rekey(state);
|
||||
//}
|
||||
|
||||
//if (outlen_p != NULL) {
|
||||
//*outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
|
||||
//}
|
||||
|
||||
//return 0;
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func NewDecryptor(key, header []byte) (Decryptor, error) {
|
||||
stream := &decryptor{}
|
||||
|
||||
//crypto_core_hchacha20(state->k, in, k, NULL);
|
||||
k, err := chacha20.HChaCha20(key, header[:16])
|
||||
if err != nil {
|
||||
fmt.Printf("error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
copy(stream.k[:], k)
|
||||
|
||||
//_crypto_secretstream_xchacha20poly1305_counter_reset(state);
|
||||
stream.reset()
|
||||
|
||||
//memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
|
||||
// crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
copy(stream.nonce[cryptoSecretStreamXchacha20poly1305Counterbytes:],
|
||||
header[cryptoCoreHchacha20InputBytes:])
|
||||
|
||||
//memset(state->_pad, 0, sizeof state->_pad);
|
||||
copy(stream.pad[:], pad0[:])
|
||||
|
||||
//fmt.Printf("decryptor: %+v\n", stream.streamState)
|
||||
|
||||
return stream, nil
|
||||
}
|
||||
|
||||
func (s *decryptor) Pull(cipher []byte) ([]byte, byte, error) {
|
||||
cipherLen := len(cipher)
|
||||
|
||||
//crypto_onetimeauth_poly1305_state poly1305_state;
|
||||
var poly1305State [32]byte
|
||||
|
||||
//unsigned char block[64U];
|
||||
var block [64]byte
|
||||
//unsigned char slen[8U];
|
||||
var slen [8]byte
|
||||
|
||||
//unsigned char mac[crypto_onetimeauth_poly1305_BYTES];
|
||||
//const unsigned char *c;
|
||||
//const unsigned char *stored_mac;
|
||||
//unsigned long long mlen; // length of the returned message
|
||||
//unsigned char tag; // for the return value
|
||||
//
|
||||
//if (mlen_p != NULL) {
|
||||
//*mlen_p = 0U;
|
||||
//}
|
||||
//if (tag_p != NULL) {
|
||||
//*tag_p = 0xff;
|
||||
//}
|
||||
|
||||
/*
|
||||
if (inlen < crypto_secretstream_xchacha20poly1305_ABYTES) {
|
||||
return -1;
|
||||
}
|
||||
mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
|
||||
*/
|
||||
if cipherLen < XChaCha20Poly1305IetfABYTES {
|
||||
return nil, 0, invalidInput
|
||||
}
|
||||
mlen := cipherLen - XChaCha20Poly1305IetfABYTES
|
||||
|
||||
//if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
|
||||
//sodium_misuse();
|
||||
//}
|
||||
|
||||
//crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
|
||||
chacha, err := chacha20.NewUnauthenticatedCipher(s.k[:], s.nonce[:])
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
chacha.XORKeyStream(block[:], block[:])
|
||||
|
||||
//crypto_onetimeauth_poly1305_init(&poly1305_state, block);
|
||||
|
||||
copy(poly1305State[:], block[:])
|
||||
poly := poly1305.New(&poly1305State)
|
||||
|
||||
// TODO
|
||||
//sodium_memzero(block, sizeof block);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
|
||||
//(0x10 - adlen) & 0xf);
|
||||
//
|
||||
|
||||
//memset(block, 0, sizeof block);
|
||||
//block[0] = in[0];
|
||||
//crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, state->nonce, 1U, state->k);
|
||||
memZero(block[:])
|
||||
block[0] = cipher[0]
|
||||
chacha.XORKeyStream(block[:], block[:])
|
||||
|
||||
//tag = block[0];
|
||||
//block[0] = in[0];
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
|
||||
tag := block[0]
|
||||
block[0] = cipher[0]
|
||||
if _, err = poly.Write(block[:]); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
//c = in + (sizeof tag);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
|
||||
//crypto_onetimeauth_poly1305_update (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
|
||||
c := cipher[1:]
|
||||
if _, err = poly.Write(c[:mlen]); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
padLen := (0x10 - len(block) + mlen) & 0xf
|
||||
if _, err = poly.Write(pad0[:padLen]); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
//
|
||||
//STORE64_LE(slen, (uint64_t) adlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
binary.LittleEndian.PutUint64(slen[:], uint64(0))
|
||||
if _, err = poly.Write(slen[:]); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
//STORE64_LE(slen, (sizeof block) + mlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
binary.LittleEndian.PutUint64(slen[:], uint64(len(block)+mlen))
|
||||
if _, err = poly.Write(slen[:]); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
//
|
||||
//crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
|
||||
//sodium_memzero(&poly1305_state, sizeof poly1305_state);
|
||||
|
||||
mac := poly.Sum(nil)
|
||||
memZero(poly1305State[:])
|
||||
|
||||
//stored_mac = c + mlen;
|
||||
//if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
|
||||
//sodium_memzero(mac, sizeof mac);
|
||||
//return -1;
|
||||
//}
|
||||
storedMac := c[mlen:]
|
||||
if !bytes.Equal(mac, storedMac) {
|
||||
memZero(mac)
|
||||
return nil, 0, cryptoFailure
|
||||
}
|
||||
|
||||
//crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
|
||||
//XOR_BUF(STATE_INONCE(state), mac, crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
//sodium_increment(STATE_COUNTER(state), crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
|
||||
m := make([]byte, mlen)
|
||||
chacha.XORKeyStream(m, c[:mlen])
|
||||
|
||||
xorBuf(s.nonce[cryptoSecretStreamXchacha20poly1305Counterbytes:], mac)
|
||||
bufInc(s.nonce[:cryptoSecretStreamXchacha20poly1305Counterbytes])
|
||||
|
||||
// TODO
|
||||
//if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
|
||||
//sodium_is_zero(STATE_COUNTER(state),
|
||||
//crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
|
||||
//crypto_secretstream_xchacha20poly1305_rekey(state);
|
||||
//}
|
||||
|
||||
//if (mlen_p != NULL) {
|
||||
//*mlen_p = mlen;
|
||||
//}
|
||||
//if (tag_p != NULL) {
|
||||
//*tag_p = tag;
|
||||
//}
|
||||
//return 0;
|
||||
return m, tag, nil
|
||||
}
|
||||
@@ -56,7 +56,7 @@ For encryption, we are using `XChaCha20-Poly1305` algorithm.
|
||||
* **ente Authenticator app**: You can directly import the codes in the ente Authenticator app.
|
||||
> Settings -> Data -> Import Codes -> ente Encrypted export.
|
||||
|
||||
* **Decryption Tool** : You can download the prebuilt [decryption tool](decrypt/decrypt) (or build it from [source](decrypt)) and run the following command.
|
||||
* **Decryption Tool** : You can download the prebuilt [decryption tool](decrypt/bin/) (or build it from [source](decrypt)) and run the following command.
|
||||
|
||||
```
|
||||
./decrypt <export_file> <password> <output_file>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: ente_auth
|
||||
description: ente two-factor authenticator
|
||||
version: 2.0.28+227
|
||||
version: 2.0.30+230
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
|
||||
Reference in New Issue
Block a user