From 4dd92c0bdcfd8552f13e586a08237767dd4effb0 Mon Sep 17 00:00:00 2001 From: Micke Nordin Date: Tue, 24 Jun 2025 11:06:10 +0200 Subject: [PATCH] first commit Signed-off-by: Micke Nordin --- .gitignore | 2 + README.md | 0 app/__init__.py | 0 app/__pycache__/__init__.cpython-313.pyc | Bin 0 -> 138 bytes app/__pycache__/accept_invite.cpython-313.pyc | Bin 0 -> 2796 bytes app/__pycache__/crypto.cpython-313.pyc | Bin 0 -> 2647 bytes app/__pycache__/disco.cpython-313.pyc | Bin 0 -> 2108 bytes app/__pycache__/main.cpython-313.pyc | Bin 0 -> 1904 bytes app/__pycache__/root.cpython-313.pyc | Bin 0 -> 877 bytes app/__pycache__/token.cpython-313.pyc | Bin 0 -> 1724 bytes app/__pycache__/wayf.cpython-313.pyc | Bin 0 -> 1048 bytes app/accept_invite.py | 48 ++++++++++++++++ app/crypto.py | 54 ++++++++++++++++++ app/datatx.py | 10 ++++ app/disco.py | 31 ++++++++++ app/main.py | 43 ++++++++++++++ app/root.py | 11 ++++ app/token.py | 36 ++++++++++++ app/wayf.py | 14 +++++ server.conf | 3 + static/favicon.ico | Bin 0 -> 15406 bytes templates/discovery.yaml | 26 +++++++++ templates/error.html | 2 + templates/index.html | 24 ++++++++ templates/wayf.html | 17 ++++++ 25 files changed, 321 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 app/__init__.py create mode 100644 app/__pycache__/__init__.cpython-313.pyc create mode 100644 app/__pycache__/accept_invite.cpython-313.pyc create mode 100644 app/__pycache__/crypto.cpython-313.pyc create mode 100644 app/__pycache__/disco.cpython-313.pyc create mode 100644 app/__pycache__/main.cpython-313.pyc create mode 100644 app/__pycache__/root.cpython-313.pyc create mode 100644 app/__pycache__/token.cpython-313.pyc create mode 100644 app/__pycache__/wayf.cpython-313.pyc create mode 100644 app/accept_invite.py create mode 100644 app/crypto.py create mode 100644 app/datatx.py create mode 100644 app/disco.py create mode 100644 app/main.py create mode 100644 app/root.py create mode 100644 app/token.py create mode 100644 app/wayf.py create mode 100644 server.conf create mode 100644 static/favicon.ico create mode 100644 templates/discovery.yaml create mode 100644 templates/error.html create mode 100644 templates/index.html create mode 100644 templates/wayf.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a380dcd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +ed25519_private_key.pem +ed25519_public_key.pem diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/__pycache__/__init__.cpython-313.pyc b/app/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8371becefd84b67133deb279664f8c0449c5a81d GIT binary patch literal 138 zcmey&%ge<81m`pYGC=fW5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa~iRenx(7s(x-} za(1eIaeir0a%!=DVs2(hrG8>Tfqr~^W?p7Ve7s&kKD;74xn^EVGPFhlZ~kC9Lk+4lduc^dctI2V$k9JJ?QfR4%#7LLbS+V?MKS_b1Rj zMCZ|Gu9|f@ekcxwNpy!-xeRX#c_Akb)k8t$7w#aW!^%8L09u|)pl=+t(~)P3x6PS}!nE&4A-}@JwZwhQI;so<(*Hb5pC55*Y;~25zg+?V%%Hk^+a3 zbB~t3SgL!Pk<7lg}XSxl;q_)mN2=NK#(PMPAJeBz5G?I|R`juX;0ZUtk{2@MIh0$dpxo zUS0&oD2{<&N?(TBaP_cEp9VRQ2Rn8+%u-MMAN&sXy^~di;RccE$$QjLo`-V}A7hQ! zNzZ{v#$VS#yyA2K0m`wpZ@q2@+3^g{6m!5OuX6c@iq0voBLKf78Nd9`ne(s{u=xpK zwjoQM${G*ggloZ7!?uA5;slp12iF3Fv19FEvldRz+{2~P^p0uWGt*X~Tnn&%xf4{Z93W`u-@&yX6Pkrlgd3^Z7S#b9xqzhj+>Sfx2u(kMI3kko{e4eeCS5B zTnoQFaOs*=)(vwx6{6n47R0d&?CAT}r=Q+lVKKS9NLa3jA38dM2mEZ)&{fMcae zlIt(^6%D&!F`}j%p`ruNA`J{8(2BaFQ-$;~n3c_#f;|kZ5q8z7WPl_0>F9B4oN;xG zF>D*^U=RH>GqrQ?l0PS!8f&onN6@Y`5BbEBEL(avO>nQY^OTaDQ5ruX)~@{i!@c5v!R zka--u)bL(<@%#b`$J(LEW@xe{fcE{GQ$RAn#O)@7zIst9Ad0j;YSr1z6*0*_(yJy5LO9p$DT}^ap4cq zQz`Hx?fY7nKPSz01tgET5_x}Mn&O^8>7bO)-POG+RNgksZGD!oH=VHGC}e_l43)~( z`ZiR0Z!flg56Z1k?@}+q%VZHI7_6O!?nvM`?$0O$e}6^q{!KpBJexXrr*-zdru_b% W@LcwA(dW_g-0Xw*{)OP<0{$D^b#XBO literal 0 HcmV?d00001 diff --git a/app/__pycache__/crypto.cpython-313.pyc b/app/__pycache__/crypto.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e81bfbfb1796e86936e5b9335ec15e22f847a4a5 GIT binary patch literal 2647 zcmb7F%TF6e7@vLl{WgX`12_f;3<#1G5=cTGb;tuZ$g*)CqLQ`P3pl~M?yMm-Cyqo_ zRdR@wQ`JKb>8({O^<1TY01iovMvfGzz4YdWNRe{tH@jYNa31PNJ3ITmXXpFIioDiV*Q5(Lw<;E;^i8QWT#)i>t$T`< z`Q=>3kY|jFXk@4saq#RO1?gQhM`hYbG+G%lp}uH%jn&sOn_?3*+JUjB=Rj{gpoGsk z?axtp!qKcvxSC}R9-d}x!q+To@Mvk)hLBNXl9}LSKE);4nyngQ{Qo)+HOEVIG|Q6g z1S<jh0)3CNespyNA=xz7Y51f}NuC}?QW&eB6N_YX%ADvnEcV}EYofMe zj4spq4tme<45I7D5wfEoT0}?C5bCeHX2E`e4We$)fK3#kNv<0$FcI@igd-M7&M4WO zyhuz73eJl~(gG4(D$t%xi_41&&J~yP5f+;u9;TfUVF_Oli%W!q?!>eg2zzTD(*}rm zFzrI(ozlBJuD5bbDiO<~Bug0jn%D|^eN3E2v(J}`l8SliY?(4j;^I@+iL)N$vR|5Jy}~PH(2%! zR(zvn-{`jQDW-YA)o1fc<4}|JwpY%I-+TeXi_2R}+vgQbU~2 z1X&#@5Z>{3{VQ-@Q_X?`y*vI+_^_CE%_fg|gL~;hF5hO)=E9x9d&S4j-UrN%!}u;DJE#g9T*|>ehQ>?4*=)j{RaFR@-gqsM_b~+_)tCr@G{?& z(QbtLoSWODv$v70vHLwz0M9wE;hp4+91=6PACqs0`4&3t&*1;JBujkYO<}BH z;xTwp^NC5Nh=Az@fgtF1ki*6~NJ;}levZ(siQ>Q0~?;MZo`umi4aM*)5|*MbO~Y`?K$y8zNgWo| zQa&#gaW11@IbH9!*H6?FPh9)#;_Os9HuYsXesT6HamQ1ie0nXqC(tMs)4%%@q9lv- zpKm#vSF$V1(mDJw$SAR>L6~YB!!Xa#+&{F1JUhODb@vOtoeA!a`AeF}?TLKO$R@j3%zqs;AtjoZkCp?ZxEd&^f%%nK$pfeZSdmEEYkq zGTD_aT|nq>rua+j3*Gx5JVpvqxFRAw&JoVj10(=EP~-~&5egy^)6CBor9zMdK^7FT z7%GHGxDX+c!VnoML`gJ_)`SdN6EjGW7P;OnO7Id#ViO2#q0>kSuMIEqJr9XjxNPJl zQ@+Ut=+LscV-U-%Vbh_BYep3-P20h>o0e9_B+Jp5jftUEja|(#Eb}FcpB3n-3N|s( z9IR?)S+%tttlq}Wx@Hg>t-{e`EwLis`1Z=JWwp5cow{=6)^!?RS-pDm#uo!a7_O^V zA(jo-N$fNxdN0`??Prd<1oX#f4Y6)Pr#Ql|39{GmliLyWLyo>~VVWF&+qT#@DS^|- zmwiq`3QxinAuCexOT*T!mqV~y?|0Zc7y`<&>!JY5tmGLPkwJfR$^HbKaFirp@xRs{>Mkw&H1|Jm1o{q^K(;9Y$vCHx3-(w7EYhFsoUCr*sL>4W+w z-nJ>+rGUw=^78xd@CE$(O`&wg_sf&MG~jZ2Ap4RjmNLF9&-l`SEBtYEsWj``Wxv(F z0eA+jO7h$ZLtk7K6=5D^;G)L`MY=SI8e9!dqim1?DuhklDjQ~nN}Cp`Y0j?La5m>J z?hcpP4DDdj%r&)Ibyvt+dTn=@(GP8-Vrou<;4IGqlC)|)g)@SO&>9V%>SHl{o_cWAVN9o5G( z6+74lj46^tQQl)|e4+Raf zsAWsHS#|0DqOW*AJ5>e{oBgCg7t?*FoF=btTHc4sdio;?Q_#3qhVAaZU<#r)rqkv{aQ$!ErWRbql_*=vY?OrlD=y zGF7YLkOk&VsqmfP=b)>a1K(?-0aFGiFMyAnXC%+auus?Xl6DnCA40@@*UJea?*6ZNs z;$Pv$R+;bFvj)tD2@C&r?2fFwIt?#4tzohrvQ`x6;`=^#%>C*@ND`}J) MZ(aKr0rQIc4>u&*{Qv*} literal 0 HcmV?d00001 diff --git a/app/__pycache__/main.cpython-313.pyc b/app/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23b656063b1d8148555f20fea1048b61eed88569 GIT binary patch literal 1904 zcmb_dUvJY^6u-9bwe!bm%0O+BW~(U-$V1~!tPh(uq)7~Ei2x}^Vp@?Rp zstK%C6O|-Q3anLAl{8H=oG1XQ-^p0XFTV%CP5^L6Ujgf*fCgwt4XKoR$@e#2N=%ld z2-XM*m_}D!-ys~_BHP&GC%5h17SsASj)ObFcixU0U}r=oRFX-B{f}0dybm^x&uZ~a z9$NsYp^421TGBdCgDqpyTOHaaWsS#rXKkcoLwt*tygrKjKk+Fi;>*nB2T#P8o#8_# z;yX3Nr=E!K^bDV7K`UV;*Q7PcN`1jvdZI@@u*z&e(u_slI1{ti7GgBkwfq>z$jZds zWzCi4_he9ruN>>z$739$xVxsZf1mGi>@n73-v%gUZ-i+d(;ZC94)M0ad9%EWTdmb? zkL-FTaoS;q%he7gJMJc?kz|G`ZZQKslOZy9*+_W|?@`*zl@6klP4#bIaaw*{00It?(m1umjhbG?wJ>^pI$Hw&k`kBMI{}Mt69S+UxWvpT$V+b~fz*M=+omN2pD@UO@TWQ}z}FlvkW;T(DOYh-BhNuww_! zNVD(y0;t$)xE^z5InW?NcU#2S{v8~#%R%(1*(7ajwq0i%n?C7M2m7Yoc7vX2cRFU< zcD-_^7eNjv?+2cfe}=tbegZF`{>#mKH=n}70W3WDx(`d-a{b=*r*QEAF8+r0w8v*J z_u=P%ziZxK?!(Wft#D7>SNib$w3Sip7yGb0ZROW$eRyd)oW3`An7ednoI5P8|Ir;N z@`b_x$i~tD0hD_MAS%Am0m_UMd;kw~7oHcFpBv|27%PvohuWj;!|da=t51w?UnSAX zCj&(@3M2Or1SMv%9nC}xxywqt$Rj-s~W@pE$CC-pkz6DtDJoQV2Wn{0Ml_zFGC zw)_*|UuI&UNRspnWS@cLe_-JskP|-!F1}WaQgLtvK>gS7iIV>dCVsv)Pyj3l(zj*K BS1|wp literal 0 HcmV?d00001 diff --git a/app/__pycache__/root.cpython-313.pyc b/app/__pycache__/root.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3f0e92293af98ec8b75626cc111a8ab14aa0f50 GIT binary patch literal 877 zcmY*X&rcIU6rS1H-Im&B6@mdg&=65JMruqzNsNgHJ%HiR4Hs=PS;{~c_eXs@MJgA( zXgzu2&Qbpx2nTgEk;D@xHLG{uY+HkK_~x7UzJ2q)x06*WC4%e6izlr)O2~J87%po- zvSlO(#3LSEA)t3-g)SRlEHhwL(lBO7gUt|+Eno$`JadVHIYBUHO%cy-SPQJ50eg$O zg)@Cvbq#glVZ0MS5=SDI>f)my6ka!#B6^(o8v@h_(st-ek-AjbVIFMu3-!?$9J0Ge z4oHIl^#~Xq1=cX@xwG?f?97-V3xg2Y9)rS`=~~LHCy6}MewzaexyD4)jc2O}H~<>c zr+Gp{ePHQd0EuS|M-UrpMtwNIbCNacu_bzyxaO)Fc@QUYH%dC`%Tf?;h~4>?j6$?( zc2WT@Q%uA=s=Os69}YsC}VA9N*q(F`>9r|YPQx&B2kNi<}*=ClMXaR zTJxhoc58mST?4c_-|i|azfzU7_4%9^us}M8uuo2%sh;`O8U5%?A3M{B_%);Wat6 zDsT8J{>xz2wTuyaJkzZIk=DBfxPqIqw}W`wzYTh1p#L&d@^G@gEt;}l`v2=x@m}B6 xeW;>TzmoJi!cRsi{X(2?I7V;<0^apZzv%dabwkhv1gC@D~Z@%Z>m5 literal 0 HcmV?d00001 diff --git a/app/__pycache__/token.cpython-313.pyc b/app/__pycache__/token.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4549d61253d2181fc6140d0a6bd33265d0c51637 GIT binary patch literal 1724 zcmZuxJ#X7a7(PlQ^+Cx>L&>on*KutpwTjwuf;a_=z*C*2hEa$yU?4^gGp z7u9wgp}%-C8p<#jd<4M}GLRvCj%eg1Dovm{WW=VB5#Nce!nb_TcttA8Z+N(AaXT8r zc{KPQDo1DsQOQ6wW=J%?BbNn+QETL(nz>rxSvmLL+Ul^xv5ex8r%6DUx*s#-DYP%s zG-MiNipVmCO0$(jG0Bw2-ZSF9;Rm*)OFPIAbL4|Rz#O3`=Tqg_d3YX_dG|Y`oOq`I z=?I%EJxPvc|Brz=v?Z+$(YUcK;ELmO;}FF}BtsMzk+P*2@~7JfneQRAh058{x)*-? z{^}6(0x}dsU6B@0F|o-~R?Q)9fE}C3mS+=|u22*5pxGd7+_UP~41=miokKHlJQs@| zg;46z!|~Ad!$!lS0kLN?V^bF=3~D-*cH#^Gw@k zsS1JZxBx|!$v&y=u_QI0PDcJjAdsa{V1@zJ+mwd7u5^7!LU;lozCuNB&pcTcpt zJ^jYdYd@|1QasV`wKMnn`J3(cSKIo7cILqVHbhLNBnYW%jh+QBawWxO+koJR%Xs-J z@(vi=*GDogMg?R7C5B|cRWM{jS(f2~#6e=!NUTV%yd{Io$xWu3zP(qeGIf`jlu+l| z7@$ZWJSQ}0hK|=L$}D4AK%O5-!P0`d=o+NSi-tpqj~$m~DcOUt8nsakP_V4yereVm z8;d(ol-QU^&43JbRj3Yq7cw$MtS-Lx`MHIdbeuO`=PTwSoz8CtpYb1pd5L;juB**- zw3*{(S1Wb2Qh#=_H*=>qGuQiI>1|3WjJ4KJGblgV+UOUikG*z&xwYQYCt4eH5*D~Z zIVV_9&Y$iPf`3~U= z1A2qc%C=(#5o_?oyc!ko3K;tVyjTmHK|r0|FaY_m029FyT=Qd7Za8Lt9n9CLuVlZ$ zuW%3C(^pTs%5+DWK2c`g#x&)VK^&>KxG9{MjF4}>w zTa?8S=rxF$>h10mz$$j-v|J!z$%hdoYn1;Uxh_6G-DzBsq}M3-8fjg*ONC%h=$ z^g#5;QU99~4(ezkiC(ywRPVmoegsd<;mw=(e)D@D^QM){We}{{&8L+nM(C$FbeGyu zS}UL&BMVu06)~|(t9V6X(u&Mv1C^w4RFcP$CC>wcSeCMgnKFXFrj8*?E2;Bx+rzXn zHd7bkP%tIl|0vjVSs3^)jlB7Knnood~3&wBGIGWrSqOi+J)X9_1>YBDPe)V`_zi3}q~2 zvz6HQ4sKf^V-2Gb){TJDZNoO=aF+%k4cl>O6d7^Fjf|RIrqJ4y4;D}l`d&Z}5(coU z$rV%PG7a{4woGHveGjfN8o&#IQ;Ddz!?I8tS7LarNc6)n41OzL34NOPU1yi(qp;2( zY~J?WxRJMOwR{q(*5IlOMEg7=x<8xfDIkc%$Q`2d{=ql*zw5)F^@&q`;$-bizjO5P zi+!1gI2JVS^d zZr44bX9;;;x4n*MfRG)RMX~1wGzh_+b}G=`1|+P}{aP4NrUNA(A|#6K*mZ~<$IRWT z!>kg*hQY^%gt#t5x+}yaL?a+xp>s9&n!F?}NmFN9GSY?;t$j)0%@n%{8`r9CP_^$e z(N-pAk>wI|xK*W2+@}6N98WK|t9rl;fQmmEO@a6=V~oF{fgfn@t9I>l)ciPoHo9=C T-8+>3D1CV5XyGq{ElJ@YMlSK< literal 0 HcmV?d00001 diff --git a/app/accept_invite.py b/app/accept_invite.py new file mode 100644 index 0000000..ca48863 --- /dev/null +++ b/app/accept_invite.py @@ -0,0 +1,48 @@ +import cherrypy +import requests +from jinja2 import Environment, FileSystemLoader + +env = Environment(loader=FileSystemLoader('templates')) + + +def get_working_url(primary, fallback, timeout=1): + try: + response = requests.get(primary, timeout=timeout) + if response.status_code == 200: + return primary + except requests.RequestException: + pass + return fallback + + +class AcceptInvite(object): + + @cherrypy.expose + def index(self, remote=None, token=None): + if not remote: + raise cherrypy.HTTPError(400, "Missing remote") + if not token: + raise cherrypy.HTTPError(400, "Missing token") + disco_url = get_working_url(f'{remote}/.well-known/ocm', + f'{remote}/ocm-provider') + try: + r = requests.get(disco_url) + except requests.exceptions.ConnectionError: + tmpl = env.get_template('error.html') + return tmpl.render(message='Unable to reach OCM provider') + if r.status_code != 200: + tmpl = env.get_template('error.html') + return tmpl.render(message=f'Unable to reach OCM provider: {r.status_code}') + + provider_data = r.json() + + if ('capabilities' not in provider_data) or ( + 'inviteAcceptDialog' not in provider_data) or ( + 'capabilities' in provider_data + and 'invite' not in provider_data['capabilities']): + tmpl = env.get_template('error.html') + return tmpl.render(message='Remote does not support OCM invites') + redirect_url = f'{provider_data['inviteAcceptDialog']}' + redirect_url += f'?token={token}&providerDomain={cherrypy.request.base}' + + raise cherrypy.HTTPRedirect(redirect_url) diff --git a/app/crypto.py b/app/crypto.py new file mode 100644 index 0000000..ca4918d --- /dev/null +++ b/app/crypto.py @@ -0,0 +1,54 @@ +from cryptography.hazmat.primitives.asymmetric import ed25519 +from cryptography.hazmat.primitives import serialization + +PRIVATE_KEY_PATH = "ed25519_private_key.pem" +PUBLIC_KEY_PATH = "ed25519_public_key.pem" + +def generate_and_save_keypair(private_key_path, public_key_path): + private_key = ed25519.Ed25519PrivateKey.generate() + public_key = private_key.public_key() + + # Serialize the private key to PEM format without encryption + pem_private = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.NoEncryption(), + ) + + # Serialize the public key to PEM format + pem_public = public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo, + ) + + for key in [{ + 'path': private_key_path, + 'pem': pem_private + }, { + 'path': public_key_path, + 'pem': pem_public + }]: + with open(key["path"], "wb") as f: + f.write(key["pem"]) + + +def load_keypair(private_key_path, public_key_path): + # Load private key from PEM file + with open(private_key_path, "rb") as f: + private_key = serialization.load_pem_private_key( + f.read(), + password=None, + ) + + # Load public key from PEM file + with open(public_key_path, "rb") as f: + public_key = serialization.load_pem_public_key(f.read()) + + # Type check (optional but good for Ed25519-specific code) + if not isinstance(private_key, ed25519.Ed25519PrivateKey): + raise TypeError("The private key is not an Ed25519 key") + if not isinstance(public_key, ed25519.Ed25519PublicKey): + raise TypeError("The public key is not an Ed25519 key") + + return private_key, public_key + diff --git a/app/datatx.py b/app/datatx.py new file mode 100644 index 0000000..6e4e68d --- /dev/null +++ b/app/datatx.py @@ -0,0 +1,10 @@ +import cherrypy +from jinja2 import Environment, FileSystemLoader +env = Environment(loader=FileSystemLoader('templates')) + +class DataTx(object): + + @cherrypy.expose + def index(self): + tmpl = env.get_template('index.html') + return tmpl.render(salutation='Hello', target='World') diff --git a/app/disco.py b/app/disco.py new file mode 100644 index 0000000..1e13a93 --- /dev/null +++ b/app/disco.py @@ -0,0 +1,31 @@ +import cherrypy +import yaml +import os +from jinja2 import Environment, FileSystemLoader +from cryptography.hazmat.primitives import serialization +from .crypto import generate_and_save_keypair, load_keypair, PRIVATE_KEY_PATH, PUBLIC_KEY_PATH + +env = Environment(loader=FileSystemLoader('templates')) + + +class Disco(object): + + @cherrypy.expose + @cherrypy.tools.json_out() + def index(self): + if not os.path.exists(PRIVATE_KEY_PATH): + generate_and_save_keypair(PRIVATE_KEY_PATH, PUBLIC_KEY_PATH) + _, public_key = load_keypair(PRIVATE_KEY_PATH, PUBLIC_KEY_PATH) + pem_bytes = public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo, + ) + + pem_string = pem_bytes.decode('utf-8') + baseurl = cherrypy.request.base + tmpl = env.get_template('discovery.yaml') + yamldoc = yaml.safe_load( + tmpl.render(endpoint=baseurl + '/ocm', + public_key_id=baseurl + '/ocm#signature', + public_key_pem=pem_string)) + return yamldoc diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..bd753e5 --- /dev/null +++ b/app/main.py @@ -0,0 +1,43 @@ +import cherrypy +import os + +from .root import Root +from .disco import Disco +from .token import Token +from .wayf import Wayf +from .accept_invite import AcceptInvite + + +def main(): + + cherrypy.config.update("server.conf") + + cherrypy.tree.mount(Disco(), '/.well-known/ocm') + cherrypy.tree.mount(Disco(), '/ocm-provider') + cherrypy.tree.mount(Root(), '/') + cherrypy.tree.mount(Token(), '/ocm/token') + cherrypy.tree.mount(Wayf(), '/wayf') + # cherrypy.tree.mount(AcceptInvite(), '/accept-invite') + cherrypy.tree.mount(AcceptInvite(), + '/accept-invite', + config={'/': { + 'tools.trailing_slash.on': False + }}) + + cherrypy.tree.mount(None, + "/favicon.ico", + config={ + "/": { + "tools.staticfile.on": + True, + "tools.staticfile.filename": + os.path.abspath("static/favicon.ico") + } + }) + + cherrypy.engine.start() + cherrypy.engine.block() + + +if __name__ == '__main__': + main() diff --git a/app/root.py b/app/root.py new file mode 100644 index 0000000..afa2707 --- /dev/null +++ b/app/root.py @@ -0,0 +1,11 @@ +import cherrypy +from jinja2 import Environment, FileSystemLoader +env = Environment(loader=FileSystemLoader('templates')) + +class Root(object): + + @cherrypy.expose + def index(self): + user = 'Anonymous' + tmpl = env.get_template('index.html') + return tmpl.render(user=user) diff --git a/app/token.py b/app/token.py new file mode 100644 index 0000000..3be741f --- /dev/null +++ b/app/token.py @@ -0,0 +1,36 @@ +import cherrypy +import json + + +class Token(object): + + @cherrypy.expose + @cherrypy.tools.json_out() + def index(self): + raw_body = cherrypy.request.body.read() + data = json.loads(raw_body) + + client_id = data['client_id'] + code = data['code'] + grant_type = data['grant_type'] + + if grant_type == 'ocm_authorization_code': + return self.get_token(client_id, code) + else: + return {'error': 'unsupported grant_type'} + + def get_token(self, client_id, code) -> dict: + if self.validate_token(client_id, code): + token = { + "access_token": "asdfgh", + "token_type": "bearer", + "expires_in": 3600, + "refresh_token": "qwertyuiop" + } + return token + else: + error = {'error': 'invalid_grant'} + return error + + def validate_token(self, client_id, token) -> bool: + return True diff --git a/app/wayf.py b/app/wayf.py new file mode 100644 index 0000000..de2594a --- /dev/null +++ b/app/wayf.py @@ -0,0 +1,14 @@ +import cherrypy +from jinja2 import Environment, FileSystemLoader +env = Environment(loader=FileSystemLoader('templates')) + +class Wayf(object): + + @cherrypy.expose + def index(self,token=None): + if token is None: + tmpl = env.get_template('error.html') + return tmpl.render(message="Sorry you need a token to access this page") + else: + tmpl = env.get_template('wayf.html') + return tmpl.render(token=token) diff --git a/server.conf b/server.conf new file mode 100644 index 0000000..ec5e523 --- /dev/null +++ b/server.conf @@ -0,0 +1,3 @@ +[global] +server.socket_port: 9090 + diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4246ff95ed5b67c4a6b2d9363725af5a1e076881 GIT binary patch literal 15406 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 b<6q}r)~FHGAvqfTOFEZY;8F|J-2(psT!dr| literal 0 HcmV?d00001 diff --git a/templates/discovery.yaml b/templates/discovery.yaml new file mode 100644 index 0000000..86c6769 --- /dev/null +++ b/templates/discovery.yaml @@ -0,0 +1,26 @@ +enabled: true +apiVersion: "1.3.0" +endPoint: {{ endpoint }} +provider: mlog +resoureTypes: + - name: file + shareTypes: + - user + protocols: + datatx: /datatx + webdav: /webdav +capabilities: + - enforce-mfa + - invites + - protocol-object + - recieve-code + - webdav-uri +criteria: + - http-request-signatures + - recieve-code + - denylist + - allowlist + - invite +publicKey: + keyId: {{ public_key_id }} + publicKeyPem: '{{ public_key_pem }}' diff --git a/templates/error.html b/templates/error.html new file mode 100644 index 0000000..9ab7e02 --- /dev/null +++ b/templates/error.html @@ -0,0 +1,2 @@ +

Oops!

+

{{ message }}

diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..3b5787c --- /dev/null +++ b/templates/index.html @@ -0,0 +1,24 @@ + + + Amity + + + + +

Hello {{ user }}

+ diff --git a/templates/wayf.html b/templates/wayf.html new file mode 100644 index 0000000..9142228 --- /dev/null +++ b/templates/wayf.html @@ -0,0 +1,17 @@ +

Where are you from?

+
+
+ + + +
+
+ +
+