doxs, refactor, extra test
This commit is contained in:
parent
4578d27433
commit
917c11b939
|
|
@ -1,361 +1,492 @@
|
||||||
{\rtf1\ansi\deff3\adeflang1025
|
{\rtf1\ansi\deff3\adeflang1025
|
||||||
{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq2\fcharset0 Helvetica{\*\falt Arial};}{\f6\froman\fprq2\fcharset0 Courier{\*\falt Courier New};}{\f7\fnil\fprq2\fcharset0 Noto Sans CJK SC;}{\f8\fnil\fprq2\fcharset0 Noto Sans Devanagari;}{\f9\fswiss\fprq0\fcharset128 Noto Sans Devanagari;}}
|
{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fmodern\fprq1\fcharset0 Liberation Mono{\*\falt Courier New};}{\f5\fnil\fprq0\fcharset2 OpenSymbol{\*\falt Arial Unicode MS};}{\f6\froman\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f7\froman\fprq2\fcharset0 Helvetica{\*\falt Arial};}{\f8\froman\fprq2\fcharset0 Courier{\*\falt Courier New};}{\f9\fmodern\fprq1\fcharset0 Noto Sans Mono CJK SC;}{\f10\fnil\fprq2\fcharset0 0;}{\f11\fnil\fprq2\fcharset0 Noto Sans CJK SC;}{\f12\fnil\fprq2\fcharset0 Noto Serif CJK SC;}{\f13\fnil\fprq2\fcharset0 Noto Sans Devanagari;}}
|
||||||
{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}
|
{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}
|
||||||
{\stylesheet{\s0\snext0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052 Normal;}
|
{\stylesheet{\s0\snext0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052 Normal;}
|
||||||
{\s15\sbasedon0\snext16\rtlch\af8\afs28 \ltrch\hich\af4\loch\sb240\sa120\keepn\f4\fs28\dbch\af7 Heading;}
|
{\s1\sbasedon19\snext20\rtlch\af13\afs48\ab \ltrch\hich\af3\loch\ilvl0\outlinelevel0\sb240\sa120\f3\fs48\b\dbch\af12 heading 1;}
|
||||||
{\s16\sbasedon0\snext16\loch\sl276\slmult1\sb0\sa140 Body Text;}
|
{\s2\sbasedon19\snext20\rtlch\af13\afs36\ab \ltrch\hich\af3\loch\ilvl1\outlinelevel1\sb200\sa120\f3\fs36\b\dbch\af12 heading 2;}
|
||||||
{\s17\sbasedon16\snext17\rtlch\af9 \ltrch List;}
|
{\*\cs15\snext15\rtlch\ab \ltrch\loch\b Strong;}
|
||||||
{\s18\sbasedon0\snext18\rtlch\af9\afs24\ai \ltrch\loch\sb120\sa120\noline\fs24\i caption;}
|
{\*\cs16\snext16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9 Source Text;}
|
||||||
{\s19\sbasedon0\snext19\rtlch\af9 \ltrch\loch\noline Index;}
|
{\*\cs17\snext17\rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 Bullets;}
|
||||||
}{\*\generator LibreOffice/25.2.7.2$Linux_X86_64 LibreOffice_project/520$Build-2}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}}{\*\userprops}\deftab720
|
{\*\cs18\snext18 Numbering Symbols;}
|
||||||
\hyphauto1\viewscale100\formshade\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\fet\aftnrstcont\aftnstart1\aftnnrlc
|
{\s19\sbasedon0\snext20\rtlch\af13\afs28 \ltrch\hich\af6\loch\sb240\sa120\keepn\f6\fs28\dbch\af11 Heading;}
|
||||||
{\*\ftnsep\chftnsep}\pgndec\pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs36\b\f5\loch
|
{\s20\sbasedon0\snext20\loch\sl276\slmult1\sb0\sa140 Body Text;}
|
||||||
|
{\s21\sbasedon20\snext21\rtlch\af13 \ltrch\loch\sl240\slmult1\sb0\sa0 List;}
|
||||||
|
{\s22\sbasedon0\snext22\rtlch\af13\afs24\ai \ltrch\loch\sb120\sa120\fs24\i caption;}
|
||||||
|
{\s23\sbasedon0\snext23\rtlch\af13 \ltrch Index;}
|
||||||
|
{\s24\sbasedon0\snext24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9 Preformatted Text;}
|
||||||
|
{\s25\sbasedon0\snext20\rtlch\afs12 \ltrch\loch\sb0\sa283\brdrt\brdrnone\brdrl\brdrnone\brdrb\brdrdb\brdrw1\brdrcf15\brsp0\brdrr\brdrnone\noline\fs12 Horizontal Line;}
|
||||||
|
{\s26\sbasedon0\snext26\loch\nowidctlpar\noline Table Contents;}
|
||||||
|
{\s27\sbasedon26\snext27\rtlch\ab \ltrch\loch\qc\noline\b Table Heading;}
|
||||||
|
}{\*\listtable{\list\listtemplateid1
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li709}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li1418}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li2127}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li2836}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li3545}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li4254}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li4963}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li5672}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li6381}\listid1}
|
||||||
|
{\list\listtemplateid2
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li709}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li1418}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li2127}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li2836}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li3545}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li4254}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li4963}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li5672}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li6381}\listid2}
|
||||||
|
{\list\listtemplateid3
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li709}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li1418}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li2127}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li2836}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li3545}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li4254}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li4963}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li5672}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li6381}\listid3}
|
||||||
|
{\list\listtemplateid4
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li709}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li1418}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li2127}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li2836}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li3545}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li4254}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li4963}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li5672}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li6381}\listid4}
|
||||||
|
{\list\listtemplateid5
|
||||||
|
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'00.;}{\levelnumbers\'01;}\fi-283\li709}
|
||||||
|
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'01.;}{\levelnumbers\'01;}\fi-283\li1418}
|
||||||
|
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'02.;}{\levelnumbers\'01;}\fi-283\li2127}
|
||||||
|
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'03.;}{\levelnumbers\'01;}\fi-283\li2836}
|
||||||
|
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'04.;}{\levelnumbers\'01;}\fi-283\li3545}
|
||||||
|
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'05.;}{\levelnumbers\'01;}\fi-283\li4254}
|
||||||
|
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'06.;}{\levelnumbers\'01;}\fi-283\li4963}
|
||||||
|
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'07.;}{\levelnumbers\'01;}\fi-283\li5672}
|
||||||
|
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'08.;}{\levelnumbers\'01;}\fi-283\li6381}\listid5}
|
||||||
|
{\list\listtemplateid6
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li709}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li1418}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li2127}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li2836}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li3545}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li4254}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li4963}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li5672}
|
||||||
|
{\listlevel\levelnfc23\leveljc0\levelstartat1\levelfollow0{\leveltext \'01\u8226 ?;}{\levelnumbers;}\f5\rtlch\af5 \ltrch\loch\fi-283\li6381}\listid6}
|
||||||
|
{\list\listtemplateid7
|
||||||
|
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
|
||||||
|
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
|
||||||
|
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
|
||||||
|
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
|
||||||
|
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
|
||||||
|
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
|
||||||
|
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
|
||||||
|
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
|
||||||
|
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}\listid7}
|
||||||
|
}{\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}{\listoverride\listid3\listoverridecount0\ls3}{\listoverride\listid4\listoverridecount0\ls4}{\listoverride\listid5\listoverridecount0\ls5}{\listoverride\listid6\listoverridecount0\ls6}{\listoverride\listid7\listoverridecount0\ls7}}{\*\generator LibreOffice/25.2.7.2$Linux_X86_64 LibreOffice_project/520$Build-2}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr2026\mo3\dy11\hr7\min49}{\printim\yr0\mo0\dy0\hr0\min0}}{\*\userprops}\deftab720
|
||||||
|
\hyphauto1\viewscale100\formshade\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\fet\aftnrstcont\aftnstart1\aftnnrlc
|
||||||
|
{\*\ftnsep\chftnsep}\pgndec\pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
CA/PKI Backend Project Context}
|
CA/PKI Backend Project Context}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs32\b\f7\loch
|
||||||
Stack}
|
Stack}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab Python 3.13}
|
\tab Python 3.13}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab FastAPI (web API)}
|
\tab FastAPI (web API)}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab psycopg (PostgreSQL driver)}
|
\tab psycopg (PostgreSQL driver)}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab PostgreSQL database: }{\hich\af6\loch\f6\loch
|
\tab PostgreSQL database: }{\hich\af8\loch\f8\loch
|
||||||
ca}
|
ca}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab Unit tests: }{\hich\af6\loch\f6\loch
|
\tab Unit tests: }{\hich\af8\loch\f8\loch
|
||||||
unittest}
|
unittest}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab HTTP testing: }{\hich\af6\loch\f6\loch
|
\tab HTTP testing: }{\hich\af8\loch\f8\loch
|
||||||
fastapi.testclient}
|
fastapi.testclient}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab Zenroom cryptographic runtime (Docker container)}
|
\tab Zenroom cryptographic runtime }{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs24\b\f7\dbch\af10\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
(local execution via Python wrapper)}
|
||||||
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Run tests:}
|
Run tests:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af8\loch\f8\loch
|
||||||
python3 -m unittest discover}
|
python3 -m unittest discover}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Integration tests require:}
|
Integration tests require:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af8\loch\f8\loch
|
||||||
export DATABASE_URL="postgresql:///ca"}
|
export DATABASE_URL="postgresql:///ca"}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7
|
||||||
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs36\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Project Structure}
|
Project Structure}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af8\loch\f8\loch
|
||||||
pki/\line \u9500\'3f\u9472\'3f\u9472\'3f ca_core/\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f entity.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f group_member.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f property.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f metadata.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f db_logging.py\line \u9474\'3f \u9492\'3f\u9472\'3f\u9472\'3f crypto/\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f zenroom_client.py\line \u9474\'3f \u9492\'3f\u9472\'3f\u9472\'3f zenroom_service_client.py\line \u9474\'3f\line \u9500\'3f\u9472\'3f\u9472\'3f ca_api/\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f app.py\line \u9474\'3f \u9492\'3f\u9472\'3f\u9472\'3f db.py\line \u9474\'3f\line \u9500\'3f\u9472\'3f\u9472\'3f tests/\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_entity.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_group.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_property.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_metadata.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_api_smoke.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_api_unit.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_api_integration.py\line \u9474\'3f \u9492\'3f\u9472\'3f\u9472\'3f integration/\line \u9474\'3f \u9492\'3f\u9472\'3f\u9472\'3f zenroom tests\line \u9474\'3f\line \u9500\'3f\u9472\'3f\u9472\'3f create_tables.sql\line \u9492\'3f\u9472\'3f\u9472\'3f PROJECT_CONTEXT.md}
|
pki/\line \u9500\'3f\u9472\'3f\u9472\'3f ca_core/\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f entity.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f group_member.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f property.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f metadata.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f db_logging.py\line \u9474\'3f \u9492\'3f\u9472\'3f\u9472\'3f crypto/\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f zenroom_client.py\line \u9474\'3f \u9492\'3f\u9472\'3f\u9472\'3f zenroom_service_client.py\line \u9474\'3f\line \u9500\'3f\u9472\'3f\u9472\'3f ca_api/\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f app.py\line \u9474\'3f \u9492\'3f\u9472\'3f\u9472\'3f db.py\line \u9474\'3f\line \u9500\'3f\u9472\'3f\u9472\'3f tests/\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_entity.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_group.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_property.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_metadata.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_api_smoke.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_api_unit.py\line \u9474\'3f \u9500\'3f\u9472\'3f\u9472\'3f test_api_integration.py\line \u9474\'3f \u9492\'3f\u9472\'3f\u9472\'3f integration/\line \u9474\'3f \u9492\'3f\u9472\'3f\u9472\'3f zenroom tests\line \u9474\'3f\line \u9500\'3f\u9472\'3f\u9472\'3f create_tables.sql\line \u9492\'3f\u9472\'3f\u9472\'3f PROJECT_CONTEXT.md}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7
|
||||||
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs36\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Architecture}
|
Architecture}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af8\loch\f8\loch
|
||||||
HTTP API (FastAPI)\line \u9474\'3f\line \u9660\'3f\line ca_api (thin HTTP adapter)\line \u9474\'3f\line \u9660\'3f\line ca_core (business logic)\line \u9474\'3f\line \u9660\'3f\line PostgreSQL}
|
HTTP API (FastAPI)\line \u9474\'3f\line \u9660\'3f\line ca_api (thin HTTP adapter)\line \u9474\'3f\line \u9660\'3f\line ca_core (business logic)\line \u9474\'3f\line \u9660\'3f\line PostgreSQL}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
The system is layered to keep business logic independent from the HTTP interface.}
|
The system is layered to keep business logic independent from the HTTP interface.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7
|
||||||
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs36\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Database Overview}
|
Database Overview}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Database: }{\hich\af5\loch\b\f5\loch
|
Database: }{\hich\af7\loch\b\f7\loch
|
||||||
ca}
|
ca}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Core tables:}
|
Core tables:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab entity}
|
\tab entity}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab group_member}
|
\tab group_member}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab property}
|
\tab property}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab metadata}
|
\tab metadata}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab log}
|
\tab log}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs32\b\f7\loch
|
||||||
Entity Rules}
|
Entity Rules}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Entity types:}
|
Entity types:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab person}
|
\tab person}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab group}
|
\tab group}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab device}
|
\tab device}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Status values:}
|
Status values:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab active}
|
\tab active}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab revoked}
|
\tab revoked}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Groups must include }{\hich\af6\loch\f6\loch
|
Groups must include }{\hich\af8\loch\f8\loch
|
||||||
ca_reference}{\hich\af5\loch\f5\loch
|
ca_reference}{\hich\af7\loch\f7\loch
|
||||||
.}
|
.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Persons and devices must }{\hich\af5\loch\b\f5\loch
|
Persons and devices must }{\hich\af7\loch\b\f7\loch
|
||||||
not}{\hich\af5\loch\f5\loch
|
not}{\hich\af7\loch\f7\loch
|
||||||
include }{\hich\af6\loch\f6\loch
|
include }{\hich\af8\loch\f8\loch
|
||||||
ca_reference}{\hich\af5\loch\f5\loch
|
ca_reference}{\hich\af7\loch\f7\loch
|
||||||
.}
|
.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Revoked entities are immutable.}
|
Revoked entities are immutable.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7
|
||||||
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs36\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Logging}
|
Logging}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
All mutations must call:}
|
All mutations must call:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af8\loch\f8\loch
|
||||||
log_change(cursor, message)}
|
log_change(cursor, message)}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Exactly }{\hich\af5\loch\b\f5\loch
|
Exactly }{\hich\af7\loch\b\f7\loch
|
||||||
one log entry must be produced per mutation}{\hich\af5\loch\f5\loch
|
one log entry must be produced per mutation}{\hich\af7\loch\f7\loch
|
||||||
.}
|
.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Logging occurs inside the same transaction.}
|
Logging occurs inside the same transaction.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7
|
||||||
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs36\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Core Modules}
|
Core Modules}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs32\b\f7\loch
|
||||||
entity.py}
|
entity.py}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Provides:}
|
Provides:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab insert_creator}
|
\tab insert_creator}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab enroll_person}
|
\tab enroll_person}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab create_group}
|
\tab create_group}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab get_entity}
|
\tab get_entity}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab set_entity_status}
|
\tab set_entity_status}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs32\b\f7\loch
|
||||||
group_member.py}
|
group_member.py}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Provides:}
|
Provides:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab add_group_member}
|
\tab add_group_member}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab remove_group_member}
|
\tab remove_group_member}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab get_members_of_group}
|
\tab get_members_of_group}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs32\b\f7\loch
|
||||||
property.py}
|
property.py}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Provides:}
|
Provides:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab set_property}
|
\tab set_property}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab delete_property}
|
\tab delete_property}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab get_properties}
|
\tab get_properties}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\fs32\b\f7\loch
|
||||||
metadata.py}
|
metadata.py}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7\loch
|
||||||
Provides:}
|
Provides:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab get_name}
|
\tab get_name}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab get_comment}
|
\tab get_comment}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab get_public_key}
|
\tab get_public_key}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab get_defense_p}
|
\tab get_defense_p}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab set_name}
|
\tab set_name}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0{\hich\af7\loch\f7
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\u8226\'95}{\hich\af7\loch\f7\loch
|
||||||
\tab set_defense_p}
|
\tab set_defense_p}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s0\rtlch\af13\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180{\hich\af7\loch\f7
|
||||||
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs36\b\f5\loch
|
\par \pard\plain \s2\rtlch\af13\afs36\ab \ltrch\hich\af3\loch\ilvl1\outlinelevel1\sb200\sa120\f3\fs36\b\dbch\af12\ql\fi0\li0\lin0\sb0\sa180{\rtlch\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
Cryptographic Layer}
|
Cryptographic Layer}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
The system integrates }{\hich\af5\loch\b\f5\loch
|
The system integrates }{\hich\af7\loch\cs15\rtlch\ab \ltrch\loch\b\fs36\f7\loch
|
||||||
Zenroom}{\hich\af5\loch\f5\loch
|
Zenroom}{\hich\af7\loch\fs36\b\f7\loch
|
||||||
for cryptographic operations.}
|
as its cryptographic runtime.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Zenroom runs in an isolated environment, typically a }{\hich\af5\loch\b\f5\loch
|
Zenroom is a deterministic virtual machine designed for secure execution of\line cryptographic protocols defined in }{\hich\af7\loch\cs15\rtlch\ab \ltrch\loch\b\fs36\f7\loch
|
||||||
Docker container}{\hich\af5\loch\f5\loch
|
Zencode scripts}{\hich\af7\loch\fs36\b\f7\loch
|
||||||
.}
|
.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
ca_core\line \u9474\'3f\line \u9660\'3f\line crypto clients\line \u9474\'3f\line \u9660\'3f\line Zenroom runtime}
|
In this project Zenroom is executed }{\hich\af7\loch\cs15\rtlch\ab \ltrch\loch\b\fs36\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
locally via the official Python wrapper}{\hich\af7\loch\fs36\b\f7\loch
|
||||||
zenroom_client.py}
|
.\line No Docker container or HTTP service is used.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\fi0\li0\lin0\ri0\rin0\sb0\sa180{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
Local execution interface.}
|
ca_core}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\sb0\sa180{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10
|
||||||
Responsibilities:}
|
\u9492\'3f\u9472\'3f }{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
crypto}
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\par \pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\sb0\sa180{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10
|
||||||
\tab execute Zenroom scripts}
|
\u9492\'3f\u9472\'3f }{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
|
||||||
\tab parse output}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
|
||||||
\tab raise errors}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
|
||||||
Used for development and some integration tests.}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
|
||||||
zenroom_service_client.py}
|
zenroom_service_client.py}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\sb0\sa180{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10
|
||||||
HTTP client for a Zenroom service container.}
|
\u9474\'3f}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\sb0\sa180{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10
|
||||||
|
\u9660\'3f}
|
||||||
|
\par \pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\sb0\sa180{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10
|
||||||
|
}{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
|
zenroom Python wrapper}
|
||||||
|
\par \pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\sb0\sa180{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10
|
||||||
|
\u9474\'3f}
|
||||||
|
\par \pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\sb0\sa180{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10
|
||||||
|
\u9660\'3f}
|
||||||
|
\par \pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10
|
||||||
|
}{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
|
Zenroom runtime (local process)}
|
||||||
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
This architecture removes the previous HTTP service layer and simplifies\line deployment and testing.}
|
||||||
|
\par \pard\plain \s25\rtlch\afs12 \ltrch\loch\sb0\sa283\brdrt\brdrnone\brdrl\brdrnone\brdrb\brdrdb\brdrw1\brdrcf15\brsp0\brdrr\brdrnone\noline\fs12\sb0\sa180\rtlch\afs24 \ltrch\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
|
||||||
|
\par \pard\plain \s2\rtlch\af13\afs36\ab \ltrch\hich\af3\loch\ilvl1\outlinelevel1\sb200\sa120\f3\fs36\b\dbch\af12\sb0\sa180{\rtlch\afs24 \ltrch\hich\af7\loch\f7\dbch\af10\loch
|
||||||
|
zenroom_service_client.py}
|
||||||
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\fs36\b\f7\loch
|
||||||
|
zenroom_service_client.py}{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
provides the }{\hich\af7\loch\cs15\rtlch\ab \ltrch\loch\b\fs36\f7\loch
|
||||||
|
adapter between the CA backend and Zenroom}{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
.}
|
||||||
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Responsibilities:}
|
Responsibilities:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls1 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
execute Zencode scripts using the Zenroom Python wrapper}
|
||||||
\tab send scripts}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls1 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
pass structured JSON input}
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls1 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\tab pass JSON input}
|
parse Zenroom output}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls1 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
normalize results into Python structures}
|
||||||
\tab return parsed result}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls1 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
translate runtime errors into }{\hich\af7\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\fs36\b\f7\loch
|
||||||
Typical flow:}
|
ZenroomServiceError}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Python\line \u8595\'3f\line ZenroomServiceClient\line \u8595\'3f\line HTTP request\line \u8595\'3f\line Zenroom container\line \u8595\'3f\line JSON result}
|
All cryptographic operations are exposed through a }{\hich\af7\loch\cs15\rtlch\ab \ltrch\loch\b\fs36\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5
|
single client class}{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs36\b\f5\loch
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\fi0\li0\lin0\ri0\rin0{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
API Layer (ca_api)}
|
{\*\bkmkstart code-block-viewer}{\*\bkmkend code-block-viewer}ZenroomServiceClient}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s25\rtlch\afs12 \ltrch\loch\sb0\sa283\brdrt\brdrnone\brdrl\brdrnone\brdrb\brdrdb\brdrw1\brdrcf15\brsp0\brdrr\brdrnone\noline\fs12\sb0\sa180\rtlch\afs24 \ltrch\hich\af7\loch\fs36\b\f7\loch
|
||||||
FastAPI provides the HTTP interface.}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s2\rtlch\af13\afs36\ab \ltrch\hich\af3\loch\ilvl1\outlinelevel1\sb200\sa120\f3\fs36\b\dbch\af12\sb0\sa180{\rtlch\afs24 \ltrch\hich\af7\loch\f7\dbch\af10\loch
|
||||||
|
Supported Operations}
|
||||||
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
The client provides the following cryptographic operations:}
|
||||||
|
\par \trowd\trql\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx3145\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx6933\pard\plain \s27\rtlch\ab \ltrch\loch\qc\noline\b\intbl{\loch
|
||||||
|
Method}\cell\pard\plain \s27\rtlch\ab \ltrch\loch\qc\noline\b\intbl{\loch
|
||||||
|
Description}\cell\row\pard \trowd\trql\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx3145\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx6933\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\loch
|
||||||
|
generate_keypair()}\cell\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch
|
||||||
|
Create an ECDH keypair}\cell\row\pard \trowd\trql\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx3145\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx6933\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\loch
|
||||||
|
generate_public_key()}\cell\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch
|
||||||
|
Derive public key from keyring}\cell\row\pard \trowd\trql\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx3145\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx6933\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\loch
|
||||||
|
symmetric_encrypt()}\cell\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch
|
||||||
|
Encrypt message using password}\cell\row\pard \trowd\trql\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx3145\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx6933\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\loch
|
||||||
|
symmetric_decrypt()}\cell\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch
|
||||||
|
Decrypt password-encrypted message}\cell\row\pard \trowd\trql\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx3145\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx6933\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\loch
|
||||||
|
asymmetric_encrypt()}\cell\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch
|
||||||
|
Encrypt message for a recipient}\cell\row\pard \trowd\trql\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx3145\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx6933\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\loch
|
||||||
|
asymmetric_decrypt()}\cell\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch
|
||||||
|
Decrypt message from a sender}\cell\row\pard \trowd\trql\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx3145\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx6933\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\loch
|
||||||
|
sign_objects()}\cell\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch
|
||||||
|
Sign a string field}\cell\row\pard \trowd\trql\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx3145\clpadfl3\clpadl28\clpadft3\clpadt28\clpadfb3\clpadb28\clpadfr3\clpadr28\clvertalc\cellx6933\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\loch
|
||||||
|
verify_signature()}\cell\pard\plain \s26\loch\nowidctlpar\noline\intbl{\loch
|
||||||
|
Verify an ECDH signature}\cell\row\pard \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
These operations correspond directly to the Zencode scripts embedded in the module.}
|
||||||
|
\par \pard\plain \s25\rtlch\afs12 \ltrch\loch\sb0\sa283\brdrt\brdrnone\brdrl\brdrnone\brdrb\brdrdb\brdrw1\brdrcf15\brsp0\brdrr\brdrnone\noline\fs12\sb0\sa180\rtlch\afs24 \ltrch\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
|
||||||
|
\par \pard\plain \s2\rtlch\af13\afs36\ab \ltrch\hich\af3\loch\ilvl1\outlinelevel1\sb200\sa120\f3\fs36\b\dbch\af12\sb0\sa180{\rtlch\afs24 \ltrch\hich\af7\loch\f7\dbch\af10\loch
|
||||||
|
Script Execution}
|
||||||
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
All Zencode scripts are executed through a single internal helper:}
|
||||||
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\fi0\li0\lin0\ri0\rin0{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
|
{\*\bkmkstart code-block-viewer Copy 1}{\*\bkmkend code-block-viewer Copy 1}_run_script()}
|
||||||
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Responsibilities:}
|
Responsibilities:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls2 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
invoke }{\hich\af7\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\fs36\b\f7\loch
|
||||||
\tab routing}
|
zenroom.zencode_exec()}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls2 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
pass JSON input}
|
||||||
\tab validation}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls2 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
capture Zenroom logs}
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls2 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\tab DB connection handling}
|
parse returned JSON output}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls2 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
raise }{\hich\af7\loch\cs16\rtlch\af4 \ltrch\hich\af4\loch\f4\dbch\af9\fs36\b\f7\loch
|
||||||
\tab error mapping}
|
ZenroomServiceError}{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
on failure}
|
||||||
Flow:}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
This centralizes Zenroom interaction and ensures consistent error handling.}
|
||||||
HTTP request\line \u8595\'3f\line FastAPI route\line \u8595\'3f\line db_cursor()\line \u8595\'3f\line ca_core function\line \u8595\'3f\line commit / rollback}
|
\par \pard\plain \s25\rtlch\afs12 \ltrch\loch\sb0\sa283\brdrt\brdrnone\brdrl\brdrnone\brdrb\brdrdb\brdrw1\brdrcf15\brsp0\brdrr\brdrnone\noline\fs12\sb0\sa180\rtlch\afs24 \ltrch\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5
|
|
||||||
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
\par \pard\plain \s2\rtlch\af13\afs36\ab \ltrch\hich\af3\loch\ilvl1\outlinelevel1\sb200\sa120\f3\fs36\b\dbch\af12\sb0\sa180{\rtlch\afs24 \ltrch\hich\af7\loch\f7\dbch\af10\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs36\b\f5\loch
|
Error Handling}
|
||||||
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
Zenroom failures are converted into Python exceptions.}
|
||||||
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\fi0\li0\lin0\ri0\rin0{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
|
{\*\bkmkstart code-block-viewer Copy 2}{\*\bkmkend code-block-viewer Copy 2}ZenroomServiceError}
|
||||||
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
This exception is raised when:}
|
||||||
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls3 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
Zenroom execution fails}
|
||||||
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls3 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
output cannot be parsed}
|
||||||
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls3 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
expected fields are missing}
|
||||||
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls3 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
verification fails}
|
||||||
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
This allows the rest of the system to treat cryptographic failures as standard\line Python exceptions.}
|
||||||
|
\par \pard\plain \s25\rtlch\afs12 \ltrch\loch\sb0\sa283\brdrt\brdrnone\brdrl\brdrnone\brdrb\brdrdb\brdrw1\brdrcf15\brsp0\brdrr\brdrnone\noline\fs12\sb0\sa180\rtlch\afs24 \ltrch\hich\af7\loch\fs36\b\f7\loch
|
||||||
|
|
||||||
|
\par \pard\plain \s2\rtlch\af13\afs36\ab \ltrch\hich\af3\loch\ilvl1\outlinelevel1\sb200\sa120\f3\fs36\b\dbch\af12\sb0\sa180{\rtlch\afs24 \ltrch\hich\af7\loch\f7\dbch\af10\loch
|
||||||
Testing Strategy}
|
Testing Strategy}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Three layers of tests exist.}
|
Cryptographic functionality is tested using }{\hich\af7\loch\cs15\rtlch\ab \ltrch\loch\b\fs36\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
direct functional tests}{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Core Unit Tests}
|
.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Test domain logic directly.}
|
Tests execute the real Zenroom runtime through the adapter and verify:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls4 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Examples:}
|
key generation}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls4 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
encryption/decryption roundtrips}
|
||||||
\tab test_entity.py}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls4 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
signing}
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls4 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\tab test_group.py}
|
signature verification}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls4 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
signature rejection for tampered messages}
|
||||||
\tab test_property.py}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
Example tests:}
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\fi0\li0\lin0\ri0\rin0{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
\tab test_metadata.py}
|
{\*\bkmkstart code-block-viewer Copy 3}{\*\bkmkend code-block-viewer Copy 3}tests/test_zenroom_service_client.py}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
API Unit Tests}
|
The suite currently contains }{\hich\af7\loch\cs15\rtlch\ab \ltrch\loch\b\fs36\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
9 tests}{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Test HTTP behaviour without DB.}
|
:}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain 1.\tab}\ilvl0\ls5 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Mocked components:}
|
generate keypair}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain 2.\tab}\ilvl0\ls5 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
generate public key}
|
||||||
\tab db_cursor}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain 3.\tab}\ilvl0\ls5 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
symmetric encryption}
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain 4.\tab}\ilvl0\ls5 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\tab ca_core functions}
|
symmetric decryption}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain 5.\tab}\ilvl0\ls5 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
File:}
|
asymmetric encryption}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain 6.\tab}\ilvl0\ls5 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
asymmetric decryption}
|
||||||
\tab test_api_unit.py}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain 7.\tab}\ilvl0\ls5 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
signing}
|
||||||
API Integration Tests}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain 8.\tab}\ilvl0\ls5 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
successful verification}
|
||||||
Full stack tests:}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain 9.\tab}\ilvl0\ls5 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
verification failure for modified message}
|
||||||
FastAPI\line \u8595\'3f\line ca_core\line \u8595\'3f\line PostgreSQL}
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
Tests run with:}
|
||||||
File:}
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s24\rtlch\af4\afs20 \ltrch\hich\af4\loch\sb0\sa0\f4\fs20\dbch\af9\fi0\li0\lin0\ri0\rin0{\rtlch\af13\afs24 \ltrch\hich\af7\loch\fs36\b\f7\dbch\af10\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
{\*\bkmkstart code-block-viewer Copy 4}{\*\bkmkend code-block-viewer Copy 4}python3 -m unittest discover}
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
\par \sect\sectd\sftnnar\saftnnrlc\sectunlocked1\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ltrsect\sbknone\pard\plain \s20\loch\sl276\slmult1\sb0\sa140\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\tab test_api_integration.py}
|
Typical runtime is }{\hich\af7\loch\cs15\rtlch\ab \ltrch\loch\b\fs36\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
under 0.5 seconds}{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Requires:}
|
.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
\par \pard\plain \s25\rtlch\afs12 \ltrch\loch\sb0\sa283\brdrt\brdrnone\brdrl\brdrnone\brdrb\brdrdb\brdrw1\brdrcf15\brsp0\brdrr\brdrnone\noline\fs12\sb0\sa180\rtlch\afs24 \ltrch\hich\af7\loch\fs36\b\f7\loch
|
||||||
export DATABASE_URL="postgresql:///ca"}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs32\b\f5\loch
|
\par \pard\plain \s2\rtlch\af13\afs36\ab \ltrch\hich\af3\loch\ilvl1\outlinelevel1\sb200\sa120\f3\fs36\b\dbch\af12\sb0\sa180{\rtlch\afs24 \ltrch\hich\af7\loch\f7\dbch\af10\loch
|
||||||
Zenroom Integration Tests}
|
Security Notes}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls6 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Located in:}
|
Zenroom scripts execute in an isolated runtime.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls6 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
tests/integration/}
|
All inputs are passed as structured JSON.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls6 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
Verify:}
|
Dynamic script generation restricts field names to safe identifiers.}
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
\par \pard\plain \s20\loch\sl276\slmult1\sb0\sa140{\listtext\pard\plain \rtlch\af5 \ltrch\hich\af5\loch\f5\dbch\af5 \u8226\'95\tab}\ilvl0\ls6 \fi-283\li0\lin0\tx0\fi-283\li709\lin709\sb0\sa180{\hich\af7\loch\fs36\b\f7\loch
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
Cryptographic failures are surfaced immediately as exceptions.}
|
||||||
\tab Zenroom script execution}
|
\par \pard\plain \s25\rtlch\afs12 \ltrch\loch\sb0\sa283\brdrt\brdrnone\brdrl\brdrnone\brdrb\brdrdb\brdrw1\brdrcf15\brsp0\brdrr\brdrnone\noline\fs12\sb0\sa180\hich\af7\loch\fs36\b\f7\loch
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
|
||||||
\tab service communication}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi-360\li360\lin360\sb0\sa0\ltrpar{\hich\af5\loch\f5
|
|
||||||
\u8226\'95}{\hich\af5\loch\f5\loch
|
|
||||||
\tab error handling}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
|
||||||
Some tests require a running Zenroom container.}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\qc\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5
|
|
||||||
\u8212\'97\u8212\'97\u8212\'97\u8212\'97\u8212\'97}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\fs36\b\f5\loch
|
|
||||||
Runtime Deployment Model}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af6\loch\f6\loch
|
|
||||||
FastAPI API\line \u9474\'3f\line \u9660\'3f\line ca_core\line \u9474\'3f\line \u9660\'3f\line crypto client\line \u9474\'3f\line \u9660\'3f\line Zenroom container\line \u9474\'3f\line \u9660\'3f\line PostgreSQL}
|
|
||||||
\par \pard\plain \s0\rtlch\af8\afs24\alang1081 \ltrch\lang1033\langfe2052\hich\af3\loch\widctlpar\hyphpar1\ltrpar\cf0\f3\fs24\lang1033\kerning1\dbch\af10\langfe2052\ql\fi0\li0\lin0\sb0\sa180\ltrpar{\hich\af5\loch\f5\loch
|
|
||||||
This design keeps cryptographic execution isolated while keeping the Python service lightweight.}
|
|
||||||
\par }
|
\par }
|
||||||
Binary file not shown.
|
|
@ -6,18 +6,26 @@ from zenroom import zenroom
|
||||||
|
|
||||||
|
|
||||||
class ZenroomServiceError(RuntimeError):
|
class ZenroomServiceError(RuntimeError):
|
||||||
pass
|
"""Raised when local Zenroom execution fails or returns invalid data."""
|
||||||
|
|
||||||
|
|
||||||
class ZenroomServiceClient:
|
class ZenroomServiceClient:
|
||||||
"""
|
"""
|
||||||
Local Zenroom client using the installed `zenroom` Python wrapper.
|
Local Zenroom client.
|
||||||
|
|
||||||
This preserves the public API of the old HTTP/Docker-backed client as much
|
This class replaces the old HTTP/Docker service client and talks directly to
|
||||||
as possible, so callers should not need changes.
|
the installed Zenroom Python wrapper plus local Zenroom binary.
|
||||||
|
|
||||||
|
The public method names intentionally mirror the old service-oriented API so
|
||||||
|
the rest of the codebase can keep using the same interface.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SCRIPT_GENERATE_KEYPAIR = """Scenario 'ecdh': Create the keypair from a name passed from data/keys
|
# -------------------------------------------------------------------------
|
||||||
|
# Embedded Zencode scripts
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SCRIPT_GENERATE_KEYPAIR = """\
|
||||||
|
Scenario 'ecdh': Create the keypair from a name passed from data/keys
|
||||||
|
|
||||||
# Here we load the identity of the executor
|
# Here we load the identity of the executor
|
||||||
Given my name is in a 'string' named 'myName'
|
Given my name is in a 'string' named 'myName'
|
||||||
|
|
@ -27,7 +35,8 @@ When I create the ecdh key
|
||||||
Then print my 'keyring'
|
Then print my 'keyring'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SCRIPT_GENERATE_PUBLIC_KEY = """# Loading scenarios
|
SCRIPT_GENERATE_PUBLIC_KEY = """\
|
||||||
|
# Loading scenarios
|
||||||
Scenario 'ecdh': Create the public key
|
Scenario 'ecdh': Create the public key
|
||||||
|
|
||||||
# Loading the private keys
|
# Loading the private keys
|
||||||
|
|
@ -40,7 +49,8 @@ When I create the ecdh public key
|
||||||
Then print the 'ecdh public key'
|
Then print the 'ecdh public key'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SCRIPT_SYMMETRIC_ENCRYPT = """Scenario 'ecdh': Encrypt a message with the password
|
SCRIPT_SYMMETRIC_ENCRYPT = """\
|
||||||
|
Scenario 'ecdh': Encrypt a message with the password
|
||||||
Given that I have a 'string' named 'password'
|
Given that I have a 'string' named 'password'
|
||||||
Given that I have a 'string' named 'header'
|
Given that I have a 'string' named 'header'
|
||||||
Given that I have a 'string' named 'message'
|
Given that I have a 'string' named 'message'
|
||||||
|
|
@ -48,7 +58,8 @@ When I encrypt the secret message 'message' with 'password'
|
||||||
Then print the 'secret message'
|
Then print the 'secret message'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SCRIPT_SYMMETRIC_DECRYPT = """Scenario 'ecdh': Decrypt the message with the password
|
SCRIPT_SYMMETRIC_DECRYPT = """\
|
||||||
|
Scenario 'ecdh': Decrypt the message with the password
|
||||||
Given that I have a valid 'secret message'
|
Given that I have a valid 'secret message'
|
||||||
Given that I have a 'string' named 'password'
|
Given that I have a 'string' named 'password'
|
||||||
When I decrypt the text of 'secret message' with 'password'
|
When I decrypt the text of 'secret message' with 'password'
|
||||||
|
|
@ -56,7 +67,8 @@ When I rename the 'text' to 'textDecrypted'
|
||||||
Then print the 'textDecrypted' as 'string'
|
Then print the 'textDecrypted' as 'string'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SCRIPT_ASYMMETRIC_ENCRYPT = """Scenario 'ecdh': Alice encrypts a message for Bob
|
SCRIPT_ASYMMETRIC_ENCRYPT = """\
|
||||||
|
Scenario 'ecdh': Alice encrypts a message for Bob
|
||||||
|
|
||||||
Given that I am known as 'sender'
|
Given that I am known as 'sender'
|
||||||
Given that I have my valid 'keyring'
|
Given that I have my valid 'keyring'
|
||||||
|
|
@ -70,7 +82,8 @@ When I rename the 'secret message' to 'secret'
|
||||||
Then print the 'secret'
|
Then print the 'secret'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SCRIPT_ASYMMETRIC_DECRYPT = """Scenario 'ecdh': Bob decrypts the message from Alice
|
SCRIPT_ASYMMETRIC_DECRYPT = """\
|
||||||
|
Scenario 'ecdh': Bob decrypts the message from Alice
|
||||||
Given that I am known as 'reciever'
|
Given that I am known as 'reciever'
|
||||||
Given I have my 'keyring'
|
Given I have my 'keyring'
|
||||||
Given I have a 'public key' from 'sender'
|
Given I have a 'public key' from 'sender'
|
||||||
|
|
@ -80,8 +93,10 @@ Then print the 'text' as 'string'
|
||||||
Then print the 'header' from 'secret' as 'string'
|
Then print the 'header' from 'secret' as 'string'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Used as a template so sign_objects() can sign any single string field.
|
# Dynamic templates are used for sign/verify so the public Python methods
|
||||||
SCRIPT_SIGN_TEMPLATE = """Scenario 'ecdh': create the signature of an object
|
# can work with arbitrary safe field names such as "myMessage".
|
||||||
|
SCRIPT_SIGN_TEMPLATE = """\
|
||||||
|
Scenario 'ecdh': create the signature of an object
|
||||||
Given I am 'signer'
|
Given I am 'signer'
|
||||||
Given I have my 'keyring'
|
Given I have my 'keyring'
|
||||||
Given that I have a 'string' named '{field_name}' inside 'mySecretStuff'
|
Given that I have a 'string' named '{field_name}' inside 'mySecretStuff'
|
||||||
|
|
@ -93,8 +108,8 @@ Then print the '{field_name}'
|
||||||
Then print the '{field_name}.signature'
|
Then print the '{field_name}.signature'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Used as a template so verify_signature() can verify any single string field.
|
SCRIPT_VERIFY_TEMPLATE = """\
|
||||||
SCRIPT_VERIFY_TEMPLATE = """rule check version 3.0.0
|
rule check version 3.0.0
|
||||||
Scenario 'ecdh': Bob verifies the signature from Alice
|
Scenario 'ecdh': Bob verifies the signature from Alice
|
||||||
|
|
||||||
# Here we load the pubkey we'll verify the signature against
|
# Here we load the pubkey we'll verify the signature against
|
||||||
|
|
@ -103,38 +118,46 @@ Given I have a 'public key' from 'signer'
|
||||||
# Here we load the objects to be verified
|
# Here we load the objects to be verified
|
||||||
Given I have a 'string' named '{field_name}'
|
Given I have a 'string' named '{field_name}'
|
||||||
|
|
||||||
# Here we load the objects's signatures
|
# Here we load the object's signature
|
||||||
Given I have a 'signature' named '{field_name}.signature'
|
Given I have a 'signature' named '{field_name}.signature'
|
||||||
|
|
||||||
# Here we perform the verifications
|
# Here we perform the verification
|
||||||
When I verify the '{field_name}' has a ecdh signature in '{field_name}.signature' by 'signer'
|
When I verify the '{field_name}' has a ecdh signature in '{field_name}.signature' by 'signer'
|
||||||
|
|
||||||
# Here we print out the result: if the verifications succeeded, a string will be printed out
|
# If verification succeeds, Zenroom prints the success string.
|
||||||
# if the verifications failed, Zenroom will throw an error
|
# If verification fails, Zenroom raises an error.
|
||||||
Then print the string 'Zenroom certifies that signature is correct!'
|
Then print the string 'Zenroom certifies that signature is correct!'
|
||||||
Then print the '{field_name}'
|
Then print the '{field_name}'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
"""Construct a local client. No external service configuration is needed."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Validation helpers
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _require_non_empty_str(name: str, value: str) -> str:
|
def _require_non_empty_str(name: str, value: str) -> str:
|
||||||
|
"""Validate that a value is a non-empty string and return the stripped value."""
|
||||||
if not isinstance(value, str):
|
if not isinstance(value, str):
|
||||||
raise TypeError(f"{name} must be a string")
|
raise TypeError(f"{name} must be a string")
|
||||||
v = value.strip()
|
value = value.strip()
|
||||||
if not v:
|
if not value:
|
||||||
raise ValueError(f"{name} cannot be empty")
|
raise ValueError(f"{name} cannot be empty")
|
||||||
return v
|
return value
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _require_dict(name: str, value: Any) -> Dict[str, Any]:
|
def _require_dict(name: str, value: Any) -> Dict[str, Any]:
|
||||||
|
"""Validate that a value is a dict."""
|
||||||
if not isinstance(value, dict):
|
if not isinstance(value, dict):
|
||||||
raise TypeError(f"{name} must be a dict")
|
raise TypeError(f"{name} must be a dict")
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _require_keys(d: Dict[str, Any], *, required: Tuple[str, ...], ctx: str) -> None:
|
def _require_keys(d: Dict[str, Any], *, required: Tuple[str, ...], ctx: str) -> None:
|
||||||
|
"""Ensure a dict contains the required keys."""
|
||||||
missing = [k for k in required if k not in d]
|
missing = [k for k in required if k not in d]
|
||||||
if missing:
|
if missing:
|
||||||
raise ZenroomServiceError(f"Missing {missing} in {ctx}: {d!r}")
|
raise ZenroomServiceError(f"Missing {missing} in {ctx}: {d!r}")
|
||||||
|
|
@ -142,16 +165,31 @@ Then print the '{field_name}'
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _require_safe_field_name(field_name: str) -> str:
|
def _require_safe_field_name(field_name: str) -> str:
|
||||||
"""
|
"""
|
||||||
Restrict dynamic field names used inside generated Zencode to avoid script injection.
|
Restrict dynamic field names used in generated Zencode.
|
||||||
|
|
||||||
|
This avoids accidentally generating unsafe script fragments.
|
||||||
"""
|
"""
|
||||||
if not isinstance(field_name, str):
|
if not isinstance(field_name, str):
|
||||||
raise TypeError("field_name must be a string")
|
raise TypeError("field_name must be a string")
|
||||||
if not re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", field_name):
|
if not re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", field_name):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"field_name must match [A-Za-z_][A-Za-z0-9_]* for safe Zencode generation"
|
"field_name must match [A-Za-z_][A-Za-z0-9_]*"
|
||||||
)
|
)
|
||||||
return field_name
|
return field_name
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Zenroom execution helpers
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _normalize_logs(logs: Any) -> str:
|
||||||
|
"""Convert Zenroom logs to a readable string for error messages."""
|
||||||
|
if logs is None:
|
||||||
|
return ""
|
||||||
|
if isinstance(logs, list):
|
||||||
|
return "\n".join(str(item) for item in logs)
|
||||||
|
return str(logs)
|
||||||
|
|
||||||
def _run_script(
|
def _run_script(
|
||||||
self,
|
self,
|
||||||
script_name: str,
|
script_name: str,
|
||||||
|
|
@ -161,25 +199,31 @@ Then print the '{field_name}'
|
||||||
keys: Optional[Dict[str, Any]] = None,
|
keys: Optional[Dict[str, Any]] = None,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Execute a local Zencode script and return parsed JSON result as a dict.
|
Execute a Zencode script locally and return the parsed JSON result.
|
||||||
|
|
||||||
|
Zenroom's Python wrapper returns an object with attributes such as:
|
||||||
|
- output : raw textual output
|
||||||
|
- logs : Zenroom logs
|
||||||
|
- result : parsed JSON object when output is JSON
|
||||||
|
|
||||||
|
We prefer `result`, but fall back to parsing `output` if necessary.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
result = zenroom.zencode_exec(
|
exec_result = zenroom.zencode_exec(
|
||||||
script_text,
|
script_text,
|
||||||
data=json.dumps(data or {}),
|
data=json.dumps(data or {}),
|
||||||
keys=json.dumps(keys) if keys is not None else None,
|
keys=json.dumps(keys) if keys is not None else None,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
raise ZenroomServiceError(f"Failed to execute Zenroom script {script_name}: {e}") from e
|
raise ZenroomServiceError(
|
||||||
|
f"Failed to execute Zenroom script {script_name}: {exc}"
|
||||||
logs = getattr(result, "logs", None)
|
) from exc
|
||||||
output = getattr(result, "output", None)
|
|
||||||
parsed = getattr(result, "result", None)
|
|
||||||
|
|
||||||
|
parsed = getattr(exec_result, "result", None)
|
||||||
if isinstance(parsed, dict):
|
if isinstance(parsed, dict):
|
||||||
return parsed
|
return parsed
|
||||||
|
|
||||||
# Fallback: sometimes output may still be JSON text even if .result is None.
|
output = getattr(exec_result, "output", None)
|
||||||
if isinstance(output, str):
|
if isinstance(output, str):
|
||||||
try:
|
try:
|
||||||
parsed_output = json.loads(output)
|
parsed_output = json.loads(output)
|
||||||
|
|
@ -188,23 +232,23 @@ Then print the '{field_name}'
|
||||||
if isinstance(parsed_output, dict):
|
if isinstance(parsed_output, dict):
|
||||||
return parsed_output
|
return parsed_output
|
||||||
|
|
||||||
log_text = logs
|
logs_text = self._normalize_logs(getattr(exec_result, "logs", None))
|
||||||
if isinstance(log_text, list):
|
|
||||||
log_text = "\n".join(str(x) for x in log_text)
|
|
||||||
elif log_text is None:
|
|
||||||
log_text = ""
|
|
||||||
|
|
||||||
out_preview = output if isinstance(output, str) else repr(output)
|
out_preview = output if isinstance(output, str) else repr(output)
|
||||||
|
|
||||||
raise ZenroomServiceError(
|
raise ZenroomServiceError(
|
||||||
f"Zenroom script {script_name} did not return a JSON object.\n"
|
f"Zenroom script {script_name} did not return a JSON object.\n"
|
||||||
f"Output: {out_preview[:800]}\n"
|
f"Output: {out_preview[:800]}\n"
|
||||||
f"Logs: {str(log_text)[:2000]}"
|
f"Logs: {logs_text[:2000]}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def _pick_owner_block(self, res: Dict[str, Any], my_name: str, ctx: str) -> Dict[str, Any]:
|
@staticmethod
|
||||||
|
def _pick_owner_block(res: Dict[str, Any], my_name: str, ctx: str) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Zenroom often returns: { "<identity>": { ... } }
|
Zenroom often returns data shaped like:
|
||||||
Prefer res[my_name] when present, else accept single-entry dict.
|
{ "<identity>": { ... } }
|
||||||
|
|
||||||
|
Prefer `res[my_name]` when present. If not present, accept a single-entry
|
||||||
|
dict as long as it is unambiguous.
|
||||||
"""
|
"""
|
||||||
if my_name in res:
|
if my_name in res:
|
||||||
owner = res[my_name]
|
owner = res[my_name]
|
||||||
|
|
@ -219,10 +263,48 @@ Then print the '{field_name}'
|
||||||
raise ZenroomServiceError(f"Invalid {ctx} response structure: {res!r}")
|
raise ZenroomServiceError(f"Invalid {ctx} response structure: {res!r}")
|
||||||
return owner
|
return owner
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _validate_secret_box(secret: Dict[str, Any], *, ctx: str) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Validate the standard Zenroom encrypted object shape.
|
||||||
|
|
||||||
|
Expected keys:
|
||||||
|
- checksum
|
||||||
|
- header
|
||||||
|
- iv
|
||||||
|
- text
|
||||||
|
"""
|
||||||
|
if not isinstance(secret, dict):
|
||||||
|
raise ZenroomServiceError(f"Invalid {ctx} response: {secret!r}")
|
||||||
|
|
||||||
|
required = ("checksum", "header", "iv", "text")
|
||||||
|
missing = [k for k in required if not isinstance(secret.get(k), str) or not secret[k].strip()]
|
||||||
|
if missing:
|
||||||
|
raise ZenroomServiceError(f"Invalid {ctx} fields {missing}: {secret!r}")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"checksum": secret["checksum"],
|
||||||
|
"header": secret["header"],
|
||||||
|
"iv": secret["iv"],
|
||||||
|
"text": secret["text"],
|
||||||
|
}
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Service 1: Generate-a-keypair,-reading-identity-from-data
|
# Service 1: Generate-a-keypair,-reading-identity-from-data
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def generate_keypair(self, my_name: str) -> Dict[str, Any]:
|
def generate_keypair(self, my_name: str) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Generate a keypair for the supplied identity name.
|
||||||
|
|
||||||
|
Returns a normalized structure:
|
||||||
|
{
|
||||||
|
"my_name": "<identity>",
|
||||||
|
"keyring": {"ecdh": "<private_b64>"},
|
||||||
|
"private_key": "<private_b64>",
|
||||||
|
# optionally "public_key" if Zenroom emits it
|
||||||
|
}
|
||||||
|
"""
|
||||||
my_name = self._require_non_empty_str("my_name", my_name)
|
my_name = self._require_non_empty_str("my_name", my_name)
|
||||||
|
|
||||||
res = self._run_script(
|
res = self._run_script(
|
||||||
|
|
@ -258,7 +340,9 @@ Then print the '{field_name}'
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Service 2: Generate-public-key
|
# Service 2: Generate-public-key
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def generate_public_key(self, keyring: Dict[str, Any]) -> str:
|
def generate_public_key(self, keyring: Dict[str, Any]) -> str:
|
||||||
|
"""Derive the public key from a Zenroom keyring."""
|
||||||
keyring = self._require_dict("keyring", keyring)
|
keyring = self._require_dict("keyring", keyring)
|
||||||
|
|
||||||
res = self._run_script(
|
res = self._run_script(
|
||||||
|
|
@ -267,15 +351,23 @@ Then print the '{field_name}'
|
||||||
data={"keyring": keyring},
|
data={"keyring": keyring},
|
||||||
)
|
)
|
||||||
|
|
||||||
pub = res.get("ecdh_public_key")
|
public_key = res.get("ecdh_public_key")
|
||||||
if not isinstance(pub, str) or not pub.strip():
|
if not isinstance(public_key, str) or not public_key.strip():
|
||||||
raise ZenroomServiceError(f"Invalid public key response: {res!r}")
|
raise ZenroomServiceError(f"Invalid public key response: {res!r}")
|
||||||
return pub
|
|
||||||
|
return public_key
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Service 3: Encrypt-a-message-with-the-password
|
# Service 3: Encrypt-a-message-with-the-password
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def symmetric_encrypt(self, *, header: str, message: str, shared_key: str) -> Dict[str, str]:
|
def symmetric_encrypt(self, *, header: str, message: str, shared_key: str) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Encrypt a message symmetrically using a password/shared key.
|
||||||
|
|
||||||
|
Returns a standard Zenroom encrypted object with checksum/header/iv/text.
|
||||||
|
Note that Zenroom may encode the returned header representation.
|
||||||
|
"""
|
||||||
header = self._require_non_empty_str("header", header)
|
header = self._require_non_empty_str("header", header)
|
||||||
message = self._require_non_empty_str("message", message)
|
message = self._require_non_empty_str("message", message)
|
||||||
shared_key = self._require_non_empty_str("shared_key", shared_key)
|
shared_key = self._require_non_empty_str("shared_key", shared_key)
|
||||||
|
|
@ -283,48 +375,44 @@ Then print the '{field_name}'
|
||||||
res = self._run_script(
|
res = self._run_script(
|
||||||
"Encrypt-a-message-with-the-password",
|
"Encrypt-a-message-with-the-password",
|
||||||
self.SCRIPT_SYMMETRIC_ENCRYPT,
|
self.SCRIPT_SYMMETRIC_ENCRYPT,
|
||||||
data={"header": header, "message": message, "password": shared_key},
|
data={
|
||||||
|
"header": header,
|
||||||
|
"message": message,
|
||||||
|
"password": shared_key,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
sm = res.get("secret_message")
|
secret_message = res.get("secret_message")
|
||||||
if not isinstance(sm, dict):
|
return self._validate_secret_box(secret_message, ctx="secret_message")
|
||||||
raise ZenroomServiceError(
|
|
||||||
f"Invalid encrypt response (missing secret_message): {res!r}"
|
|
||||||
)
|
|
||||||
|
|
||||||
self._require_keys(sm, required=("checksum", "header", "iv", "text"), ctx="secret_message")
|
|
||||||
for k in ("checksum", "header", "iv", "text"):
|
|
||||||
if not isinstance(sm.get(k), str) or not sm[k].strip():
|
|
||||||
raise ZenroomServiceError(f"Invalid secret_message.{k}: {sm!r}")
|
|
||||||
|
|
||||||
return {
|
|
||||||
"checksum": sm["checksum"],
|
|
||||||
"header": sm["header"],
|
|
||||||
"iv": sm["iv"],
|
|
||||||
"text": sm["text"],
|
|
||||||
}
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Service 4: Decrypt-the-message-with-the-password
|
# Service 4: Decrypt-the-message-with-the-password
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def symmetric_decrypt(self, *, secret_message: Dict[str, Any], shared_key: str) -> str:
|
def symmetric_decrypt(self, *, secret_message: Dict[str, Any], shared_key: str) -> str:
|
||||||
|
"""Decrypt a symmetrically encrypted secret message and return plaintext."""
|
||||||
secret_message = self._require_dict("secret_message", secret_message)
|
secret_message = self._require_dict("secret_message", secret_message)
|
||||||
shared_key = self._require_non_empty_str("shared_key", shared_key)
|
shared_key = self._require_non_empty_str("shared_key", shared_key)
|
||||||
|
|
||||||
res = self._run_script(
|
res = self._run_script(
|
||||||
"Decrypt-the-message-with-the-password",
|
"Decrypt-the-message-with-the-password",
|
||||||
self.SCRIPT_SYMMETRIC_DECRYPT,
|
self.SCRIPT_SYMMETRIC_DECRYPT,
|
||||||
data={"secret_message": secret_message, "password": shared_key},
|
data={
|
||||||
|
"secret_message": secret_message,
|
||||||
|
"password": shared_key,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
txt = res.get("textDecrypted")
|
text = res.get("textDecrypted")
|
||||||
if not isinstance(txt, str):
|
if not isinstance(text, str):
|
||||||
raise ZenroomServiceError(f"Invalid decrypt response: {res!r}")
|
raise ZenroomServiceError(f"Invalid decrypt response: {res!r}")
|
||||||
return txt
|
|
||||||
|
return text
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Service 5: Encrypt-a-message-for-two-recipients-using-asymmetric-cryptography
|
# Service 5: Encrypt-a-message-for-two-recipients-using-asymmetric-cryptography
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def asymmetric_encrypt(
|
def asymmetric_encrypt(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
|
|
@ -333,6 +421,12 @@ Then print the '{field_name}'
|
||||||
header: str,
|
header: str,
|
||||||
message: str,
|
message: str,
|
||||||
) -> Dict[str, str]:
|
) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Encrypt a message asymmetrically for a receiver using sender key material.
|
||||||
|
|
||||||
|
Note: the Zencode script expects the legacy spelling `reciever`, so the
|
||||||
|
payload preserves that exact key.
|
||||||
|
"""
|
||||||
receiver_public_key = self._require_non_empty_str(
|
receiver_public_key = self._require_non_empty_str(
|
||||||
"receiver_public_key", receiver_public_key
|
"receiver_public_key", receiver_public_key
|
||||||
)
|
)
|
||||||
|
|
@ -351,27 +445,13 @@ Then print the '{field_name}'
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
sec = res.get("secret")
|
secret = res.get("secret")
|
||||||
if not isinstance(sec, dict):
|
return self._validate_secret_box(secret, ctx="secret")
|
||||||
raise ZenroomServiceError(
|
|
||||||
f"Invalid asymmetric encrypt response (missing secret): {res!r}"
|
|
||||||
)
|
|
||||||
|
|
||||||
self._require_keys(sec, required=("checksum", "header", "iv", "text"), ctx="secret")
|
|
||||||
for k in ("checksum", "header", "iv", "text"):
|
|
||||||
if not isinstance(sec.get(k), str) or not sec[k].strip():
|
|
||||||
raise ZenroomServiceError(f"Invalid secret.{k}: {sec!r}")
|
|
||||||
|
|
||||||
return {
|
|
||||||
"checksum": sec["checksum"],
|
|
||||||
"header": sec["header"],
|
|
||||||
"iv": sec["iv"],
|
|
||||||
"text": sec["text"],
|
|
||||||
}
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Service 6: Decrypt-a-message-for-two-recipients-using-asymmetric-cryptography
|
# Service 6: Decrypt-a-message-for-two-recipients-using-asymmetric-cryptography
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def asymmetric_decrypt(
|
def asymmetric_decrypt(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
|
|
@ -379,6 +459,15 @@ Then print the '{field_name}'
|
||||||
receiver_keyring: Dict[str, Any],
|
receiver_keyring: Dict[str, Any],
|
||||||
secret: Dict[str, Any],
|
secret: Dict[str, Any],
|
||||||
) -> Dict[str, str]:
|
) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Decrypt an asymmetrically encrypted message.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
{
|
||||||
|
"header": "...",
|
||||||
|
"text": "..."
|
||||||
|
}
|
||||||
|
"""
|
||||||
sender_public_key = self._require_non_empty_str("sender_public_key", sender_public_key)
|
sender_public_key = self._require_non_empty_str("sender_public_key", sender_public_key)
|
||||||
receiver_keyring = self._require_dict("receiver_keyring", receiver_keyring)
|
receiver_keyring = self._require_dict("receiver_keyring", receiver_keyring)
|
||||||
secret = self._require_dict("secret", secret)
|
secret = self._require_dict("secret", secret)
|
||||||
|
|
@ -393,24 +482,25 @@ Then print the '{field_name}'
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
hdr = res.get("header")
|
header = res.get("header")
|
||||||
txt = res.get("text")
|
text = res.get("text")
|
||||||
if not isinstance(hdr, str) or not isinstance(txt, str):
|
if not isinstance(header, str) or not isinstance(text, str):
|
||||||
raise ZenroomServiceError(f"Invalid asymmetric decrypt response: {res!r}")
|
raise ZenroomServiceError(f"Invalid asymmetric decrypt response: {res!r}")
|
||||||
|
|
||||||
return {"header": hdr, "text": txt}
|
return {"header": header, "text": text}
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Service 7: Sign-objects-using-asymmetric-cryptography
|
# Service 7: Sign-objects-using-asymmetric-cryptography
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def sign_objects(self, *, objects: Dict[str, Any], signer_keyring: Dict[str, Any]) -> Dict[str, Any]:
|
def sign_objects(self, *, objects: Dict[str, Any], signer_keyring: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Signs exactly one string field from `objects`.
|
Sign exactly one string field from `objects`.
|
||||||
|
|
||||||
Example:
|
Example input:
|
||||||
sign_objects(objects={"myMessage": "hello"}, signer_keyring=...)
|
{"myMessage": "hello"}
|
||||||
|
|
||||||
Returns e.g.:
|
Example output:
|
||||||
{
|
{
|
||||||
"myMessage": "hello",
|
"myMessage": "hello",
|
||||||
"myMessage.signature": {"r": "...", "s": "..."}
|
"myMessage.signature": {"r": "...", "s": "..."}
|
||||||
|
|
@ -440,12 +530,12 @@ Then print the '{field_name}'
|
||||||
)
|
)
|
||||||
|
|
||||||
sig_key = f"{field_name}.signature"
|
sig_key = f"{field_name}.signature"
|
||||||
sig = res.get(sig_key)
|
signature = res.get(sig_key)
|
||||||
|
|
||||||
if not isinstance(sig, dict):
|
if not isinstance(signature, dict):
|
||||||
raise ZenroomServiceError(f"Invalid signature object for {sig_key}: {res!r}")
|
raise ZenroomServiceError(f"Invalid signature object for {sig_key}: {res!r}")
|
||||||
if not isinstance(sig.get("r"), str) or not isinstance(sig.get("s"), str):
|
if not isinstance(signature.get("r"), str) or not isinstance(signature.get("s"), str):
|
||||||
raise ZenroomServiceError(f"Invalid signature fields for {sig_key}: {sig!r}")
|
raise ZenroomServiceError(f"Invalid signature fields for {sig_key}: {signature!r}")
|
||||||
|
|
||||||
if not isinstance(res.get(field_name), str):
|
if not isinstance(res.get(field_name), str):
|
||||||
raise ZenroomServiceError(f"Missing signed field {field_name!r} in response: {res!r}")
|
raise ZenroomServiceError(f"Missing signed field {field_name!r} in response: {res!r}")
|
||||||
|
|
@ -455,6 +545,7 @@ Then print the '{field_name}'
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Service 8: Verify-asymmetric-cryptography-signature
|
# Service 8: Verify-asymmetric-cryptography-signature
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def verify_signature(
|
def verify_signature(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
|
|
@ -463,6 +554,12 @@ Then print the '{field_name}'
|
||||||
signature: Dict[str, Any],
|
signature: Dict[str, Any],
|
||||||
signer_public_key: str,
|
signer_public_key: str,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Verify a signature over one named string field.
|
||||||
|
|
||||||
|
Returns True on success. Raises ZenroomServiceError on failure or if the
|
||||||
|
returned structure is unexpectedly malformed.
|
||||||
|
"""
|
||||||
message_field = self._require_safe_field_name(message_field)
|
message_field = self._require_safe_field_name(message_field)
|
||||||
message_value = self._require_non_empty_str("message_value", message_value)
|
message_value = self._require_non_empty_str("message_value", message_value)
|
||||||
signature = self._require_dict("signature", signature)
|
signature = self._require_dict("signature", signature)
|
||||||
|
|
@ -470,39 +567,50 @@ Then print the '{field_name}'
|
||||||
|
|
||||||
script = self.SCRIPT_VERIFY_TEMPLATE.format(field_name=message_field)
|
script = self.SCRIPT_VERIFY_TEMPLATE.format(field_name=message_field)
|
||||||
|
|
||||||
payload: Dict[str, Any] = {
|
|
||||||
message_field: message_value,
|
|
||||||
f"{message_field}.signature": signature,
|
|
||||||
"signer": {"public_key": signer_public_key},
|
|
||||||
}
|
|
||||||
|
|
||||||
res = self._run_script(
|
res = self._run_script(
|
||||||
"Verify-asymmetric-cryptography-signature",
|
"Verify-asymmetric-cryptography-signature",
|
||||||
script,
|
script,
|
||||||
data=payload,
|
data={
|
||||||
|
message_field: message_value,
|
||||||
|
f"{message_field}.signature": signature,
|
||||||
|
"signer": {"public_key": signer_public_key},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
out = res.get("output")
|
output = res.get("output")
|
||||||
if isinstance(out, list) and out:
|
if isinstance(output, list) and output:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Some Zenroom variants may print the success string directly as a named field
|
# Some Zenroom variants may return only the verified field itself.
|
||||||
# or return the verified message only. If execution succeeded and no exception
|
|
||||||
# was raised, we still treat that as success when the original message is present.
|
|
||||||
if res.get(message_field) == message_value:
|
if res.get(message_field) == message_value:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
raise ZenroomServiceError(f"Invalid verify response: {res!r}")
|
raise ZenroomServiceError(f"Invalid verify response: {res!r}")
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Backward-compatible alias names
|
# Backward-compatible aliases
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def generate_a_keypair_reading_identity_from_data(self, my_name: str) -> Dict[str, Any]:
|
def generate_a_keypair_reading_identity_from_data(self, my_name: str) -> Dict[str, Any]:
|
||||||
|
"""Backward-compatible alias."""
|
||||||
return self.generate_keypair(my_name)
|
return self.generate_keypair(my_name)
|
||||||
|
|
||||||
def encrypt_a_message_with_the_password(self, *, header: str, message: str, password: str) -> Dict[str, str]:
|
def encrypt_a_message_with_the_password(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
header: str,
|
||||||
|
message: str,
|
||||||
|
password: str,
|
||||||
|
) -> Dict[str, str]:
|
||||||
|
"""Backward-compatible alias."""
|
||||||
return self.symmetric_encrypt(header=header, message=message, shared_key=password)
|
return self.symmetric_encrypt(header=header, message=message, shared_key=password)
|
||||||
|
|
||||||
def decrypt_the_message_with_the_password(self, *, secret_message: Dict[str, Any], password: str) -> Dict[str, str]:
|
def decrypt_the_message_with_the_password(
|
||||||
txt = self.symmetric_decrypt(secret_message=secret_message, shared_key=password)
|
self,
|
||||||
return {"textDecrypted": txt}
|
*,
|
||||||
|
secret_message: Dict[str, Any],
|
||||||
|
password: str,
|
||||||
|
) -> Dict[str, str]:
|
||||||
|
"""Backward-compatible alias preserving the historical return shape."""
|
||||||
|
text = self.symmetric_decrypt(secret_message=secret_message, shared_key=password)
|
||||||
|
return {"textDecrypted": text}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,6 +1,9 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from ca_core.crypto.zenroom_service_client import ZenroomServiceClient
|
from ca_core.crypto.zenroom_service_client import (
|
||||||
|
ZenroomServiceClient,
|
||||||
|
ZenroomServiceError,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestZenroomServiceClient(unittest.TestCase):
|
class TestZenroomServiceClient(unittest.TestCase):
|
||||||
|
|
@ -157,6 +160,23 @@ class TestZenroomServiceClient(unittest.TestCase):
|
||||||
|
|
||||||
self.assertTrue(verified)
|
self.assertTrue(verified)
|
||||||
|
|
||||||
|
def test_9_verify_signature_rejects_modified_message(self):
|
||||||
|
alice = self.client.generate_keypair("Alice")
|
||||||
|
alice_public_key = self.client.generate_public_key(alice["keyring"])
|
||||||
|
|
||||||
|
signed = self.client.sign_objects(
|
||||||
|
objects={"myMessage": "hello"},
|
||||||
|
signer_keyring=alice["keyring"],
|
||||||
|
)
|
||||||
|
|
||||||
|
with self.assertRaises(ZenroomServiceError):
|
||||||
|
self.client.verify_signature(
|
||||||
|
message_field="myMessage",
|
||||||
|
message_value="tampered",
|
||||||
|
signature=signed["myMessage.signature"],
|
||||||
|
signer_public_key=alice_public_key,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue