forked from mirror/grapevine
Compare commits
2 commits
custom
...
lambda/aut
Author | SHA1 | Date | |
---|---|---|---|
|
cd658d038a | ||
|
d6fe411443 |
14 changed files with 1932 additions and 13 deletions
1391
Cargo.lock
generated
1391
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,7 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["auth-media-cert-gen"]
|
||||
|
||||
# Keep alphabetically sorted
|
||||
[workspace.lints.rust]
|
||||
elided_lifetimes_in_paths = "warn"
|
||||
|
@ -89,6 +93,7 @@ workspace = true
|
|||
[dependencies]
|
||||
argon2 = "0.5.3"
|
||||
async-trait = "0.1.80"
|
||||
auth-media-cert-gen = { path = "auth-media-cert-gen" }
|
||||
axum = { version = "0.7.5", default-features = false, features = ["form", "http1", "http2", "json", "matched-path", "tracing"] }
|
||||
axum-extra = { version = "0.9.3", features = ["typed-header"] }
|
||||
axum-server = { version = "0.6.0", features = ["tls-rustls"] }
|
||||
|
|
13
auth-media-cert-gen/Cargo.toml
Normal file
13
auth-media-cert-gen/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "auth-media-cert-gen"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
comemo = "0.4.0"
|
||||
time = "0.3.36"
|
||||
typst = "0.11.1"
|
||||
typst-render = "0.11.1"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
BIN
auth-media-cert-gen/res/ComicNeue-Bold.ttf
Normal file
BIN
auth-media-cert-gen/res/ComicNeue-Bold.ttf
Normal file
Binary file not shown.
BIN
auth-media-cert-gen/res/NotoColorEmoji.ttf
Normal file
BIN
auth-media-cert-gen/res/NotoColorEmoji.ttf
Normal file
Binary file not shown.
44
auth-media-cert-gen/res/auth.typ
Normal file
44
auth-media-cert-gen/res/auth.typ
Normal file
|
@ -0,0 +1,44 @@
|
|||
#let issuer = sys.inputs.issuer
|
||||
#let target = sys.inputs.target
|
||||
|
||||
#set page(
|
||||
width: 11cm,
|
||||
height: 7cm,
|
||||
fill: red.lighten(90%),
|
||||
footer: text(size: 0.5em)[Issued by #issuer, #datetime.today().display()]
|
||||
)
|
||||
#set text(size: 1.1em)
|
||||
#set text(font: "Comic Neue", weight: "bold", fill: gray.darken(80%))
|
||||
#set align(center)
|
||||
#set par(leading: 0.5em)
|
||||
|
||||
#let target = text(target.replace(".", "\u{200A}.\u{200A}"))
|
||||
|
||||
#text(size: 1.5em)[
|
||||
Congratulations, \
|
||||
#target user!
|
||||
]
|
||||
#parbreak()
|
||||
#text(size: 0.9em)[
|
||||
Your homeserver supports authenticated media!
|
||||
]
|
||||
|
||||
#block(
|
||||
above: 34pt,
|
||||
radius: 4pt,
|
||||
inset: 7pt,
|
||||
fill: green.lighten(85%),
|
||||
stroke: 2pt + green.lighten(10%),
|
||||
grid(
|
||||
columns: (2.3em, auto),
|
||||
grid.cell(text(size: 1.7em, top-edge: 0.85em, emoji.checkmark.box)),
|
||||
grid.cell(align(left)[
|
||||
#target \
|
||||
MSC3916 certified
|
||||
]),
|
||||
)
|
||||
)
|
||||
|
||||
#let emojiscale = 45%
|
||||
#place(horizon + right, dx: 41pt, dy: 35pt, scale(x: emojiscale, y: emojiscale, image("party.svg")))
|
||||
#place(horizon + left, dx: -46pt, dy: 40pt, scale(x: emojiscale, y: emojiscale, image("confetti.svg")))
|
116
auth-media-cert-gen/res/confetti.svg
Normal file
116
auth-media-cert-gen/res/confetti.svg
Normal file
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xml:space="preserve"
|
||||
viewBox="0 0 137.28036 150.47484"
|
||||
version="1.1"
|
||||
id="svg20"
|
||||
sodipodi:docname="confetti.svg"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
||||
width="137.28036"
|
||||
height="150.47484"
|
||||
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="defs20" /><sodipodi:namedview
|
||||
id="namedview20"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="4.5519999"
|
||||
inkscape:cx="69.310195"
|
||||
inkscape:cy="77.328648"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1032"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg20" /><path
|
||||
d="m 36.102519,33.502424 a 4.336,4.336 0 0 1 2.981459,4.273757 C 38.893916,43.179918 38.196064,54.230597 35.561493,62.547558 32.317231,72.815487 27.62103,79.774991 25.056491,83.084437 23.922089,84.551384 21.979385,85.109954 20.226181,84.51727 15.909693,83.067568 7.8389298,79.104583 2.5612233,69.033294 -4.9583309,54.719483 5.3332491,37.699769 17.201466,33.823503 29.069683,29.947242 36.102519,33.502424 36.102519,33.502424"
|
||||
style="fill:#ffc107"
|
||||
id="path1" /><radialGradient
|
||||
id="a"
|
||||
cx="39.661999"
|
||||
cy="33.066002"
|
||||
r="15.102"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="rotate(-36,76.403023,62.749107)"><stop
|
||||
offset=".376"
|
||||
style="stop-color:#af5700"
|
||||
id="stop1" /><stop
|
||||
offset="1"
|
||||
style="stop-color:#8f4700"
|
||||
id="stop2" /></radialGradient><path
|
||||
d="m 24.58535,79.730898 c -0.658535,1.084127 -2.321358,0.598826 -2.308258,-0.65912 0.05175,-3.671637 0.673125,-10.080941 3.284076,-19.740415 2.833376,-10.476192 6.262826,-15.946756 8.408695,-18.556478 0.74373,-0.898813 2.194066,-0.382711 2.202328,0.785526 0.03421,3.806958 -0.400859,11.119194 -3.365803,19.985204 -2.872918,8.601374 -6.14462,14.748412 -8.221038,18.185283"
|
||||
style="fill:url(#a)"
|
||||
id="path2" /><path
|
||||
d="m 9.325047,44.72518 c 1.535965,1.331475 3.964078,0.420233 5.680907,-1.333904 1.861,-1.895966 4.313276,-4.134994 2.498971,-6.104764 -1.875295,-2.036707 -5.354133,0.626784 -6.611838,1.651807 -1.8350814,1.506315 -2.9283594,4.612077 -1.56804,5.786861"
|
||||
style="fill:#ffee58"
|
||||
id="path3" /><path
|
||||
d="m 48.054922,10.381219 c 7.783173,-9.63494661 24.411187,-16.6233057 39.437834,-1.9294759 5.709964,5.5793299 7.274599,13.0579489 7.689403,17.3547449 0.207787,2.123399 -0.923219,4.156466 -2.860926,5.045148 -3.782763,1.734764 -11.27732,4.349283 -23.251427,5.187589 -6.65392,0.471036 -16.927314,-0.569056 -22.835159,-1.282831 -2.669408,-0.322565 -4.627624,-2.694566 -4.388867,-5.37725 0.465691,-5.245536 1.889405,-13.646889 6.209142,-18.997925"
|
||||
style="fill:#ffc107"
|
||||
id="path4" /><radialGradient
|
||||
id="b"
|
||||
cx="90.500999"
|
||||
cy="31.969999"
|
||||
r="21.224001"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="rotate(-36,76.403023,62.749107)"><stop
|
||||
offset=".376"
|
||||
style="stop-color:#af5700"
|
||||
id="stop4" /><stop
|
||||
offset="1"
|
||||
style="stop-color:#8f4700"
|
||||
id="stop5" /></radialGradient><path
|
||||
d="m 50.331875,31.940273 c -0.879985,-0.139376 -1.017628,-1.349604 -0.184465,-1.682995 3.654704,-1.468722 10.622011,-3.873226 17.984713,-4.389462 7.556785,-0.521332 16.398675,0.607035 20.982404,1.318705 0.902045,0.135709 1.019073,1.385634 0.154302,1.692544 -3.939955,1.416344 -11.446832,3.656632 -20.258529,3.964888 -8.955794,0.31407 -15.304041,-0.376387 -18.678425,-0.90368"
|
||||
style="fill:url(#b)"
|
||||
id="path5" /><path
|
||||
d="m 52.293787,17.338376 c -2.466763,3.324934 -5.004693,1.720219 -4.543772,-1.235126 0.330395,-2.13123 3.91154,-8.1075506 9.091506,-10.4371771 3.421685,-1.534228 7.46144,2.0695183 3.237676,5.0517381 -2.877129,2.028553 -4.763201,2.545979 -7.78541,6.620565"
|
||||
style="fill:#ffee58"
|
||||
id="path6" /><path
|
||||
d="M 137.28037,89.346941 C 122.60573,90.33027 106.8948,82.894884 95.24954,69.452536 84.730746,57.30544 78.341734,41.910669 73.212902,29.543377 l 6.888164,-1.407586 c 4.912932,11.831952 11.519209,24.905756 21.190764,36.073876 10.0037,11.557209 23.26391,17.967263 35.44975,17.148166 z m -41.620109,26.827219 -6.954712,-3.95805 c 2.122879,-3.7302 0.93592,-9.20885 -2.540451,-11.71392 C 84.469543,99.274316 82.22013,98.56008 79.849426,97.797999 77.914637,97.176553 75.90413,96.535956 73.932752,95.557915 68.783063,92.995436 64.687891,88.430737 62.715686,83.028172 61.722979,80.300787 61.298605,77.556027 60.896975,74.893623 60.44258,71.886378 60.009415,69.061477 58.779752,66.790546 57.637498,64.690962 55.709106,62.98949 53.475937,62.127487 51.457404,61.356752 49.068048,61.164455 46.542678,60.972092 44.62678,60.818987 42.638831,60.668787 40.620866,60.256104 35.843172,59.277457 32.286031,56.559139 29.48672,52.672192 l 3.265999,-4.98099 c 0,0 4.014659,3.807389 6.390416,4.763568 2.491167,0.995936 5.119561,0.98984 7.764767,1.194022 2.990739,0.237433 6.335428,-0.177836 9.44555,1.023522 3.981189,1.532618 7.431574,4.563349 9.470736,8.322743 1.895183,3.493176 2.451456,7.168044 2.991613,10.718655 0.362067,2.369769 0.702136,4.607191 1.426109,6.59041 1.279079,3.49582 3.924434,6.456325 7.263724,8.109211 1.433326,0.713844 3.061577,1.236625 4.799359,1.791072 2.868369,0.919654 5.826423,1.860669 8.556805,3.832351 6.800607,4.885808 8.961795,14.835764 4.798463,22.137404"
|
||||
style="fill:#03a9f4"
|
||||
id="path7" /><path
|
||||
d="M 58.691248,150.47484 51.073376,148.0369 C 62.55028,112.23302 46.036873,84.009068 34.560096,71.853426 l 3.79906,-5.046904 c 12.691473,13.43623 33.064396,43.961048 20.332092,83.668318"
|
||||
style="fill:#f48fb1"
|
||||
id="path8" /><path
|
||||
d="m 97.620499,60.449496 0.669771,0.02017 c -1.982355,-2.626399 -3.798481,-5.398291 -5.475623,-8.234078 -3.478925,-0.228845 -6.906275,-0.692934 -10.008304,-1.900166 -0.08747,-0.03533 -0.166856,-0.07654 -0.254331,-0.111875 1.67916,3.229864 3.502421,6.453919 5.521299,9.572927 3.27958,0.447844 6.526233,0.561147 9.547188,0.653023"
|
||||
style="fill:#0076c6"
|
||||
id="path9" /><path
|
||||
d="m 126.73434,66.478192 -7.85431,1.540936 C 118.03737,63.71183 113.9561,60.731533 110.42624,59.377789 105.8364,57.619906 100.49441,57.44678 95.322258,57.286238 89.772205,57.115958 83.488416,56.922535 77.588683,54.620701 66.745548,50.397593 60.478454,39.883235 60.789127,28.24861 l 6.610692,-0.785728 c -0.217215,8.377668 5.287795,16.652199 13.088438,19.69898 4.61114,1.804214 9.927403,1.958943 15.077505,2.123151 5.564028,0.172491 11.861768,0.368127 17.720378,2.613328 7.06558,2.715586 12.22337,8.300539 13.4482,14.579851 M 39.404781,126.51528 c -6.197945,-5.97879 -3.762421,-13.17465 -2.455564,-17.04125 0.159027,-0.46163 0.349719,-1.03281 0.466083,-1.45109 -0.441598,-0.55677 -1.353056,-0.99467 -2.968727,-1.68727 -2.66093,-1.14453 -6.30537,-2.72404 -7.608261,-7.154325 -1.129658,-3.851593 1.306962,-7.166986 2.552239,-9.87639 1.061286,-2.316156 1.470371,-4.492196 0.624607,-7.017326 -0.987455,-2.941333 -5.88644,-8.578358 -5.88644,-8.578358 l 2.272814,-5.174091 c 0,0 5.42504,4.846923 7.552823,7.775563 6.030677,8.300515 2.967367,13.764638 1.819236,16.267496 -0.796326,1.72811 -1.549232,3.362866 -1.260026,4.339369 0.209195,0.71326 0.956704,1.146659 3.114849,2.075527 2.587425,1.111415 6.130424,2.653375 7.592969,6.844055 0.715127,2.0391 0.03629,4.06501 -0.688182,6.19827 -1.27961,3.78501 -1.944044,6.44323 0.42961,8.72353 z M 86.776618,79.329039 c -3.379718,1.404851 -6.591734,1.118048 -9.413403,0.943195 l 0.499352,-7.98934 c 0,0 3.045462,1.112365 6.986114,-0.217961 z m -31.65598,-32.648363 -6.820905,0.666517 -0.516714,-7.992766 6.828995,-0.672395 z m 57.270102,52.727557 -9.35741,0.680007 0.955,-9.148554 8.40812,1.109768 z"
|
||||
style="fill:#f44336"
|
||||
id="path10" /><path
|
||||
d="m 101.42396,41.377903 -0.0146,-7.999991 8.58997,-0.01574 0.0147,7.999983 z"
|
||||
style="fill:#fb8c00"
|
||||
id="path11" /><path
|
||||
d="m 54.036615,71.967132 -8.580053,0.201761 0.10658,-6.097084 8.571961,-0.195882 z"
|
||||
style="fill:#f44336"
|
||||
id="path12" /><path
|
||||
d="m 65.959428,73.848361 c 0,0 1.070873,-0.839838 2.632081,-1.56622 -0.423682,-2.65874 -0.954698,-5.363111 -2.120956,-7.989121 -1.959013,0.842358 -3.174884,2.010031 -3.174884,2.010031 z"
|
||||
style="fill:#0076c6"
|
||||
id="path13" /><path
|
||||
d="m 74.189518,69.030755 c -3.656086,-0.285538 -7.326183,2.591072 -7.326183,2.591072 l -2.67184,-7.539434 c 0,0 3.751323,-3.615465 8.700361,-2.724225 z"
|
||||
style="fill:#fb8c00"
|
||||
id="path14" /><path
|
||||
d="m 39.248262,133.69831 5.610358,-4.6235 5.08776,6.1737 -5.610358,4.6235 z"
|
||||
style="fill:#fb8c00"
|
||||
id="path15" /><path
|
||||
d="m 69.596211,109.91973 -7.573684,-2.58129 c 0.803984,-2.36406 1.311734,-4.84664 1.499672,-7.344067 l 7.979731,0.605217 a 38.2,38.2 0 0 1 -1.905719,9.32014"
|
||||
style="fill:#fb8c00"
|
||||
id="path16" /><path
|
||||
d="m 80.507028,124.8351 c -3.105462,-0.19118 -6.241886,-0.18679 -9.337233,0.0102 l -0.510837,-7.98468 c 3.4218,-0.22409 6.894215,-0.22536 10.33345,-0.0171 z"
|
||||
style="fill:#f44336"
|
||||
id="path17" /><path
|
||||
d="m 95.856542,70.049822 c 2.172094,2.513265 3.88654,4.20949 6.307348,6.28248 l 1.77718,-6.519768 -7.917953,-2.170461 z"
|
||||
style="fill:#0076c6"
|
||||
id="path18" /><path
|
||||
d="m 91.996028,79.163831 2.722156,-9.964875 7.717236,2.108154 -2.722159,9.964877 z"
|
||||
style="fill:#ffc107"
|
||||
id="path19" /><path
|
||||
d="m 113.32155,113.19394 c -2.64324,-1.25626 -5.38874,-2.36409 -8.16299,-3.2903 l 2.53349,-7.58841 a 79,79 0 0 1 9.06345,3.66201 z"
|
||||
style="fill:#fb8c00"
|
||||
id="path20" /></svg>
|
After Width: | Height: | Size: 9.6 KiB |
102
auth-media-cert-gen/res/party.svg
Normal file
102
auth-media-cert-gen/res/party.svg
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xml:space="preserve"
|
||||
viewBox="0 0 128.43089 126.50923"
|
||||
version="1.1"
|
||||
id="svg18"
|
||||
sodipodi:docname="party.svg"
|
||||
width="128.43089"
|
||||
height="126.50923"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 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="defs18" /><sodipodi:namedview
|
||||
id="namedview18"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="6.4375"
|
||||
inkscape:cx="67.184466"
|
||||
inkscape:cy="60.893204"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1032"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg18" /><path
|
||||
d="M 0.33214338,109.12986 C 2.140482,111.94667 12.093386,109.34546 19.958618,107.23925 25.85088,105.66857 49.2214,100.56934 60.872169,97.841032 64.017581,97.106062 68.560207,96.221441 72.33318,92.733623 75.683329,89.628192 85.576723,75.674169 73.779987,57.692505 61.808268,39.436285 45.870065,41.083673 39.489089,44.101476 35.733835,45.876347 32.076328,50.724886 30.377634,53.217785 23.199449,63.751335 12.145966,83.42074 7.6987152,91.13569 4.4311846,96.824719 -1.4599719,106.33623 0.33214338,109.12986"
|
||||
style="fill:#ffc107"
|
||||
id="path1" /><path
|
||||
d="m 28.31235,56.407612 c -0.164275,1.737876 -0.311016,4.585659 -0.07563,10.16124 0.158098,3.825572 0.79704,7.918706 1.420731,10.658635 1.867602,8.239483 5.842614,12.128824 9.984377,15.418004 7.036767,5.586801 12.186266,7.307131 12.186266,7.307131 l -6.798857,1.471748 c 0,0 -3.700094,-1.474918 -8.484314,-4.978921 -4.558854,-3.342415 -9.024106,-8.425015 -11.387658,-17.249505 -1.021231,-3.825452 -1.372204,-7.421022 -1.444423,-10.236334 -0.08564,-3.48786 0.142907,-5.417489 0.142907,-5.417489 z M 17.000935,75.005956 c 0,0 -0.33913,6.530322 3.517261,15.526652 4.521044,10.524962 12.885179,13.594012 12.885179,13.594012 l -6.158183,1.35117 c 0,0 -6.06554,-3.09022 -10.694172,-12.486726 C 13.664788,87.130845 13.695179,80.739017 13.695179,80.739017 Z M 8.8645436,89.188552 c 0,0 0.4653897,5.768451 2.8909254,10.44062 2.885613,5.575788 7.410141,7.845958 7.410141,7.845958 l -4.745914,1.17371 c 0,0 -3.215208,-1.28788 -6.0526991,-6.56071 C 6.209763,98.082672 6.1338746,93.906047 6.1338746,93.906047 Z"
|
||||
style="fill:#ff8f00"
|
||||
id="path2" /><g
|
||||
style="opacity:0.44"
|
||||
id="g3"
|
||||
transform="rotate(10,84.702281,75.521203)"><path
|
||||
d="m 9.96,116.37 c -0.2,-0.45 -0.2,-0.96 0.01,-1.4 l 25.47,-52.82 4.19,15.75 -26.8,38.71 c -0.72,1.08 -2.34,0.94 -2.87,-0.24"
|
||||
style="fill:#fffde7"
|
||||
id="path3" /></g><linearGradient
|
||||
id="a"
|
||||
x1="74.384003"
|
||||
x2="44.617001"
|
||||
y1="61.839001"
|
||||
y2="79.698997"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="rotate(10,84.702281,75.521203)"><stop
|
||||
offset=".024"
|
||||
style="stop-color:#8f4700"
|
||||
id="stop3" /><stop
|
||||
offset="1"
|
||||
style="stop-color:#703e2d"
|
||||
id="stop4" /></linearGradient><path
|
||||
d="M 40.972388,75.597543 C 50.274417,91.37248 63.92071,92.011848 68.973435,89.328478 74.037743,86.636997 79.65986,75.311202 70.367132,59.771453 60.625934,43.492599 46.069317,45.07897 42.330382,47.567518 38.591448,50.056065 32.435774,61.125311 40.972388,75.597543"
|
||||
style="fill:url(#a)"
|
||||
id="path4" /><path
|
||||
d="M 80.226477,88.337493 C 76.584491,83.99916 74.196714,84.238157 70.919803,84.97025 66.692317,85.910439 60.284288,86.029505 52.375873,81.700455 l 3.605838,-5.649684 c 4.696037,2.564417 8.45441,2.384315 11.900973,1.09319 4.434771,-1.655053 10.501303,-3.926111 17.783537,4.760399 3.037113,3.622423 6.339981,6.255969 9.178414,5.822269 2.064528,-0.306149 3.610837,-3.029002 4.540859,-5.251267 0.08571,-0.198127 0.26868,-0.775119 0.419801,-1.286649 1.109995,-3.530893 3.273135,-11.191652 9.786785,-14.1556 6.96603,-3.168497 13.4953,-2.017208 13.4953,-2.017208 l -0.88812,11.947287 c -2.92551,-0.972792 -5.12096,-0.730347 -7.05569,-0.06622 -7.28878,2.52264 -4.00849,17.723191 -15.179587,20.66809 -10.751122,2.866628 -17.47097,-6.533056 -19.737506,-9.227572"
|
||||
style="fill:#03a9f4"
|
||||
id="path5" /><path
|
||||
d="M 46.309865,66.922595 42.711291,62.338059 C 52.105677,54.957246 51.17324,48.151942 50.49305,43.198577 50.354458,42.19933 50.226885,41.252796 50.190848,40.363021 50.056015,37.211732 50.383519,34.548136 50.996665,32.280152 48.644753,27.996671 48.00812,23.832863 47.966371,23.551337 47.112268,17.683883 49.444327,12.520397 53.499848,8.0060469 61.705874,-1.1582171 73.277363,0.8821445 73.277363,0.8821445 L 75.316237,11.89348 C 72.402348,11.257831 62.754729,9.7090089 58.97895,13.846204 c -4.767366,5.211329 -2.954219,9.267806 -2.849886,9.712682 0.883875,-0.808805 1.744606,-1.428759 2.497031,-1.895189 5.455234,-3.353657 9.65796,-3.232013 12.226024,-2.535492 2.887843,0.78337 5.286352,2.729432 6.759856,5.4872 1.609094,3.025379 1.856373,6.633127 0.642612,9.658319 -1.18017,2.949881 -3.675417,5.180474 -7.028161,6.285058 -5.854559,1.932728 -10.23643,0.753915 -13.045013,-0.766894 0.0076,0.0724 0.0035,0.15293 0.01104,0.22534 0.02151,0.511505 0.116609,1.239073 0.232004,2.081916 0.791517,5.704104 2.520797,14.843234 -12.114594,24.823448 m 13.75536,-35.683518 c 0.498255,0.514335 1.038211,0.964943 1.615228,1.320544 1.922233,1.191899 4.226063,1.313808 7.02967,0.386562 1.649149,-0.541861 1.979224,-1.377235 2.08867,-1.652411 0.328341,-0.825527 0.225646,-1.970757 -0.27035,-2.901019 -0.434577,-0.817889 -1.018564,-1.306724 -1.78267,-1.522689 -1.454638,-0.388498 -3.618763,0.194563 -5.932226,1.624559 -1.106337,0.688344 -2.020899,1.613589 -2.748322,2.744454"
|
||||
style="fill:#f44336"
|
||||
id="path6" /><path
|
||||
d="m 63.132929,71.544101 -6.086135,-1.245773 c 0,0 5.798161,-15.894635 15.68929,-16.993757 1.853103,-0.20127 3.87536,-0.382868 5.865789,-0.326375 1.183481,0.0259 3.052261,0.08125 4.007476,-0.09556 0.479438,-1.509683 0.176761,-3.593906 -0.157816,-5.95792 -0.265571,-1.833976 -0.542149,-3.720667 -0.513464,-5.726155 0.0597,-3.90902 1.666194,-7.088356 4.526439,-8.97027 3.488712,-2.278812 8.48214,-2.322376 13.719172,-0.119504 2.98697,1.257788 5.01242,3.188839 6.79511,4.884157 2.54687,2.429165 4.05899,3.701063 8.00309,1.949337 4.77126,-2.12374 1.18205,-14.362943 -0.63613,-21.385356 l 11.87206,-2.658831 c 0.91402,3.512075 5.14472,21.500004 -1.27486,30.207546 -2.16147,2.92916 -5.28417,4.571869 -9.02922,4.73401 -8.14816,0.370718 -12.19906,-3.491386 -15.15496,-6.307457 -1.399742,-1.333316 -2.642451,-2.4054 -4.072805,-3.104395 -9.942353,-4.829849 1.956337,13.149483 -6.108824,18.865827 -4.837707,3.421928 -15.065647,2.745594 -15.743405,2.788548 -6.734702,0.416865 -11.700808,9.461925 -11.700808,9.461925"
|
||||
style="fill:#f48fb1"
|
||||
id="path7" /><path
|
||||
d="m 50.986817,32.278416 c -0.56914,2.133584 -0.885251,3.408054 -0.820544,6.323583 2.357452,2.466844 8.25645,3.506997 8.25645,3.506997 -0.115391,-0.842844 -0.220347,-1.572148 -0.232003,-2.081916 -0.0076,-0.0724 -0.0035,-0.152931 -0.01104,-0.22534 -5.469588,-4.051334 -7.192864,-7.523324 -7.192864,-7.523324"
|
||||
style="fill:#c92b27"
|
||||
id="path8" /><path
|
||||
d="m 37.005678,39.815116 -9.302516,-6.788497 6.363703,-6.432682 7.0543,6.696705 z"
|
||||
style="fill:#ffc107"
|
||||
id="path9" /><path
|
||||
d="M 24.435228,23.342017 C 19.358733,21.725941 14.838411,16.379776 14.345936,15.775071 l 6.168669,-5.096245 c 1.315197,1.582421 4.207372,4.356791 6.351398,5.039469 z"
|
||||
style="fill:#fb8c00"
|
||||
id="path10" /><path
|
||||
d="M 35.928366,11.832931 28.876212,8.0610329 C 30.194898,5.5925184 30.919775,2.8060592 30.957617,0 l 8.000515,0.1211146 c -0.05794,4.0717987 -1.107041,8.1211433 -3.029766,11.7118164"
|
||||
style="fill:#03a9f4"
|
||||
id="path11" /><path
|
||||
d="m 83.702688,14.21982 7.993335,-0.326495 0.430974,10.551201 -7.993335,0.326495 z"
|
||||
style="fill:#fb8c00"
|
||||
id="path12" /><path
|
||||
d="m 102.37053,19.994485 -4.407543,-6.676799 c 3.310303,-2.188418 4.580203,-5.5895751 4.587153,-5.6289671 l 7.55597,2.6422231 c -0.20787,0.603064 -2.18538,6.001691 -7.73558,9.663543"
|
||||
style="fill:#ffc107"
|
||||
id="path13" /><path
|
||||
d="m 100.02783,50.866597 7.25978,-0.937082 1.02413,7.934177 -7.25978,0.937082 z"
|
||||
style="fill:#fb8c00"
|
||||
id="path14" /><path
|
||||
d="m 90.841481,114.69114 -7.665994,-2.30623 c 0.826259,-2.72796 -0.649125,-6.51163 -1.086607,-7.37066 l 7.136285,-3.61572 c 0.363308,0.70377 3.468004,7.11022 1.616316,13.29261"
|
||||
style="fill:#f44336"
|
||||
id="path15" /><path
|
||||
d="m 115.07559,108.66784 c -2.86644,-0.96237 -5.84869,-1.67101 -8.84191,-2.08709 l 1.12329,-7.925348 c 3.47751,0.49133 6.93884,1.30474 10.2641,2.429248 z"
|
||||
style="fill:#fb8c00"
|
||||
id="path16" /><path
|
||||
d="m 102.57033,117.64484 6.52394,-4.63015 6.29121,8.86439 -6.52393,4.63015 z"
|
||||
style="fill:#f48fb1"
|
||||
id="path17" /><path
|
||||
d="m 95.09196,64.977986 4.544606,7.51232 -7.51232,4.544606 -4.544606,-7.51232 z"
|
||||
style="fill:#f44336"
|
||||
id="path18" /></svg>
|
After Width: | Height: | Size: 9 KiB |
10
auth-media-cert-gen/res/unauth.typ
Normal file
10
auth-media-cert-gen/res/unauth.typ
Normal file
|
@ -0,0 +1,10 @@
|
|||
#set page(
|
||||
width: 11cm,
|
||||
height: 5cm,
|
||||
fill: red.lighten(90%),
|
||||
)
|
||||
#set text(font: "Comic Neue", weight: "bold", size: 2.2em, fill: gray.darken(70%))
|
||||
#set align(center)
|
||||
#set par(leading: 0.5em)
|
||||
|
||||
Unfortunately, your server does not support authenticated media as of #datetime.today().display().
|
161
auth-media-cert-gen/src/lib.rs
Normal file
161
auth-media-cert-gen/src/lib.rs
Normal file
|
@ -0,0 +1,161 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use comemo::Prehashed;
|
||||
use time::OffsetDateTime;
|
||||
use typst::{
|
||||
diag::{FileError, FileResult},
|
||||
eval::Tracer,
|
||||
foundations::{Bytes, Datetime, IntoValue},
|
||||
syntax::{FileId, Source, VirtualPath},
|
||||
text::{Font, FontBook},
|
||||
visualize::Color,
|
||||
Library, World,
|
||||
};
|
||||
|
||||
const EMBEDDED_FONTS: &[&[u8]] = &[
|
||||
include_bytes!("../res/ComicNeue-Bold.ttf"),
|
||||
include_bytes!("../res/NotoColorEmoji.ttf"),
|
||||
];
|
||||
|
||||
const AUTH_SOURCE: &str = include_str!("../res/auth.typ");
|
||||
const UNAUTH_SOURCE: &str = include_str!("../res/unauth.typ");
|
||||
|
||||
const FILE_SOURCES: &[(&str, &[u8])] = &[
|
||||
("confetti.svg", include_bytes!("../res/confetti.svg")),
|
||||
("party.svg", include_bytes!("../res/party.svg")),
|
||||
];
|
||||
|
||||
fn get_fonts() -> (FontBook, Vec<Font>) {
|
||||
let mut book = FontBook::new();
|
||||
let mut fonts = vec![];
|
||||
for font in EMBEDDED_FONTS
|
||||
.iter()
|
||||
.flat_map(|data| Font::iter(Bytes::from_static(data)))
|
||||
{
|
||||
book.push(font.info().clone());
|
||||
fonts.push(font);
|
||||
}
|
||||
|
||||
(book, fonts)
|
||||
}
|
||||
|
||||
/// A minimal world that generates Authenticated Media certificates
|
||||
pub struct AuthMediaWorld {
|
||||
/// The name of the server issuing the certificate
|
||||
issuer: String,
|
||||
/// File ID of the authenticated source
|
||||
auth_id: FileId,
|
||||
/// File ID of the unauthenticated source
|
||||
unauth_id: FileId,
|
||||
/// True if the authenticated source should be used
|
||||
is_authenticated: bool,
|
||||
/// Typst's standard library.
|
||||
library: Prehashed<Library>,
|
||||
/// Metadata about discovered fonts.
|
||||
book: Prehashed<FontBook>,
|
||||
/// Locations of and storage for lazily loaded fonts.
|
||||
fonts: Vec<Font>,
|
||||
/// Maps file ids to source files and buffers.
|
||||
slots: HashMap<FileId, (Bytes, Option<Source>)>,
|
||||
/// The current datetime if requested. This is stored here to ensure it is
|
||||
/// always the same within one compilation. Reset between compilations.
|
||||
now: Datetime,
|
||||
}
|
||||
|
||||
impl AuthMediaWorld {
|
||||
#[must_use]
|
||||
pub fn new(issuer: String) -> Self {
|
||||
let auth_id = FileId::new_fake(VirtualPath::new("<auth>"));
|
||||
let unauth_id = FileId::new_fake(VirtualPath::new("<unauth>"));
|
||||
|
||||
let mut slots = HashMap::new();
|
||||
for &(name, data) in FILE_SOURCES {
|
||||
let id = FileId::new(None, VirtualPath::new(format!("/{name}")));
|
||||
let bytes = data.into();
|
||||
let source = std::str::from_utf8(data)
|
||||
.ok()
|
||||
.map(|s| Source::new(id, s.to_owned()));
|
||||
slots.insert(id, (bytes, source));
|
||||
}
|
||||
|
||||
let library = Library::builder().build();
|
||||
|
||||
let (book, fonts) = get_fonts();
|
||||
let now = Datetime::Date(OffsetDateTime::now_utc().date());
|
||||
|
||||
Self {
|
||||
issuer,
|
||||
auth_id,
|
||||
unauth_id,
|
||||
is_authenticated: false,
|
||||
library: Prehashed::new(library),
|
||||
book: Prehashed::new(book),
|
||||
fonts,
|
||||
slots,
|
||||
now,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate(&mut self, target: Option<&str>) -> Option<Vec<u8>> {
|
||||
let mut inputs =
|
||||
vec![("issuer".into(), self.issuer.as_str().into_value())];
|
||||
if let Some(target) = target {
|
||||
inputs.push(("target".into(), target.into_value()));
|
||||
}
|
||||
let library = Library::builder()
|
||||
.with_inputs(inputs.into_iter().collect())
|
||||
.build();
|
||||
self.library.update(|old| *old = library);
|
||||
self.is_authenticated = target.is_some();
|
||||
|
||||
let mut tracer = Tracer::new();
|
||||
let document = typst::compile(self, &mut tracer).unwrap();
|
||||
if document.pages.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
typst_render::render(&document.pages[0].frame, 2.0, Color::WHITE)
|
||||
.encode_png()
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl World for AuthMediaWorld {
|
||||
fn library(&self) -> &Prehashed<Library> {
|
||||
&self.library
|
||||
}
|
||||
|
||||
fn book(&self) -> &Prehashed<FontBook> {
|
||||
&self.book
|
||||
}
|
||||
|
||||
fn main(&self) -> Source {
|
||||
if self.is_authenticated {
|
||||
Source::new(self.auth_id, AUTH_SOURCE.to_owned())
|
||||
} else {
|
||||
Source::new(self.unauth_id, UNAUTH_SOURCE.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
fn source(&self, id: FileId) -> FileResult<Source> {
|
||||
let (_bytes, source) = self.slots.get(&id).ok_or(
|
||||
FileError::NotFound(id.vpath().as_rooted_path().to_owned()),
|
||||
)?;
|
||||
Ok(source.as_ref().ok_or(FileError::NotSource)?.clone())
|
||||
}
|
||||
|
||||
fn file(&self, id: FileId) -> FileResult<Bytes> {
|
||||
let (bytes, _source) = self.slots.get(&id).ok_or(
|
||||
FileError::NotFound(id.vpath().as_rooted_path().to_owned()),
|
||||
)?;
|
||||
Ok(bytes.clone())
|
||||
}
|
||||
|
||||
fn font(&self, index: usize) -> Option<Font> {
|
||||
self.fonts.get(index).cloned()
|
||||
}
|
||||
|
||||
fn today(&self, offset: Option<i64>) -> Option<Datetime> {
|
||||
assert_eq!(offset, None, "today offset not supported");
|
||||
Some(self.now)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use axum::response::IntoResponse;
|
||||
use axum_extra::headers::ContentType;
|
||||
use http::{
|
||||
header::{CONTENT_DISPOSITION, CONTENT_SECURITY_POLICY, CONTENT_TYPE},
|
||||
HeaderName, HeaderValue, Method,
|
||||
|
@ -449,6 +450,24 @@ async fn get_content_route_ruma(
|
|||
) -> Result<authenticated_media_client::get_content::v1::Response> {
|
||||
let mxc = MxcData::new(&body.server_name, &body.media_id)?;
|
||||
|
||||
if body.media_id.starts_with("auth_media_cert") {
|
||||
let Some(file) = services().media.generate_auth_media_cert(None).await
|
||||
else {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::NotYetUploaded,
|
||||
"Failed to generate authenticated media certificate",
|
||||
));
|
||||
};
|
||||
|
||||
return Ok(authenticated_media_client::get_content::v1::Response {
|
||||
file,
|
||||
content_type: Some(ContentType::png().to_string()),
|
||||
content_disposition: Some(ContentDisposition::new(
|
||||
ContentDispositionType::Inline,
|
||||
)),
|
||||
});
|
||||
}
|
||||
|
||||
if let Some((
|
||||
FileMeta {
|
||||
content_type,
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::{
|
|||
};
|
||||
|
||||
use axum::{response::IntoResponse, Json};
|
||||
use axum_extra::headers::{Authorization, HeaderMapExt};
|
||||
use axum_extra::headers::{Authorization, ContentType, HeaderMapExt};
|
||||
use base64::Engine as _;
|
||||
use get_profile_information::v1::ProfileField;
|
||||
use ruma::{
|
||||
|
@ -55,6 +55,7 @@ use ruma::{
|
|||
},
|
||||
StateEventType, TimelineEventType,
|
||||
},
|
||||
http_headers::ContentDisposition,
|
||||
serde::{Base64, JsonObject, Raw},
|
||||
server_util::authorization::XMatrix,
|
||||
state_res::Event,
|
||||
|
@ -62,7 +63,7 @@ use ruma::{
|
|||
uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId,
|
||||
MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedServerName,
|
||||
OwnedServerSigningKeyId, OwnedSigningKeyId, OwnedUserId, RoomId,
|
||||
ServerName,
|
||||
ServerName, UserId,
|
||||
};
|
||||
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
|
||||
use tokio::sync::RwLock;
|
||||
|
@ -1796,7 +1797,7 @@ pub(crate) async fn create_invite_route(
|
|||
Error::BadRequest(ErrorKind::InvalidParam, "sender is not a user id.")
|
||||
})?;
|
||||
|
||||
let invited_user: Box<_> = serde_json::from_value(
|
||||
let invited_user: Box<UserId> = serde_json::from_value(
|
||||
signed_event
|
||||
.get("state_key")
|
||||
.ok_or(Error::BadRequest(
|
||||
|
@ -2046,6 +2047,33 @@ pub(crate) async fn media_download_route(
|
|||
body: Ar<authenticated_media::get_content::v1::Request>,
|
||||
) -> Result<Ra<authenticated_media::get_content::v1::Response>> {
|
||||
let mxc = MxcData::new(services().globals.server_name(), &body.media_id)?;
|
||||
|
||||
if body.media_id.starts_with("auth_media_cert") {
|
||||
let Some(file) = services()
|
||||
.media
|
||||
.generate_auth_media_cert(body.sender_servername.as_deref())
|
||||
.await
|
||||
else {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::NotYetUploaded,
|
||||
"Failed to generate authenticated media certificate",
|
||||
));
|
||||
};
|
||||
|
||||
return Ok(Ra(authenticated_media::get_content::v1::Response {
|
||||
metadata: authenticated_media::ContentMetadata {},
|
||||
content: authenticated_media::FileOrLocation::File(
|
||||
authenticated_media::Content {
|
||||
file,
|
||||
content_type: Some(ContentType::png().to_string()),
|
||||
content_disposition: Some(ContentDisposition::new(
|
||||
ruma::http_headers::ContentDispositionType::Inline,
|
||||
)),
|
||||
},
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
let Some((
|
||||
crate::service::media::FileMeta {
|
||||
content_disposition,
|
||||
|
@ -2086,6 +2114,14 @@ pub(crate) async fn media_thumbnail_route(
|
|||
body: Ar<authenticated_media::get_content_thumbnail::v1::Request>,
|
||||
) -> Result<Ra<authenticated_media::get_content_thumbnail::v1::Response>> {
|
||||
let mxc = MxcData::new(services().globals.server_name(), &body.media_id)?;
|
||||
|
||||
if body.media_id.starts_with("auth_media_cert") {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::NotYetUploaded,
|
||||
"No thumbnails for authenticated media certificates",
|
||||
));
|
||||
}
|
||||
|
||||
let width = body.width.try_into().map_err(|_| {
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "Width is invalid.")
|
||||
})?;
|
||||
|
|
|
@ -145,9 +145,7 @@ impl Services {
|
|||
account_data: db,
|
||||
admin: admin::Service::build(),
|
||||
key_backups: db,
|
||||
media: media::Service {
|
||||
db,
|
||||
},
|
||||
media: media::Service::new(db),
|
||||
sending: sending::Service::build(db, &config),
|
||||
|
||||
globals: globals::Service::load(db, config, reload_handles)?,
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use std::io::Cursor;
|
||||
|
||||
use image::imageops::FilterType;
|
||||
use ruma::http_headers::ContentDisposition;
|
||||
use ruma::{http_headers::ContentDisposition, ServerName};
|
||||
use tokio::{
|
||||
fs::File,
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
sync::Mutex,
|
||||
};
|
||||
use tracing::{debug, warn};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::{services, Result};
|
||||
|
||||
|
@ -39,9 +40,17 @@ impl MediaFileKey {
|
|||
|
||||
pub(crate) struct Service {
|
||||
pub(crate) db: &'static dyn Data,
|
||||
cert_gen: Mutex<Option<auth_media_cert_gen::AuthMediaWorld>>,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub(crate) fn new(db: &'static dyn Data) -> Self {
|
||||
Self {
|
||||
db,
|
||||
cert_gen: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Uploads a file.
|
||||
#[tracing::instrument(skip(self, file))]
|
||||
pub(crate) async fn create(
|
||||
|
@ -287,4 +296,29 @@ impl Service {
|
|||
|
||||
Ok(Some((meta, thumbnail_bytes.clone())))
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub(crate) async fn generate_auth_media_cert(
|
||||
&self,
|
||||
target: Option<&ServerName>,
|
||||
) -> Option<Vec<u8>> {
|
||||
let mut cert_gen_lock = self.cert_gen.lock().await;
|
||||
let mut cert_gen = cert_gen_lock.take().unwrap_or_else(|| {
|
||||
auth_media_cert_gen::AuthMediaWorld::new(
|
||||
services().globals.server_name().to_string(),
|
||||
)
|
||||
});
|
||||
|
||||
let target = target.map(|s| s.to_string());
|
||||
let (file, cert_gen) = tokio::task::spawn_blocking(move || {
|
||||
info!(target, "generating authenticated media cert");
|
||||
(cert_gen.generate(target.as_deref()), cert_gen)
|
||||
})
|
||||
.await
|
||||
.ok()?;
|
||||
|
||||
*cert_gen_lock = Some(cert_gen);
|
||||
|
||||
file
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue