csp.struct.yml 214 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099
  1. # Meta information
  2. meta:
  3. # Document name and ID
  4. id: csp
  5. name: Chat Server Protocol
  6. # References used by the structs
  7. references:
  8. # A public or secret key
  9. key: &key b32
  10. # A random cookie
  11. cookie: &cookie b16
  12. # A random nonce
  13. nonce: &nonce b24
  14. # A Threema ID
  15. identity: &identity b8
  16. # Multiple Threema IDs
  17. identities: &identities b8[]
  18. # A message ID
  19. message-id: &message-id u64-le
  20. # Multiple message IDs
  21. message-ids: &message-ids u64-le[]
  22. # A blob ID
  23. blob-id: &blob-id b16
  24. # A poll ID
  25. poll-id: &poll-id u64-le
  26. # A group ID
  27. group-id: &group-id u64-le
  28. # Virtual namespace, just containing the below docstring
  29. index: &index
  30. _doc: |-
  31. # Chat Server Protocol
  32. The Chat Server Protocol is a custom transport encrypted frame-based
  33. protocol, originally designed to operate on top of TCP. it uses the NaCl
  34. cryptography library to provide authentication, integrity and encryption.
  35. The login [**handshake**](ref:handshake) takes two round trips and
  36. establishes ephemeral encryption keys along the way. Authentication is
  37. solely based on the secret key associated to a Threema ID.
  38. After the handshake process, [**payloads**](ref:payload) can be exchanged
  39. bidirectionally although some payload structs may only be used in one
  40. direction. A client may now send and receive end-to-end encrypted
  41. [**messages**](ref:e2e) (wrapped in [message payload
  42. structs](ref:payload.container)).
  43. ## Terminology
  44. - `CK`: Client Key (permanent secret key associated to the Threema ID)
  45. - `SK`: Permanent Server Key
  46. - `TCK`: Temporary Client Key
  47. - `TSK`: Temporary Server Key
  48. - `CCK`: Client Connection Cookie
  49. - `SCK`: Server Connection Cookie
  50. - `CSN`: Client Sequence Number
  51. - `SSN`: Server Sequence Number
  52. - `ID`: The client's Threema ID
  53. ## General Information
  54. **Endianness:** All integers use little-endian encoding.
  55. **Encryption cipher:** XSalsa20-Poly1305, unless otherwise specified.
  56. **Nonce format:**
  57. - a 16 byte cookie (CCK/SCK), followed by
  58. - a monotonically increasing sequence number (CSN/SSN, u64-le).
  59. **Sequence number:** The sequence number starts with `1` and is counted
  60. separately for each direction (i.e. there is one sequence number counter for
  61. the client and one for the server). We will use `CSN+` and `SSN+` in this
  62. document to denote that the counter should be increased **after** the value
  63. has been inserted (i.e. semantically equivalent to `x++` in many languages).
  64. ## Size Limitations
  65. The chat server protocol currently allows for up to 8192 bytes within a
  66. single frame. Because we make heavy use of Protobuf messages, the overhead
  67. cannot be calculated reliably ahead of time. Therefore, the total amount of
  68. user-defined bytes should be constrained to ~7000 bytes. To achieve this,
  69. the maximum recommended size of each property will be defined for each
  70. message, so that it's total size roughly matches that constraint.
  71. # Handshake structs
  72. handshake: &handshake
  73. _doc: |-
  74. ## Handshake
  75. To perform authentication handshake, the following handshake structs have to
  76. be exchanged in this order:
  77. C -- client-hello -> S
  78. C <- server-hello -- S
  79. C ---- login ---- -> S
  80. C <-- login-ack ---- S
  81. Note that handshake structs have no wrapping frame container struct.
  82. client-hello:
  83. _doc: |-
  84. Initial message from the client, containing a server authentication
  85. challenge in order to establish transport layer encryption.
  86. Direction: Client --> Server
  87. fields:
  88. - _doc: |-
  89. 32 byte temporary public key (`TCK.public`).
  90. name: tck
  91. type: *key
  92. - _doc: |-
  93. 16 byte random cookie used for nonces (also acting as server
  94. authentication challenge).
  95. name: cck
  96. type: *cookie
  97. server-hello:
  98. _doc: |-
  99. Initial message from the server, containing the server's authentication
  100. challenge response. This concludes establishing transport layer
  101. encryption based on `TCK` and `TSK`.
  102. Direction: Client <-- Server
  103. When creating this message:
  104. 1. Ensure that CCK and SCK are not equal.
  105. When receiving this message:
  106. 1. If CCK and SCK are equal, abort the connection and these steps.
  107. 2. If the repeated random cookie of the client does not equal CCK,
  108. abort the connection and these steps.
  109. fields:
  110. - _doc: |-
  111. 16 byte random cookie used for nonces (also acting as client
  112. authentication challenge)
  113. name: sck
  114. type: *cookie
  115. - _doc: |-
  116. The server's challenge response (`server-challenge-response`),
  117. encrypted by:
  118. XSalsa20-Poly1305(
  119. key=X25519HSalsa20(SK.secret, TCK.public),
  120. nonce=SCK || u64-le(SSN+),
  121. )
  122. name: server-challenge-response-box
  123. type: b64
  124. server-challenge-response:
  125. _doc: |-
  126. Authentication challenge response from the server.
  127. fields:
  128. - _doc: |-
  129. 32 byte temporary public key (`TSK.public`)
  130. name: tsk
  131. type: *key
  132. - _doc: |-
  133. 16 byte repeated random cookie of the client (acting as the server's
  134. challenge response)
  135. name: cck
  136. type: *cookie
  137. login:
  138. _doc: |-
  139. Login request from the client.
  140. IMPORTANT: `CSN` is used and increased for `box` and then for
  141. `extension-box`. It must follow this exact order.
  142. Direction: Client --> Server
  143. fields:
  144. - _doc: |-
  145. The [`login-data`](ref:handshake.login-data), encrypted by:
  146. XSalsa20-Poly1305(
  147. key=X25519HSalsa20(TCK.secret, TSK.public),
  148. nonce=CCK || u64-le(CSN+),
  149. )
  150. name: box
  151. type: b144
  152. - _doc: |-
  153. An optional arbitrary amount of
  154. [`extension`](ref:handshake.extension)s, encrypted by:
  155. XSalsa20-Poly1305(
  156. key=X25519HSalsa20(TCK.secret, TSK.public),
  157. nonce=CCK || u64-le(CSN+),
  158. )
  159. These fields are only present if the
  160. [`extension-indicator`](ref:handshake.extension-indicator) of the
  161. [`login-data`](ref:handshake.login-data) field is present. If so,
  162. extensions should be consumed until the extension indicator `length`
  163. field is zero.
  164. name: extensions-box
  165. type: b*
  166. login-data:
  167. _doc: |-
  168. Login data of the client.
  169. fields:
  170. - _doc: |-
  171. Threema ID of the client.
  172. name: identity
  173. type: *identity
  174. - _doc: |-
  175. This is either the old client info field or an extension indicator.
  176. If the first 30 bytes of the field start with the string
  177. `threema-clever-extension-field`, then parse this field as an
  178. [`extension-indicator`](ref:handshake.extension-indicator) and parse
  179. `extensions-box` appropriately.
  180. Otherwise, this represents an old client info and the content is
  181. identical to the content of
  182. [`client-info`](ref:handshake.client-info). Since the field has a
  183. fixed size, the string is zero-padded.
  184. name: client-info-or-extension-indicator
  185. type: b32
  186. - _doc: |-
  187. 16 byte repeated random cookie of the server (acting as the client's
  188. challenge response)
  189. name: sck
  190. type: *cookie
  191. - _doc: |-
  192. 24 zero bytes (previously used as vouch nonce, now set to zero
  193. indicating that the new vouch format is being used)
  194. name: reserved1
  195. type: b24
  196. - _doc: |-
  197. The vouch value, calculated as follows:
  198. SS1 = X25519HSalsa20(CK.secret, SK.public)
  199. SS2 = X25519HSalsa20(CK.secret, TSK.public)
  200. VouchKey = BLAKE2b(key=SS1 || SS2, salt='v2', personal='3ma-csp')
  201. vouch = BLAKE2b(
  202. out-length=32,
  203. key=VouchKey,
  204. input=SCK || TCK.public,
  205. )
  206. name: vouch
  207. type: b32
  208. - _doc: |-
  209. 16 zero bytes (previously part of the vouch box, now set to zero for
  210. compatibility)
  211. name: reserved2
  212. type: b16
  213. extension-indicator:
  214. _doc: |-
  215. Indicates that extensions are present
  216. fields:
  217. - _doc: |-
  218. Magic string: `threema-clever-extension-field`
  219. name: magic
  220. type: b30
  221. - _doc: |-
  222. Amount of encrypted bytes present for extensions. Extension fields
  223. need to be consumed until `length` is zero.
  224. name: length
  225. type: u16-le
  226. extension:
  227. _doc: |-
  228. An extension field.
  229. fields:
  230. - _doc: |-
  231. Type of the extension. Must correspond to the encoded extension struct
  232. of the `payload` field:
  233. - `0x00`: `client-info`
  234. - `0x01`: `csp-device-id`
  235. - `0x02`: `message-payload-version`
  236. - `0x03`: `device-cookie`
  237. name: type
  238. type: u8
  239. - _doc: |-
  240. Length of the extension's `payload` field.
  241. name: length
  242. type: u16-le
  243. - _doc: |-
  244. Extension payload. Needs to be parsed according to the `type` field.
  245. name: payload
  246. type: b{length}
  247. client-info:
  248. _doc: |-
  249. Client info extension payload.
  250. fields:
  251. - _doc: |-
  252. Client info string in the following format (without line breaks):
  253. <app-version>;
  254. <platform>;
  255. <lang>/<country-code>;
  256. <rest>
  257. The `<rest>` looks like this for mobile clients (A/I/W):
  258. <device-model>;
  259. <os-version>
  260. The `<rest>` looks like this for web/desktop clients (Q):
  261. <renderer>;
  262. <renderer-version>;
  263. <os-name>;
  264. <os-architecture>
  265. The `<rest>` looks like this for Bots (B):
  266. <os-name>;
  267. <os-architecture>
  268. The fields may contain the following values:
  269. - `app-version`: Arbitrary version string, depending on the platform
  270. - `platform`:
  271. * `A`: Android
  272. * `I`: iOS
  273. * `Q`: Desktop/Web
  274. * `W`: Windows Phone
  275. * `B`: Bot
  276. - `lang`: ISO 639-1:2002-ish language code
  277. - `country-code`: ISO 3166-1-ish country code
  278. - `device-model`: Arbitrary smartphone model
  279. - `os-version`: Arbitrary OS version string
  280. - `renderer`: Renderer name for Desktop/Web (e.g. `Firefox` or
  281. `Electron`)
  282. - `renderer-version`: Renderer major version (e.g. `107`)
  283. - `os-name`: Name of the operating system (e.g. `Linux` or `Windows`)
  284. - `os-architecture`: Architecture of the operating system (e.g. `x64`)
  285. name: client-info
  286. type: b*
  287. csp-device-id:
  288. _doc: |-
  289. CSP device ID extension payload.
  290. fields:
  291. - _doc: |-
  292. CSP device ID, randomly generated **once** when the device got the
  293. Mediator device ID.
  294. name: csp-device-id
  295. type: u64-le
  296. message-payload-version:
  297. _doc: |-
  298. Message payload struct version to be used.
  299. In case this extension is not present, the server must assume that
  300. version `0x00` has been selected.
  301. In case the server receives an unknown or unsupported protocol version,
  302. it shall complete the handshake and then immediately send a `close-error`
  303. payload.
  304. fields:
  305. - _doc: |-
  306. Indicates the payload struct version the client will send and expects
  307. to receive when exchanging message payload structs with the server:
  308. - `0x00`: `legacy-message`
  309. - `0x01`: `message-with-metadata-box`
  310. name: version
  311. type: u8
  312. device-cookie:
  313. _doc: |-
  314. A 16 byte random value chosen by the client and stored in a secure,
  315. device-specific location (not included in any backups etc., not
  316. viewable/exportable).
  317. Its purpose is to allow detection when a different (rogue) device has
  318. connected to the chat server, e.g. because an attacker has obtained
  319. the secret key of a user.
  320. The server will store the device cookie of the last connection, and if a
  321. different cookie is sent by the client, it will set a flag on the identity
  322. and send a
  323. [`device-cookie-change-indication`](ref:payload.device-cookie-change-indication)
  324. payload to the client every time it connects. The client should then show
  325. a warning in form of a notification or a dialog to the user. Note that the
  326. normal protocol flow should continue regardless of whether the user has
  327. acknowledged the warning or not.
  328. If this extension is not sent by the client, then the server's behavior
  329. depends on whether it has already stored a device cookie for this
  330. identity or not. If not, then nothing will happen. If yes, then it will
  331. act as if the client had sent an all-zero device cookie.
  332. fields:
  333. - _doc: |-
  334. Device cookie, randomly generated **once** per device.
  335. name: device-cookie
  336. type: b16
  337. login-ack:
  338. _doc: |-
  339. Login acknowledgement from the server.
  340. Direction: Client <-- Server
  341. fields:
  342. - _doc: |-
  343. Reserved (16 zero bytes), encrypted by:
  344. XSalsa20-Poly1305(
  345. key=X25519HSalsa20(TSK.secret, TCK.public),
  346. nonce=SCK || u64-le(SSN+),
  347. )
  348. name: reserved-box
  349. type: b32
  350. # Payload structs
  351. payload: &payload
  352. _doc: |-
  353. ## Payload
  354. After the handshake process, payloads may be sent and received without any
  355. strictly defined order.
  356. Note that payload structs are mandatory to encrypt and frame. To achieve
  357. this, first wrap the payload struct in a
  358. [`container`](ref:payload.container) struct, encrypt it and wrap the
  359. encrypted bytes in a [`frame`](ref:payload.frame) struct.
  360. frame:
  361. _group: Header
  362. _doc: |-
  363. Contains an encrypted [payload](ref:payload#payload) wrapped in a
  364. [container](ref:payload.container).
  365. Direction: Client <-> Server
  366. fields:
  367. - _doc: |-
  368. Length of the `box` field.
  369. name: length
  370. type: u16-le
  371. - _doc: |-
  372. The encrypted [payload](ref:payload#payload).
  373. For messages from the server to the client, encrypted by:
  374. XSalsa20-Poly1305(
  375. key=X25519HSalsa20(TSK.secret, TCK.public),
  376. nonce=SCK || u64-le(SSN+),
  377. )
  378. For messages from the client to the server, encrypted by:
  379. XSalsa20-Poly1305(
  380. key=X25519HSalsa20(TSK.secret, TCK.public),
  381. nonce=CCK || u64-le(CSN+),
  382. )
  383. name: box
  384. type: b{length}
  385. container:
  386. _group: Header
  387. _doc: |-
  388. Contains an inner [payload](ref:payload#payload) struct.
  389. Direction: Client <-> Server
  390. fields:
  391. - _doc: |-
  392. Type of the payload. Must correspond to the encoded payload struct
  393. of the `data` field:
  394. - `0x00`: [`echo-request`](ref:payload.echo-request)
  395. - `0x80`: [`echo-response`](ref:payload.echo-response)
  396. - `0x01`: outgoing [`legacy-message`](ref:payload.legacy-message) or
  397. [`message-with-metadata-box`](ref:payload.message-with-metadata-box)
  398. - `0x81`: outgoing [`message-ack`](ref:payload.message-ack)
  399. - `0x02`: incoming [`legacy-message`](ref:payload.legacy-message) or
  400. [`message-with-metadata-box`](ref:payload.message-with-metadata-box)
  401. - `0x82`: incoming [`message-ack`](ref:payload.message-ack)
  402. - `0x03`: [`unblock-incoming-messages`](ref:payload.unblock-incoming-messages)
  403. - `0x20`: [`set-push-notification-token`](ref:payload.set-push-notification-token)
  404. - `0x21`: (obsolete, formerly used by iOS to set a push filter)
  405. - `0x22`: (obsolete, formerly used by iOS to set a push sound for contacts)
  406. - `0x23`: (obsolete, formerly used by iOS to set a push sound for groups)
  407. - `0x24`: high-priority token for notifications that require
  408. immediate delivery (e.g. for calls) using the same struct as
  409. [`set-push-notification-token`](ref:payload.set-push-notification-token)
  410. - `0x25`: [`delete-push-notification-token`](ref:payload.delete-push-notification-token)
  411. - `0x30`: [`set-connection-idle-timeout`](ref:payload.set-connection-idle-timeout)
  412. - `0x31`: (obsolete, formerly used to ensure that a push message is
  413. sent for all messages, regardless of the flag)
  414. - `0xd0`: [`queue-send-complete`](ref:payload.queue-send-complete)
  415. - `0xd1`: (obsolete, formerly used for a function similar to the
  416. device cookie)
  417. - `0xd2`: [`device-cookie-change-indication`](ref:payload.device-cookie-change-indication)
  418. - `0xd3`: [`clear-device-cookie-change-indication`](ref:payload.clear-device-cookie-change-indication)
  419. - `0xe0`: [`close-error`](ref:payload.close-error)
  420. - `0xe1`: [`alert`](ref:payload.alert)
  421. name: type
  422. type: u8
  423. - _doc: |-
  424. Reserved, currently all zeroes.
  425. name: reserved
  426. type: b3
  427. - _doc: |-
  428. Inner payload. Needs to be parsed according to the `type` field.
  429. name: data
  430. type: b*
  431. echo-request:
  432. _group: Payloads
  433. _doc: |-
  434. An echo request to be answered by a corresponding echo response.
  435. Can be used for connection keep-alive or RTT estimation.
  436. Direction: Client <-> Server
  437. [//]: # "TODO(SE-128)"
  438. fields:
  439. - _doc: |-
  440. Data to be echoed back in the echo response.
  441. name: data
  442. type: b*
  443. echo-response:
  444. _group: Payloads
  445. _doc: |-
  446. An echo response corresponding to an echo request.
  447. Direction: Client <-> Server
  448. [//]: # "TODO(SE-128)"
  449. fields:
  450. - _doc: |-
  451. Data echoed back from the echo request.
  452. name: data
  453. type: b*
  454. legacy-message:
  455. _group: Payloads
  456. _doc: |-
  457. An end-to-end encrypted Threema message.
  458. Direction: Client <-> Server
  459. Note: This payload is deprecated and may be phased out eventually. It
  460. will only be used in case the
  461. [`message-payload-version`](ref:handshake.message-payload-version)
  462. was not present during login or was explicitly set to the version
  463. `0x00`.
  464. Conversion to [`message-with-metadata-box`](ref:payload.message-with-metadata-box):
  465. - Copy `legacy-message.sender-nickname` to
  466. `message-with-metadata-box.legacy-sender-nickname`
  467. - Copy all other fields of `legacy-message` to their respective
  468. counterparts in `message-with-metadata-box`
  469. - Set `message-with-metadata-box.metadata-length` to `0`
  470. - Omit `message-with-metadata-box.metadata-container` (i.e. set it to
  471. contain 0 bytes)
  472. - Copy `legacy-message.message-nonce` to
  473. `message-with-metadata-box.message-and-metadata-nonce`.
  474. When sending or receiving this payload, convert it to a
  475. `message-with-metadata-box` and handle it as defined by that struct.
  476. [//]: # "TODO(SE-128)"
  477. fields:
  478. - &message-sender-identity
  479. _doc: |-
  480. The sender's Threema ID.
  481. name: sender-identity
  482. type: *identity
  483. - &message-receiver-identity
  484. _doc: |-
  485. The receiver's Threema ID.
  486. name: receiver-identity
  487. type: *identity
  488. - &message-message-id
  489. _doc: |-
  490. Unique message ID for each sender/receiver pair.
  491. Used for duplicate detection and for quotes.
  492. Messages sent in a group must have the same message ID for each group
  493. member.
  494. name: message-id
  495. type: *message-id
  496. - &message-created-at
  497. _doc: |-
  498. Unix timestamp in seconds for when the message has been created.
  499. Messages sent in a group must have the same timestamp for each group
  500. member.
  501. However, the server overrides this timestamp with the current time if
  502. - the declared timestamp is in the future, or
  503. - the _short-lived server queuing_ flag was set (`0x20`).
  504. Note: The original timestamp is still available in an attached
  505. `csp-e2e.MessageMetadata`.
  506. name: created-at
  507. type: u32-le
  508. - &message-flags
  509. _doc: |-
  510. Flags:
  511. - `0x01`: Send push notification. The server will send a push message
  512. to the receiver of the message. Only use this for messages that
  513. require a notification. For example, do not set this for delivery
  514. receipts.
  515. - `0x02`: No server queuing. Use this for messages that can be
  516. discarded by the chat server in case the receiver is not connected
  517. to the chat server, e.g. the _typing_ indicator.
  518. - `0x04`: No server acknowledgement. Use this for messages where reliable
  519. delivery and acknowledgement is not essential, e.g. the _typing_
  520. indicator. Will not be acknowledged by the chat server when sending.
  521. No acknowledgement should be sent by the receiver to the chat
  522. server.
  523. - `0x10`: Reserved (formerly _group message marker_).
  524. - `0x20`: Short-lived server queuing. Messages with this flag will
  525. only be queued for 60 seconds.
  526. - `0x80`: No automatic delivery receipts. A receiver of a message with this
  527. flag must not send automatic delivery receipt of type _received_
  528. (`0x01`) or _read_ (`0x02`). This is not used by the apps but can be
  529. used by Threema Gateway IDs which do not necessarily want a delivery
  530. receipt for a message.
  531. name: flags
  532. type: u8
  533. - &message-reserved
  534. _doc: |-
  535. Reserved, must be set to zero.
  536. name: reserved
  537. type: u8
  538. - _doc: |-
  539. Reserved for header compatibility with metadata message.
  540. Must be set to zero by legacy clients.
  541. name: reserved-metadata-length
  542. type: b2
  543. - _doc: |-
  544. The sender's public nickname, padded with zeroes if needed.
  545. name: sender-nickname
  546. type: b32
  547. - _doc: |-
  548. Nonce used for the message box.
  549. name: message-nonce
  550. type: *nonce
  551. - &message-message-box
  552. _doc: |-
  553. The message, end-to-end encrypted by:
  554. XSalsa20-Poly1305(
  555. key=X25519HSalsa20(<sender.CK>.secret, <receiver.CK>.public),
  556. nonce=<message-nonce>,
  557. )
  558. name: message-box
  559. type: b*
  560. message-with-metadata-box:
  561. _group: Payloads
  562. _doc: |-
  563. An end-to-end encrypted Threema message with additional end-to-end
  564. encrypted metadata.
  565. Direction: Client <-> Server
  566. Note: This payload will only be used in case the
  567. [`message-payload-version`](ref:handshake.message-payload-version)
  568. was set to version `0x01`.
  569. Conversion to [`legacy-message`](ref:payload.legacy-message):
  570. - Discard `message-with-metadata-box.metadata-length` and
  571. `message-with-metadata-box.metadata-container`
  572. - Copy `message-with-metadata-box.legacy-sender-nickname` to
  573. `legacy-message.sender-nickname`
  574. - Copy `message-with-metadata-box.message-and-metadata-nonce` to
  575. `legacy-message.message-nonce`.
  576. - Copy all other fields of `message-with-metadata-box` to their
  577. respective counterparts in `legacy-message`
  578. Creating this payload is only allowed as part of the _Bundled Messages
  579. Send Steps_.
  580. When receiving this payload:
  581. 1. (MD) If the device is currently not declared _leader_, exceptionally
  582. abort these steps and the connection.
  583. 2. If the nonce of `message-and-metadata-nonce` has been used before, log
  584. a warning, _Acknowledge_ and discard the message and abort these steps.
  585. 3. If `receiver-identity` does not equal the user's Threema ID, log a
  586. warning, _Acknowledge_ and discard the message and abort these steps.
  587. 4. Run the _Valid Contacts Lookup Steps_ for `sender-identity` and let
  588. `contact-or-init` be the result.
  589. 5. If `contact-or-init` indicates that the _contact is the user_ or that
  590. the _contact is invalid_, log a warning, _Acknowledge_ and discard the
  591. message and abort these steps.
  592. 6. If `metadata-length` is greater zero, decrypt the `metadata-container`
  593. and let `outer-metadata` be the result. If this fails, log a warning,
  594. _Acknowledge_ and discard the message and abort these steps.
  595. 7. Decrypt the `message-box`, decode it to a
  596. [`container`](ref:payload.container) struct and let `outer` be the
  597. result. If this fails, log a warning, _Acknowledge_ and discard the
  598. message and abort these steps.
  599. 8. If `outer.type` is `0xff`, log a warning, _Acknowledge_ and
  600. discard the message and abort these steps. (Legacy logic, may be
  601. removed in the future.)
  602. 9. If `outer.type` is unknown, log a notice, _Acknowledge_ and
  603. discard the message and abort these steps.
  604. 10. Decode `outer.padded-data` into the message type associated to
  605. `outer.type` and let `outer-message` be the result. If this fails, log
  606. a warning, _Acknowledge_ and discard the message and abort these
  607. steps.
  608. 11. If `outer.type` is not `0xa0`, let `inner-metadata` be
  609. `outer-metadata`, let `inner-type` be `outer.type` and let
  610. `inner-message` be `outer-message`.
  611. 12. If `outer.type` is `0xa0`:
  612. 1. Run the receive steps associated to
  613. `csp-e2e-fs.Envelope` with the decoded `outer-message` and let
  614. `inner-metadata`, `inner-type`, `inner-message` and `fs-commit-fn`
  615. be the result. If this fails, exceptionally abort these steps and
  616. the connection. If the message has been discarded, _Acknowledge_
  617. and abort these steps.
  618. 2. If `inner-metadata` is not defined, set `inner-metadata` to
  619. `outer-metadata`.
  620. 13. If `message-id` does not equal `inner-metadata.message_id`, log a
  621. warning, _Acknowledge_ and discard the message and abort these steps.
  622. 14. If `message-id` refers to a message that has been received previously
  623. from `sender-identity` (including group messages), log a warning,
  624. _Acknowledge_ and discard the message and abort these steps.
  625. 15. If `inner-type` is not defined (i.e. handling an FS control message),
  626. log a notice, _Acknowledge_ and discard the message and abort these
  627. steps.
  628. 16. If `inner-type` is unknown, log a notice, _Acknowledge_ and
  629. discard the message and abort these steps.
  630. 17. If `inner-type` is `0xa0` (i.e. FS encapsulation within FS
  631. encapsulation), log a warning, _Acknowledge_ and discard the message
  632. and abort these steps.
  633. 18. If `inner-type` has dedicated blocking exemption steps, run these with
  634. `sender-identity` and `inner-message`. If the result indicates that
  635. the message should be discarded, _Acknowledge_ the message and abort
  636. these steps.
  637. 19. If `inner-type` does not have dedicated blocking exemption steps and
  638. is not exempted from blocking, run the _Identity Blocked Steps_ for
  639. `sender-identity`. If the result indicates that `sender-identity` is
  640. blocked, _Acknowledge_ and discard the message and abort these steps.
  641. 20. If `sender-identity` equals `*3MAPUSH`:
  642. 1. If `inner-type` is not `0xfe`, log a warning,
  643. _Acknowledge_ and discard the message and abort these steps.
  644. 2. Run the receive steps associated to `inner-type` with
  645. `inner-message`. If this fails, exceptionally abort these steps and
  646. the connection. If the message has been discarded, _Acknowledge_
  647. the message and abort these steps.
  648. 21. If `sender-identity` is not a _Special Contact_:
  649. 1. If `inner-metadata.nickname` is defined, let `nickname` be the
  650. value of `inner-metadata.nickname`.¹
  651. 2. If `inner-metadata` is not defined and _User Profile Distribution_
  652. was expected for `inner-type`, let `nickname` be the result of
  653. decoding the plaintext `legacy-sender-nickname`.¹
  654. 3. If `nickname` is present, trim any excess whitespaces from the
  655. beginning and the end of `nickname`.
  656. 4. If `contact-or-init` does not contain an existing contact:
  657. 1. If `inner-type` does not require to create an implicit
  658. _direct_ contact, log a notice, _Acknowledge_ and discard the
  659. message and abort these steps.
  660. 2. (MD) Run the following sub-steps (labelled _add-contact_):
  661. 1. Begin a transaction with scope `CONTACT_SYNC` and the
  662. following precondition:
  663. 1. If the contact for `sender-identity` exists, abort the
  664. _add-contact_ sub-steps.
  665. 2. Reflect a `ContactSync.Create` with `contact` set from
  666. `contact-or-init` and the following additional properties:
  667. - `created_at` set to now,
  668. - `nickname` set to `nickname`,
  669. - `acquaintance_level` set to `DIRECT`,
  670. - all policies and categories set to their defaults.
  671. 3. Commit the transaction and await acknowledgement.
  672. 3. If the contact for `sender-identity` does not exist, persist a
  673. new contact from `contact-or-init` and `nickname`.
  674. 4. TODO(SE-510): Schedule fetching gateway-defined profile picture
  675. here, if contact was added and if necessary.
  676. 5. Lookup the contact associated to `sender-identity` and let
  677. `contact` be the result (at this point, `contact` must exist).
  678. 6. (MD) If the contact's nickname is different to `nickname`:
  679. 1. Begin a transaction with scope `CONTACT_SYNC` and the
  680. following precondition:
  681. 1. If the contact no longer exists, log an error and
  682. exceptionally abort these steps and the connection.
  683. 2. Reflect a `ContactSync.Update` with `contact` including the
  684. new `nickname`.
  685. 3. Commit the transaction and await acknowledgement.
  686. 7. Update the contact's nickname with `nickname`. Remove the
  687. contact's nickname if `nickname` is empty.
  688. 8. Run the receive steps associated to `inner-type` with
  689. `inner-message`. If this fails, exceptionally abort these steps and
  690. the connection. If the message has been discarded, _Acknowledge_
  691. the message and abort these steps.
  692. 22. (MD) If the properties associated to `inner-type` require
  693. reflecting incoming messages, reflect a `d2d.IncomingMessage` from
  694. `outer-type` and `outer-message` and the associated conversation to
  695. other devices and wait for reflection acknowledgement.² If this fails,
  696. exceptionally abort these steps and the connection.³
  697. 23. If the properties associated to `inner-type` require sending
  698. automatic delivery receipts and `flags` does not contain the _no
  699. automatic delivery receipts_ (`0x80`) flag, schedule a persistent task
  700. to run the _Bundled Messages Send Steps_ with the following
  701. properties:
  702. - `id` being a random message ID,
  703. - `created-at` set to the current timestamp,
  704. - `receivers` set to `contact`,
  705. - to construct a [`delivery-receipt`](ref:e2e.delivery-receipt)
  706. message with status _received_ (`0x01`) and the respective
  707. `message-id`.
  708. 24. _Acknowledge_ the message.
  709. ¹: Note that the `nickname` of `MessageMetadata` may be undefined (leading
  710. to no changes) or defined but explicitly empty (leading to the nickname of
  711. the contact being removed) which is an important semantic difference.
  712. Unlike the legacy nickname field which always contains a value and
  713. therefore cannot represent this semantic difference without having to
  714. check whether _User Profile Distribution_ was required for the type.
  715. ²: We reflect the **outer** message container depending on the unwrapped
  716. **inner** message type, so the forward security properties are untouched
  717. and all other devices need to go through the same process.
  718. ³: Reflection needs to happen after the message has been processed and all
  719. side effects have been applied. Otherwise, if the receive process is
  720. interrupted and another device takes over, it would discard the message as
  721. a duplicate.
  722. The following steps are defined as _Acknowledge_ steps for an incoming
  723. message:
  724. 1. If the steps for this message have already been invoked once, abort
  725. these steps.
  726. 2. If `flags` does not contain the _no server acknowledgement_ (`0x04`)
  727. flag, send a [`message-ack`](ref:payload.message-ack) payload to the
  728. chat server with the respective `message-id`.
  729. 3. If the properties associated to `inner-type` require protection against
  730. replay, mark the nonce of `message-and-metadata-nonce` as used.
  731. 4. If `fs-commit-fn` is defined, run it.
  732. [//]: # "TODO(SE-128)"
  733. fields:
  734. - *message-sender-identity
  735. - *message-receiver-identity
  736. - *message-message-id
  737. - *message-created-at
  738. - *message-flags
  739. - *message-reserved
  740. - _doc: |-
  741. Length of the metadata box. In case it is zero, no metadata is
  742. present (for compatibility with clients using
  743. [`legacy-message`](ref:payload.legacy-message)).
  744. Note: For outgoing messages, a metadata box should always be present.
  745. name: metadata-length
  746. type: u16-le
  747. - _doc: |-
  748. Backwards compatibility field for the sender's public nickname.
  749. Padded with zeroes if needed.
  750. When sending a message towards a Threema Gateway ID (starts with a
  751. `*`), add the same nickname as included in the encrypted metadata box.
  752. Otherwise, set it to all zeroes.
  753. Note: The backwards compatibility for Threema Gateway IDs will be
  754. removed eventually!
  755. name: legacy-sender-nickname
  756. type: b32
  757. - _doc: |-
  758. Metadata associated to the message. Must be ignored in case
  759. `metadata-length` is zero.
  760. Message Metadata Key (`MMK`) derivation:
  761. S = X25519HSalsa20(<sender.CK>.secret, <receiver.CK>.public)
  762. MMK = BLAKE2b(key=S, salt='mm', personal='3ma-csp')
  763. The encoded `csp-e2e.MessageMetadata` is then encrypted in the
  764. following way:
  765. XSalsa20-Poly1305(
  766. key=MMK,
  767. nonce=<message-with-metadata-box.message-and-metadata-nonce>,
  768. )
  769. name: metadata-container
  770. type: b{metadata-length}
  771. - _doc: |-
  772. Nonce used for the message and the metadata box.
  773. name: message-and-metadata-nonce
  774. type: *nonce
  775. - *message-message-box
  776. message-ack:
  777. _group: Payloads
  778. _doc: |-
  779. Acknowledges that a message has been received.
  780. Direction: Client <-> Server
  781. [//]: # "TODO(SE-128)"
  782. fields:
  783. - _doc: |-
  784. Identity of the sender for an incoming (`0x82`) message / of the
  785. receiver for an outgoing (`0x81`) message.
  786. name: identity
  787. type: *identity
  788. - _doc: |-
  789. Refers to the `message-id` of the acknowledged message.
  790. name: message-id
  791. type: *message-id
  792. unblock-incoming-messages:
  793. _group: Payloads
  794. _doc: |-
  795. Unblock incoming messages from the server. Sent by a multi-device capable
  796. client once it is nominated to receive incoming messages.
  797. Direction: Client --> Server
  798. [//]: # "TODO(SE-128)"
  799. set-push-notification-token:
  800. _group: Payloads
  801. _doc: |-
  802. Sets the push notification token to be used when sending a push message.
  803. Direction: Client --> Server
  804. fields:
  805. - _doc: |-
  806. Type of the push token:
  807. - `0x00`: No push
  808. - `0x01`: APNs Production
  809. - `0x02`: APNs Development
  810. - `0x05`: APNs Production with `mutable-content` key
  811. - `0x06`: APNs Development with `mutable-content` key
  812. - `0x11`: FCM with empty payload
  813. - `0x13`: HMS with empty payload
  814. name: type
  815. type: u8
  816. - _doc: |-
  817. Push token, maximum 255 bytes.
  818. name: token
  819. type: b*
  820. delete-push-notification-token:
  821. _group: Payloads
  822. _doc: |-
  823. Deletes push tokens for a Threema ID. Can be used when self-removing or
  824. removing another device from a device group.
  825. Direction: Client --> Server
  826. When receiving this payload:
  827. 1. If `csp-device-ids` is empty, delete all tokens for all devices except
  828. the device sending the payload and abort these steps.
  829. 2. Delete all tokens for the devices specified in `csp-device-ids`.
  830. fields:
  831. - _doc: |-
  832. Delete tokens belonging to a
  833. [`csp-device-id`](ref:handshake.csp-device-id) in the same device
  834. group.
  835. name: csp-device-ids
  836. type: u64-le[]
  837. set-connection-idle-timeout:
  838. _group: Payloads
  839. _doc: |-
  840. Request a different idle timeout than the default one of 5 minutes. The
  841. new setting is valid for the connection only.
  842. The client must ensure that it sends echo requests or other traffic
  843. frequently to keep the connection alive.
  844. Direction: Client --> Server
  845. [//]: # "TODO(SE-128)"
  846. fields:
  847. - _doc: |-
  848. Idle timeout in seconds. Minium 30s, maximum 600s.
  849. name: timeout
  850. type: u16-le
  851. queue-send-complete:
  852. _group: Payloads
  853. _doc: |-
  854. Indicates that the incoming message queue on the server has been fully
  855. transmitted to the client. A client should not disconnect prior to
  856. having received this payload.
  857. Direction: Client <-- Server
  858. [//]: # "TODO(SE-128)"
  859. device-cookie-change-indication:
  860. _group: Payloads
  861. _doc: |-
  862. Indicates to the client that a device cookie mismatch has been detected
  863. since the last time that the device cookie change indication has been
  864. cleared (using the
  865. [`clear-device-cookie-change-indication`](ref:clear-device-cookie-change-indication)
  866. payload).
  867. The client should display a warning in form of a notification and/or
  868. dialog to the user, informing them that a new and potentially unauthorized
  869. device has accessed the account. When the user confirms, the client should
  870. send a
  871. [`clear-device-cookie-change-indication`](ref:clear-device-cookie-change-indication)
  872. payload to clear the indication.
  873. Direction: Client <-- Server
  874. clear-device-cookie-change-indication:
  875. _group: Payloads
  876. _doc: |-
  877. Causes the server to clear the flag that triggers sending the
  878. [`device-cookie-change-indication`](ref:device-cookie-change-indication)
  879. on each connection.
  880. The flag will be set again by the server if another device cookie
  881. mismatch is detected.
  882. Direction: Client --> Server
  883. close-error:
  884. _group: Payloads
  885. _doc: |-
  886. Indicates that the connection has experienced an unrecoverable error and
  887. must be closed.
  888. Direction: Client <-- Server
  889. [//]: # "TODO(SE-128)"
  890. fields:
  891. - _doc: |-
  892. Indicates whether the client is allowed to reconnect automatically
  893. after the connection has been severed. This allows the server to
  894. prevent infinite loops in case of a recurring error.
  895. Set to `0` in case the client may not reconnect automatically or any
  896. other value otherwise.
  897. name: can-reconnect
  898. type: u8
  899. - _doc: |-
  900. Error message (UTF-8 encoded)
  901. name: message
  902. type: b*
  903. alert:
  904. _group: Payloads
  905. _doc: |-
  906. Generic alert that should be displayed in the client's user interface.
  907. Direction: Client <-- Server
  908. [//]: # "TODO(SE-128)"
  909. fields:
  910. - _doc: |-
  911. Alert message (UTF-8 encoded)
  912. name: message
  913. type: b*
  914. # End-to-end encrypted structs
  915. e2e: &e2e
  916. _doc: |-
  917. ## End-to-End Encrypted Messages
  918. An end-to-end encrypted message can be sent or received once the handshake
  919. was successful. Every end-to-end encrypted message is wrapped inside of a
  920. [`container`](ref:payload.container) struct that is then encrypted and
  921. wrapped by a payload [`legacy-message`](ref:payload.legacy-message) or
  922. [`message-with-metadata-box`](ref:payload.message-with-metadata-box)
  923. struct.
  924. ### Predefined Contacts
  925. A pedefined contacts can be added to the contact list and is automatically
  926. initialised with its identity, nickname, hard-coded public key and the verification
  927. level _fully verified_. Once a predefined contact is in the contact list, it
  928. is treated like any other normal contact (with editable properties like
  929. first and last name, etc.).
  930. A predefined contact may be marked _special_ meaning it follows special
  931. logic. These are also known as _Special Contact_s. Even though special
  932. contacts should not normally appear in the contact list, there's nothing
  933. stopping a user from adding a special contact to its contact list. While
  934. they are treated like normal contacts in the contact list, depending on the
  935. special handling logic, it may not be possible to send or receive normal
  936. messages from them.
  937. The following list contains all predefined contacts:
  938. - `*3MAPUSH`:
  939. - Nickname: Threema Push
  940. - Public Key:
  941. - Production: fd711e1a0db0e2f03fcaab6c43da2575b9513664a62a12bd0728d87f7125cc24
  942. - Sandbox: fd711e1a0db0e2f03fcaab6c43da2575b9513664a62a12bd0728d87f7125cc24
  943. - Special: Yes
  944. - `*3MATOKN`:
  945. - Nickname: Threema Token
  946. - Public Key:
  947. - Production: 04884d12d668f855d00d71fb1d9d413c95f271312f7e077846af671875c4101b
  948. - Special: No
  949. - `*3MAWORK`:
  950. - Nickname: Threema Work Channel
  951. - Public Key:
  952. - Production: 9aa0a72a8fb6f0cc53727fea6096f1b7b0ebefcc2650ad39a1e54837bba0bc4b
  953. - Sandbox: 9aa0a72a8fb6f0cc53727fea6096f1b7b0ebefcc2650ad39a1e54837bba0bc4b
  954. - Special: No
  955. - `*BETAFBK`:
  956. - Nickname: Threema Beta Feedback
  957. - Public Key:
  958. - Production: 5684d6dcd32a16488df8371095fc9a1fc25baeb6b97366d99fdf2aba00e2bc5c
  959. - Special: No
  960. - `*MY3DATA`:
  961. - Nickname: My Threema Data
  962. - Public Key:
  963. - Production: 3b01854f24736e2d0d2dc387eaf2c0273c5049052147132369bf3960d0a0bf02
  964. - Sandbox: 83adfee6558b68ae3cd6bbe2a33f4e4409d5624a7cea23a18975aea6272a0070
  965. - Special: No
  966. - `*SUPPORT`:
  967. - Nickname: Threema Support
  968. - Public Key:
  969. - Production: 0f944d18324b2132c61d8e40afce60a0ebd701bb11e89be94972d4229e94722a
  970. - Sandbox: 0f944d18324b2132c61d8e40afce60a0ebd701bb11e89be94972d4229e94722a
  971. - Special: No
  972. - `*THREEMA`:
  973. - Nickname: Threema Channel
  974. - Public Key:
  975. - Production: 3a38650c681435bd1fb8498e213a2919b09388f5803aa44640e0f706326a865c
  976. - Sandbox: 3a38650c681435bd1fb8498e213a2919b09388f5803aa44640e0f706326a865c
  977. - Special: No
  978. Note: OnPrem provisions predefined contacts in the associated OPPF file.
  979. ### Mitigating Replay
  980. To prevent replay attacks, a client must permanently store used nonces for
  981. incoming and outgoing end-to-end encrypted messages. Messages reusing
  982. previously used nonces must not be processed and discarded. One nonce
  983. store for all end-to-end encrypted messages across different contacts is
  984. sufficient.
  985. Note that it is still possible for the chat server to replay old messages to
  986. a device whose database has been erased (e.g. when restoring a backup).
  987. However, this is not applicable to forward security encrypted messages.
  988. ### Message ID
  989. Each message has an associated message ID. It is crucial to understand
  990. that this is not a unique identifier across multiple conversations.
  991. Unique identification of a message is determined by:
  992. - 1:1 Chats: The message ID in combination with the contact's Threema ID.
  993. - Group Chats: The message ID in combination with the group creator's
  994. Threema ID and the group ID.
  995. - Distribution Lists: The message ID with an artificial distribution list
  996. ID.
  997. When a message is being quoted, it may only be looked up within the
  998. associated conversation.
  999. ### Flags
  1000. For each message, we will define _mandatory_ and _optional_ flags
  1001. referring to the `flags` field of the payload
  1002. [`legacy-message`](ref:payload.legacy-message) or
  1003. [`message-with-metadata-box`](ref:payload.message-with-metadata-box)
  1004. struct. A flag must be considered _mandatory_ unless it has been explicitly
  1005. marked _optional_.
  1006. ### Delivery Receipts
  1007. There are two types of delivery receipts (sent using the
  1008. [`delivery-receipt`](ref:e2e.delivery-receipt) message):
  1009. - Automatic: "received" and "read"
  1010. - Manual: "acknowledged" and "declined"
  1011. For each message, we will define whether automatic delivery receipts should
  1012. be sent and whether it is eligible for sending manual delivery receipts
  1013. (e.g. acknowledge/decline). However, two general exceptions apply:
  1014. 1. Automatic delivery receipts are not sent to group members (i.e. when
  1015. any message struct is wrapped in a `group` message struct).
  1016. 2. Messages whose flags include `0x80` must not trigger any automatic
  1017. delivery receipts.
  1018. ### Blocking
  1019. The sender Threema ID may be blocked explicitly (i.e. blocking a specific
  1020. Threema ID) or implicitly (blocking all unknown Threema IDs). This does not
  1021. require special handling on the server but instead is done entirely by the
  1022. clients.
  1023. Note that the protocol does not distinguish between implicitly and
  1024. explicitly blocked Threema IDs. An implicitly blocked Threema ID (i.e.
  1025. blocking unknown contacts) must be treated the same as an explicitly blocked
  1026. Threema ID (i.e. blocking specific contacts).
  1027. The UI must prevent users from composing or submitting messages towards a
  1028. blocked contact. In practise, this is only relevant for explicitly blocked
  1029. contacts.
  1030. The following steps are defined as the _Identity Blocked Steps_:
  1031. 1. Let `identity` be the Threema ID to be checked.
  1032. 2. If `identity` is a _Special Contact_, return that it is not blocked.
  1033. 3. If `identity` is explicitly blocked, return that it is blocked.
  1034. 4. If the settings indicate that unknown contacts should not be blocked,
  1035. return that it is not blocked.
  1036. 5. If `identity` is a _Predefined Contact_, return that it is not blocked.
  1037. 6. Let `contact` be the associated contact to `identity`.
  1038. 7. If `contact` is not defined, return that it is blocked.
  1039. 8. If `contact` has acquaintance level _direct_, return that it is not
  1040. blocked.
  1041. 9. If `contact` is part of a group that is not marked as _left_, return
  1042. that it is not blocked.
  1043. 10. Return that it is blocked.
  1044. ### Contact Flows
  1045. The following steps are defined as the _Valid Contacts Lookup Steps_:
  1046. 1. Let `identities` be the identities to look up.
  1047. 2. Let `contact-or-inits` be an empty map of Threema IDs to a contact,
  1048. properties to create a contact from, or _contact is the user_ or
  1049. _contact is invalid_ marker.
  1050. 3. Let `unknown-identities` be an empty list.
  1051. 4. For each `identity` of `identities`:
  1052. 1. If `identity` equals the user's Threema ID, add the information
  1053. that the _contact is the user_ to the `contact-or-inits` map and
  1054. abort these sub-steps.
  1055. 2. If `identity` is a _Special Contact_, add that special contact to the
  1056. `contact-or-inits` map and abort these sub-steps.
  1057. 3. Lookup the contact associated to `identity` and let `contact` be the
  1058. result.
  1059. 4. If `contact` is defined, add `contact` to the `contact-or-inits` map
  1060. and abort these sub-steps.
  1061. 5. Lookup the properties to create a contact from associated to
  1062. `identity` from the _contact lookup cache_ and let `init` be the
  1063. result.
  1064. 6. If `init` is defined, add `init` to the `contact-or-inits` map and
  1065. abort these sub-steps.
  1066. 7. Add `identity` to `unknown-identities`.
  1067. 5. Let `directory-response` be the response of asynchronously looking up
  1068. `unknown-identities` on the Directory Server.
  1069. 6. If Work flavour, let `work-directory-response` be the response of
  1070. asynchronously looking up `unknown-identities` on the Work Contacts API
  1071. endpoint.
  1072. 7. Await `directory-response` and `work-directory-response`.
  1073. 8. Process the result of `directory-response`:
  1074. 1. If the server could not be reached, exceptionally abort these steps.
  1075. 2. If the status code is `429`, exceptionally abort these steps and add
  1076. a minimum delay of 10s before retrying a connection.
  1077. 3. If the status code is not `200`, exceptionally abort these steps.
  1078. 4. For each contact entry of the result:
  1079. 1. Remove the contact from `unknown-identities`. If it was not
  1080. present in `unknown-identities`, log a warning and abort these
  1081. sub-steps.
  1082. 2. If the contact is marked as _invalid_ (never existed or has been
  1083. revoked), add the information that the _contact is invalid_ to the
  1084. `contact-or-inits` map and abort these sub-steps.
  1085. 3. If the contact is a _Predefined Contact_:
  1086. 1. If the contact's public key does not equal the _Predefined
  1087. Contact_s public key, log a warning and exceptionally abort these
  1088. steps.
  1089. 2. Update the contact information with the following information:
  1090. - set `verification_level` to `FULLY_VERIFIED`,
  1091. - set `nickname` to the nickname of the _Predefined Contact_,
  1092. - if _Predefined Contact_ defines a first name, set it
  1093. accordingly,
  1094. - if _Predefined Contact_ defines a last name, set it
  1095. accordingly,
  1096. 3. Add the resulting contact information to the `contact-or-inits` map
  1097. from which a new contact can be created.
  1098. 5. For each `identity` of `unknown-identities`:
  1099. 1. Add the information that the _contact is invalid_ to the
  1100. `contact-or-inits` map for `identity`.
  1101. 6. Clear `unknown-identities`.
  1102. 9. If `work-directory-response` is defined, process its result:
  1103. 1. If the server could not be reached, exceptionally abort these steps.
  1104. 2. If the status code is `401`, exceptionally abort these steps,
  1105. notify the user that the Work credentials are invalid and request new
  1106. ones. The connection should not be retried until new Work credentials
  1107. have been entered and checked for validity.
  1108. 3. If the status code is `429`, exceptionally abort these steps and add a
  1109. minimum delay of 10s before retrying a connection.
  1110. 4. If the status code is not `200`, exceptionally abort these steps.
  1111. 5. For each `work-contact` of the result:
  1112. 1. If an entry for the `work-contact`'s identity does not exist in
  1113. `contact-or-inits`, log a warning and abort these sub-steps.
  1114. 2. If `work-contact`'s public key does not equal `contact-or-init`'s
  1115. public key, log a warning and exceptionally abort these steps.
  1116. 3. Update the contact entry for `work-contact`'s identity in
  1117. `contact-or-inits` with the following information:
  1118. - if `verification_level` is not defined or `UNVERIFIED`, set it
  1119. to `SERVER_VERIFIED`,
  1120. - set `work_verification_level` to `WORK_SUBSCRIPTION_VERIFIED`,
  1121. - if `work-contact.first-name` is defined, set the first name
  1122. accordingly,
  1123. - if `work-contact.last-name` is defined, set the last name
  1124. accordingly,
  1125. 10. TODO(SE-173): Run the contact import flow for `contact-or-inits` and
  1126. update the `verification_level` for all whose associated phone number /
  1127. email could be matched. Import `first_name` and `last_name` (if not
  1128. already defined) and set `sync_state` to `IMPORTED`. Clarify precedence
  1129. regarding Work API.
  1130. 11. For each `init` of `contact-or-inits`:
  1131. 1. If `init` does not contain properties to create a contact from (i.e.
  1132. it is a contact or any of the special markers), abort these
  1133. sub-steps.
  1134. 2. If `init.sync_state` is not defined, set it to `INITIAL`.
  1135. 3. If `init.verification_level` is not defined, set it to `UNVERIFIED`.
  1136. 4. If `init.work_verification_level` is not defined, set it to `NONE`.
  1137. 12. Update the _contact lookup cache_ with the contents of
  1138. `contact-or-inits`. Each newly added or updated entry has an expiration
  1139. time of 10m after which the entry is to be removed from the cache.
  1140. 13. Return `contact-or-inits`.
  1141. ### Groups
  1142. Groups are handled in a decentralised manner. Messages are sent to each
  1143. group member individually. On a technical level, a group is identified by
  1144. **both** the Threema ID of the creator and the random group ID the creator
  1145. chose. A group **must never** be identified by the group ID alone.
  1146. Group messages are special containers wrapped around normal messages (it is
  1147. actually just a common header):
  1148. - [`group-member-container`](ref:e2e.group-member-container): For group
  1149. message communication between members, including the creator.
  1150. - [`group-creator-container`](ref:e2e.group-creator-container): For special
  1151. messages that may only be sent from the creator to normal group members
  1152. and vice versa.
  1153. Group messages have special types in order to separate them from other
  1154. messages. These types also define which container must be used.
  1155. The group members are determined by the
  1156. [`group-setup`](ref:e2e.group-setup) message and continuously updated by
  1157. any following [`group-leave`](ref:e2e.group-leave) messages. Any following
  1158. [`group-setup`](ref:e2e.group-setup) overrides the previous member state.
  1159. ### Implicit Contact Creation
  1160. When the user is added to a group, every unknown member of the group must be
  1161. added to the contact list with acquaintance level _group_. Messages from a
  1162. contact with any acquaintance level will not be implicitly blocked by a
  1163. _block unknown_ setting.
  1164. The contact remains at the acquaintance level _group_ until a 1:1
  1165. conversation with that contact is being started by either side in which
  1166. case the acquaintance level should be changed to _direct_.
  1167. A contact with acquaintance level _group_ will remain indefinitely even if
  1168. the contact is being removed from all groups of the user or if all remaining
  1169. common groups are marked as _left_. In that case, the contact is implicitly
  1170. marked as _deleted_ so that it is covered by _block unknown_.
  1171. ### Notes Group
  1172. A group is identified as a _notes_ group if all of the following criteria
  1173. are met:
  1174. 1. The user is the creator of the group.
  1175. 2. The group currently has no members (besides the creator).
  1176. 3. The group is not marked as _left_.
  1177. Messages in a _notes_ group are synchronised across devices but are not
  1178. sent to the chat server (since there are no other members). Therefore,
  1179. it is ideal for "notes to self", hence the name.
  1180. A group seamlessly transforms into a _notes_ group and out of it given the
  1181. above criteria. Right now this can happen in three scenarios:
  1182. - A _notes_ group is created explicitly (i.e. a group with only the user
  1183. is being created).
  1184. - The user is the creator of a group and one or more members are being
  1185. added in which case the _notes_ group transforms into a regular group.
  1186. - The user is the creator of a group whose members have just been removed
  1187. (but the group has not been disbanded) in which case the group
  1188. transforms into a _notes_ group.
  1189. The UI should signal the _notes_ status of a group to the user.
  1190. ### Group Flows
  1191. The following steps are defined as the _Active Group Update Steps_:
  1192. 1. If the user is not the creator of the group or the group is marked as
  1193. _left_, log an error and abort these steps.
  1194. 2. Let `message-ids` be a list of four pre-generated message IDs.
  1195. 3. Let `changes` be the set of expected changes to the group which may
  1196. contain the following properties:
  1197. - `profile-picture` is defined if the group's profile picture is
  1198. expected to be changed and contains either the new profile picture or
  1199. a _remove_ mark to remove it
  1200. - `profile-picture.blob` may contain the associated blob information
  1201. data in case of a changed profile picture.
  1202. - `add-members` is a set of new members to be added to the group
  1203. - `remove-members` is a set of existing members to be removed from the
  1204. group
  1205. 4. Let `group` be a snapshot of the current group state.
  1206. 5. Remove all members from `changes.add-members` that are not in
  1207. `group.members`.
  1208. 6. Remove all members from `changes.remove-members` that are in
  1209. `group.members`.
  1210. 7. Let `messages` be an empty list.
  1211. 8. If `changes.remove-members` is not empty, add a message entry to
  1212. `messages` to remove members to be removed with the following
  1213. properties:
  1214. - `id` set to the first message ID of `message-ids`,
  1215. - `created-at` set to the current timestamp,
  1216. - `receivers` set to `changes.remove-members`,
  1217. - to construct a [`group-setup`](ref:e2e.group-setup) (wrapped by
  1218. [`group-creator-container`](ref:e2e.group-creator-container))
  1219. with an empty members set.
  1220. 9. If `group.members` is not empty:
  1221. 1. Add a message entry to `messages` to update the group for the
  1222. members with the following properties:
  1223. - `id` set to the first message ID of `message-ids`,
  1224. - `created-at` set to the current timestamp,
  1225. - `receivers` set to `group.members`,
  1226. - to construct a [`group-setup`](ref:e2e.group-setup) (wrapped by
  1227. [`group-creator-container`](ref:e2e.group-creator-container))
  1228. from `group.members`.
  1229. 2. Add a message entry to `messages` to announce the group's name to
  1230. the members with the following properties:
  1231. - `id` set to the second message ID of `message-ids`,
  1232. - `created-at` set to the current timestamp,
  1233. - `receivers` set to `group.members`,
  1234. - to construct a [`group-name`](ref:e2e.group-name) (wrapped by
  1235. [`group-creator-container`](ref:e2e.group-creator-container))
  1236. from `group.name`.¹
  1237. 3. If `group.profile-picture` is defined:
  1238. 1. Let `profile-picture-blob` be `changes.profile-picture.blob`.
  1239. 2. If `group.profile-picture` does not equal
  1240. `changes.profile-picture`, upload `group.profile-picture` to the
  1241. blob server with the _persist_ flag and set
  1242. `profile-picture-blob` to the result.
  1243. 4. Add a message entry to `messages` to announce the group's profile
  1244. picture to the members with the following properties:
  1245. - `id` set to the third message ID of `message-ids`,
  1246. - `created-at` set to the current timestamp,
  1247. - `receivers` set to `group.members`,
  1248. - to construct a
  1249. [`set-profile-picture`](ref:e2e.set-profile-picture) (wrapped by
  1250. [`group-creator-container`](ref:e2e.group-creator-container)) from
  1251. `profile-picture-blob` if `profile-picture-blob` is defined or
  1252. [`delete-profile-picture`](ref:e2e.delete-profile-picture)
  1253. (wrapped by
  1254. [`group-creator-container`](ref:e2e.group-creator-container))
  1255. otherwise.¹
  1256. 5. Let `chosen-call` be the result of the most recent invocation of
  1257. the _Group Call Refresh Steps_ for the group.
  1258. 6. If `chosen-call` is defined, add a message entry to `messages` to
  1259. announce the ongoing group call to newly added members with the
  1260. following properties:
  1261. - `id` set to the fourth message ID of `message-ids`,
  1262. - `created-at` set to the `started_at` value associated to
  1263. `chosen-call`,
  1264. - `receivers` set to `changes.add-members`,
  1265. - to construct a repeat of `csp-e2e.GroupCallStart` (wrapped by
  1266. [`group-member-container`](ref:e2e.group-member-container))
  1267. that is associated to `chosen-call`.
  1268. 10. Run the _Bundled Messages Send Steps_ with `messages`.
  1269. ¹: This results in the group name and the group profile picture being
  1270. distributed to all members regardless of whether it was changed or not. This
  1271. is deemed acceptable for the sake of implementation simplicity and
  1272. reusability.
  1273. The following steps are defined as the _Active Group State Resync Steps_:
  1274. 1. If the user is not the creator of the group or the group is marked as
  1275. _left_, log an error and abort these steps.
  1276. 2. Let `message-ids` be a list of four pre-generated message IDs.
  1277. 3. Let `target-members` be a set of members to receive the resync.
  1278. 4. Remove all members from `target-members` that are not in
  1279. `group.members`.
  1280. 5. If `target-members` is empty, abort these steps.
  1281. 6. Let `messages` be an empty list.
  1282. 7. Add a message entry to `messages` to announce the group composition with
  1283. the following properties:
  1284. - `id` set to the first message ID of `message-ids`,
  1285. - `created-at` set to the current timestamp,
  1286. - `receivers` set to `target-members`,
  1287. - to construct a [`group-setup`](ref:e2e.group-setup) (wrapped by
  1288. [`group-creator-container`](ref:e2e.group-creator-container)) from
  1289. `group.members`.
  1290. 8. Add a message entry to `messages` to announce the group's name with the
  1291. following properties:
  1292. - `id` set to the second message ID of `message-ids`,
  1293. - `created-at` set to the current timestamp,
  1294. - `receivers` set to `target-members`,
  1295. - to construct a [`group-name`](ref:e2e.group-name) (wrapped by
  1296. [`group-creator-container`](ref:e2e.group-creator-container)) from
  1297. `group.name`.
  1298. 9. If `group.profile-picture` is defined, upload `group.profile-picture` to
  1299. the blob server with the _persist_ flag and let `profile-picture-blob`
  1300. be the result.
  1301. 10. Add a message entry to `messages` to announce the group's profile
  1302. picture with the following properties:
  1303. - `id` set to the third message ID of `message-ids`,
  1304. - `created-at` set to the current timestamp,
  1305. - `receivers` set to `target-members`,
  1306. - to construct a
  1307. [`set-profile-picture`](ref:e2e.set-profile-picture) (wrapped by
  1308. [`group-creator-container`](ref:e2e.group-creator-container)) from
  1309. `profile-picture-blob` if `profile-picture-blob` is defined or
  1310. [`delete-profile-picture`](ref:e2e.delete-profile-picture) (wrapped by
  1311. [`group-creator-container`](ref:e2e.group-creator-container))
  1312. otherwise.
  1313. 11. Let `chosen-call` be the result of the most recent invocation of
  1314. the _Group Call Refresh Steps_ for the group.
  1315. 12. If `chosen-call` is defined, add a message entry to `messages` to
  1316. announce the ongoing group call with the following properties:
  1317. - `id` set to the fourth message ID of `message-ids`,
  1318. - `created-at` set to the `started_at` value associated to
  1319. `chosen-call`,
  1320. - `receivers` set to `target-members`,
  1321. - to construct a repeat of `csp-e2e.GroupCallStart` (wrapped by
  1322. [`group-member-container`](ref:e2e.group-member-container)) that is
  1323. associated to `chosen-call`.
  1324. 13. Run the _Bundled Messages Send Steps_ with `messages`.
  1325. 14. For each member of `target-members`, mark the group as _recently
  1326. resynced_ for 1h.
  1327. #### Create/Clone Group
  1328. The following steps must be invoked when the user wants to create or clone a
  1329. group:
  1330. 1. Let `init` contain the following properties to create a group:
  1331. - `name` of the new group or an empty string
  1332. - `profile-picture` of the new group or undefined
  1333. - `members` is a set of initial members to be added to the group¹
  1334. 2. Let `parameters` be the MDM parameters. If
  1335. `parameters.th_disable_create_group` is `true`, abort these steps.
  1336. 3. Let `group-id` be a random group ID.
  1337. 4. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  1338. precondition:
  1339. 1. If a group with `group-id` and the user as creator exists, log an
  1340. error and abort these steps.
  1341. 2. If `init.members` contains a member that is not an existing
  1342. contact, log an error and abort these steps.
  1343. 5. If `init.profile-picture` is defined, upload `init.profile-picture` to
  1344. the blob server with the _persist_ flag and set
  1345. `init.profile-picture.blob` to the result.
  1346. 6. (MD) Reflect a `GroupSync.Create` with `group` set to contain:
  1347. - `group_identity` being `group-id` and the user as the creator,
  1348. - `created_at` set to now,
  1349. - `name` set to `init.name`
  1350. - `user_state` set to `MEMBER`,
  1351. - `profile_picture` set from `init.profile-picture.blob`,
  1352. - `member_identities` set from `init.members`,
  1353. - all policies and categories set to their defaults.
  1354. 7. (MD) Commit the transaction and await acknowledgement.
  1355. 8. Persist the newly created group from `init` and `group-id` to storage.
  1356. 9. If `init.members` is empty, abort these steps.
  1357. 10. Let `message-ids` be a list of four random message IDs.
  1358. 11. Schedule a persistent task to run the following steps:
  1359. 1. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  1360. precondition:
  1361. 1. If the group does not exist or the group is marked as _left_ or the
  1362. group has no members, log a warning that a group sync race occurred
  1363. and abort these steps.
  1364. 2. Let `group` be a snapshot of the current group state.
  1365. 3. If any of the following cases is true, log a warning that a group
  1366. sync race occurred:
  1367. - `init.name` is defined and does not equal `group.name`,
  1368. - `init.profile-picture` does not equal `group.profile-picture`,
  1369. - `init.members` does not equal `group.members`.
  1370. 4. Run the _Active Group Update Steps_ with `message-ids` and the
  1371. following expected set of `changes`:
  1372. - `profile-picture` set to `init.profile-picture`,
  1373. - `add-members` set to `init.members`,
  1374. - `remove-members` set to an empty list.
  1375. 5. (MD) Commit the transaction and await acknowledgement.
  1376. ¹: Note that all contacts must be added before they can be added as initial
  1377. members of the group.
  1378. #### Update Group
  1379. The following steps must be invoked when the user is the creator of a group
  1380. and intends to apply a change to the group's name, profile picture or
  1381. add/remove members to/from the group:
  1382. 1. If the user is not the creator of the group or the group is marked as
  1383. _left_, log an error and abort these steps.
  1384. 2. Let `changes` be the set of changes to the group which may contain the
  1385. following properties:
  1386. - `name` is defined if the group's name is to be changed and contains the
  1387. new name or an empty string
  1388. - `profile-picture` is defined if the group's profile picture is to be
  1389. changed and contains either the new profile picture or a _remove_ mark
  1390. to remove it
  1391. - `add-members` is a set of new members to be added to the group¹
  1392. - `remove-members` is a set of existing members to be removed from the
  1393. group¹
  1394. 3. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  1395. precondition:
  1396. 1. If `changes.add-members` or `changes.remove-members` contains a
  1397. member that is not an existing contact, log an error and abort these
  1398. steps.
  1399. 2. If the group does not exist or the group is marked as _left_, log a
  1400. warning and abort these steps.
  1401. 4. Let `updated-members` be a copy of the current member set of the group.
  1402. Add all `changes.add-members` to this set that are to be added to the
  1403. group. Remove all `changes.remove-members` from this set that are to be
  1404. removed from the group.
  1405. 5. If `changes.profile-picture` is defined and contains a profile picture,
  1406. upload `changes.profile-picture` to the blob server with the _persist_
  1407. flag and let `changes.profile-picture.blob` be the result.
  1408. 6. (MD) Reflect a `GroupSync.Update` with `member_state_changes`
  1409. constructed from `changes.add-members` and `changes.remove-members` and
  1410. `group` set to contain:
  1411. - `name` set to `changes.name`,
  1412. - `profile_picture` set according to `changes.profile-picture` (and
  1413. `changes.profile-picture.blob`),
  1414. - `member_identities` set from `updated-members`.
  1415. 7. (MD) Commit the transaction and await acknowledgement.
  1416. 8. If the user is currently participating in a group call of this group,
  1417. remove all `change.remove-members` participants from the group call
  1418. (handle them as if they left the call).
  1419. 9. Persist the `updated-members` and other `changes` to the group.
  1420. 10. If `changes.add-members` or `changes.remove-members` is not empty, run
  1421. the _Rejected Messages Refresh Steps_ for the group.
  1422. 11. Let `message-ids` be a list of four random message IDs.
  1423. 12. Schedule a persistent task to run the following steps:
  1424. 1. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  1425. precondition:
  1426. 1. If the group does not exist or the group is marked as _left_, log
  1427. a warning that a group sync race occurred and abort these steps.
  1428. 2. Let `group` be a snapshot of the current group state.
  1429. 3. If any of the following cases is true, log a warning that a group
  1430. sync race occurred:
  1431. - `changes.name` is defined and does not equal `group.name`,
  1432. - `changes.profile-picture` contains a profile picture and does not
  1433. equal `group.profile-picture`,
  1434. - `changes.profile-picture` contains the _remove_ mark and
  1435. `group.profile-picture` is defined,
  1436. - `updated-members` does not equal `group.members`.
  1437. 4. Run the _Active Group Update Steps_ with `message-ids` and `changes`.
  1438. 5. (MD) Commit the transaction and await acknowledgement.
  1439. ¹: Note that all contacts must be added before they can be added as members
  1440. to the group. The same applies to members that are being removed, obviously.
  1441. #### Disband/Remove Group
  1442. The following steps must be invoked when the user is the creator of a group
  1443. and intends to _disband_ or _disband and remove_ the group:
  1444. 1. Let `intent` be the user's intent which can be either to _disband_ or to
  1445. _disband and remove_ the group.
  1446. 2. If the user is not the creator of the group or the group is marked as
  1447. _left_, log an error and abort these steps.
  1448. 3. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  1449. precondition:
  1450. 1. If the group does not exist or the group is marked as _left_, log a
  1451. warning and abort these steps.
  1452. 4. (MD) If `intent` is to _disband_, reflect a `GroupSync.Update` with
  1453. `group` set to contain `user_state` set to `LEFT`.
  1454. 5. (MD) If `intent` is to _disband and remove_, reflect a
  1455. `GroupSync.Delete` for this group.
  1456. 6. (MD) Commit the transaction and await acknowledgement.
  1457. 7. If the user is participating in a group call of this group, trigger
  1458. leaving the call.
  1459. 8. If the `intent` is to _disband_:
  1460. 1. Mark the group as _left_.
  1461. 2. Persist the previous member setup so that the group can be cloned.
  1462. 3. Run the _Rejected Messages Refresh Steps_ for the group.
  1463. 9. Let `group` be a snapshot of the current group state.
  1464. 10. If the `intent` is to _disband and remove_, remove the group and all
  1465. associated messages from storage.
  1466. 11. Let `message-id` be a random message ID.
  1467. 12. Schedule a persistent task to run the following steps:
  1468. 1. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  1469. precondition:
  1470. 1. If the group exists and is not marked as _left_, log an error that
  1471. a major group state inconsistency has been detected¹ and abort
  1472. these steps.
  1473. 2. Run the _Bundled Messages Send Steps_ with the following properties:
  1474. - `id` set to `message-id`,
  1475. - `created-at` set to the current timestamp,
  1476. - `receivers` set to `group.members`,
  1477. - to construct a [`group-setup`](ref:e2e.group-setup) (wrapped by
  1478. [`group-creator-container`](ref:e2e.group-creator-container)) with
  1479. an empty members set.
  1480. 3. (MD) Commit the transaction and await acknowledgement.
  1481. ¹: Disbanding a group as the creator makes the group strictly non-reusable.
  1482. #### Leave/Remove Group
  1483. The following steps must be invoked when the user is not the creator of a
  1484. group and intends to _leave_ or _leave and remove_ the group:
  1485. 1. Let `intent` be the user's intent which can be either to _leave_ or to
  1486. _leave and remove_ the group.
  1487. 2. If the user is the creator of the group or the group is marked as
  1488. _left_, log an error and abort these steps.
  1489. 3. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  1490. precondition:
  1491. 1. If the group does not exist or the group is marked as _left_, log a
  1492. warning and abort these steps.
  1493. 4. (MD) If `intent` is to _leave_, reflect a `GroupSync.Update` with
  1494. `group` set to contain `user_state` set to `LEFT`.
  1495. 5. (MD) If `intent` is to _leave and remove_, reflect a `GroupSync.Delete`
  1496. for this group.
  1497. 6. (MD) Commit the transaction and await acknowledgement.
  1498. 7. If the user is participating in a group call of this group, trigger
  1499. leaving the call.
  1500. 8. If the `intent` is to _leave_:
  1501. 1. Mark the group as _left_.
  1502. 2. Persist the previous member setup so that the group can be cloned.
  1503. 3. Run the _Rejected Messages Refresh Steps_ for the group.
  1504. 9. Let `group` be a snapshot of the current group state.
  1505. 10. If the `intent` is to _leave and remove_, remove the group and all
  1506. associated messages from storage.
  1507. 11. Let `message-id` be a random message ID.
  1508. 12. Schedule a persistent task to run the following steps:
  1509. 1. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  1510. precondition:
  1511. 1. If the group exists and is not marked as _left_, log a warning
  1512. that a group sync race occurred and abort these steps.
  1513. 2. Run the _Bundled Messages Send Steps_ with the following properties:
  1514. - `id` set to `message-id`,
  1515. - `created-at` set to the current timestamp,
  1516. - `receivers` set to `group.members`,
  1517. - to construct a [`group-leave`](ref:e2e.group-leave) (wrapped by
  1518. [`group-member-container`](ref:e2e.group-member-container))
  1519. 3. (MD) Commit the transaction and await acknowledgement.
  1520. #### Remove Group
  1521. The following steps must be invoked when the user intends to remove a group
  1522. that is marked as _left_.
  1523. 1. If the group is not marked as _left_, log an error and abort these steps.
  1524. 2. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  1525. precondition:
  1526. 1. If the group does not exist or the group is not marked as _left_, log
  1527. a warning and abort these steps.
  1528. 3. (MD) Reflect a `GroupSync.Delete` for this group.
  1529. 4. (MD) Commit the transaction and await acknowledgement.
  1530. 5. Remove the group and all associated messages from storage.
  1531. #### Group Resync
  1532. The following steps must be invoked when the user is the creator of a group
  1533. and intends to resync the group manually:
  1534. 1. If the user is not the creator of the group or the group is marked as
  1535. _left_, log an error and abort these steps.
  1536. 2. Let `message-ids` be a list of four random message IDs.
  1537. 3. Schedule a volatile task to run the following steps:
  1538. 1. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  1539. precondition:
  1540. 1. If the group does not exist or the group is marked as _left_, log a
  1541. warning and abort these steps.
  1542. 2. Run the _Active Group State Resync Steps_ with `message-ids` and
  1543. `target-members` being all current group members.¹
  1544. 3. (MD) Commit the transaction and await acknowledgement.
  1545. ¹: This mechanic intentionally bypasses the 1h _recently resynced_ mark due
  1546. to an explicit manual request by the user to resync the group.
  1547. #### Update Conversation
  1548. The following steps must be invoked when the user intends to change any
  1549. other synchronised property of the group:
  1550. 1. Let `change` be one of the following changes to the group as defined by
  1551. `sync.Group`:
  1552. - `notification_trigger_policy_override`
  1553. - `notification_sound_policy_override`
  1554. - `conversation_category`
  1555. - `conversation_visibility`
  1556. 2. Persist the `change` to the group.
  1557. 3. (MD) Schedule a persistent task to run the following steps:
  1558. 1. Begin a transaction with scope `GROUP_SYNC` and the following precondition:
  1559. 1. If the group does not exist, log a warning and abort these steps.
  1560. 2. Reflect a `GroupSync.Update` with `group` set to contain the `change`.
  1561. 3. Commit the transaction and await acknowledgement.
  1562. 4. Persist the `change` to the group (again).
  1563. ### Device Flows
  1564. #### Deactivate Multi-Device Flow
  1565. The following steps must be invoked when the user wants to deactivate
  1566. multi-device and continue using the current device.
  1567. 1. Run the _Drop Devices Steps_ with the intent to _deactivate_
  1568. multi-device and keep the user informed regarding the process status and
  1569. any encountered issues.
  1570. #### Drop Own Device Flow
  1571. The following steps must be invoked when the user wants to stop using the
  1572. current device.
  1573. 1. If the device does not have multi-device enabled, log an error and
  1574. abort these steps.
  1575. 2. Begin a transaction (scope: `DROP_DEVICE`, precondition: none).
  1576. 3. Send a `DropDevice` with this device's Device ID.
  1577. 4. Await the corresponding `DropDeviceAck` or the connection closing with
  1578. close code `4113`.
  1579. 5. TODO(SE-494): Enter _read-only_ mode persistently.
  1580. #### Drop Other Devices Flow
  1581. The following steps must be invoked when the user wants to drop one or more
  1582. other devices from the device group.
  1583. 1. Let `device-ids-to-drop` be a set of Device IDs that should be
  1584. dropped from the device group.
  1585. 2. If this device's Device ID is contained in `device-ids-to-drop`,
  1586. log an error and abort these steps.
  1587. 3. Run the _Drop Devices Steps_ with the intent to _drop specific_
  1588. `device-ids-to-drop` and keep the user informed regarding the process
  1589. status and any encountered issues.
  1590. #### Drop Devices Steps
  1591. The following steps are defined as the _Drop Devices Steps_:
  1592. 1. If the device does not have multi-device enabled¹, run the
  1593. _Application Setup Steps_ step 2.2. through 2.6. and abort these steps.
  1594. TODO(SE-199): This shall be removed once multi-device supports FS.
  1595. 2. Let `intent` be the intent which can be either to _deactivate_
  1596. multi-device or _drop specific_ devices, letting `device-ids-to-drop` be
  1597. that set of specific Device IDs.
  1598. 3. If `device-ids-to-drop` is defined:
  1599. 1. If `device-ids-to-drop` is empty, log an error and abort these steps.
  1600. 2. If `device-ids-to-drop` contains this device's Device ID, log
  1601. an error and abort these steps.
  1602. 4. Begin a transaction (scope: `DROP_DEVICE`, precondition: none).
  1603. 5. Send a `GetDevicesInfo` message.
  1604. 6. Await the `DevicesInfo` message and let `other-device-ids` be a set of
  1605. the contained Device IDs excluding this device's Device ID.
  1606. 7. If `device-ids-to-drop` is defined, remove each Device ID from
  1607. `device-ids-to-drop` that is not present in `other-device-ids`.
  1608. 8. If `device-ids-to-drop` is not defined, define it to be a copy of
  1609. `other-device-ids`.
  1610. 9. Send a `DropDevice` message for each Device ID of `device-ids-to-drop`.
  1611. 10. Await all corresponding `DropDeviceAck`s of each Device ID in
  1612. `device-ids-to-drop`.
  1613. 11. If `device-ids-to-drop` contains the same Device IDs as
  1614. `other-device-ids` (i.e. all other devices but this device have been
  1615. dropped):
  1616. 1. Send a `DropDevice` with this device's Device ID.
  1617. 2. Await the corresponding `DropDeviceAck` or the connection closing
  1618. with close code `4113`.
  1619. 3. Disable multi-device and purge any existing device group data.
  1620. 4. Run the _Application Setup Steps_ step 2.2. through 2.6.
  1621. TODO(SE-199): This shall be removed once multi-device supports FS.
  1622. ¹: This can happen if the steps are run within a persistent task that is
  1623. aborted before reactivating FS successfully. TODO(SE-199): This shall be
  1624. removed once multi-device supports FS.
  1625. ### Sending
  1626. The following steps are defined as the _Bundled Messages Send Steps_ and
  1627. must always be invoked as part of a task in order to send a message:
  1628. 1. Let `messages` be a list of messages with each having the following
  1629. properties:
  1630. - `id` being the associated message ID¹,
  1631. - `created-at` timestamp,
  1632. - `receivers` being the set of receivers for the message²,
  1633. - the associated conversation,
  1634. - all necessary information to construct a _canonical_ message from it,
  1635. - all necessary information to construct a _specific_ message from it,
  1636. given the specific receiver.
  1637. Note: If only one set of informations to construct a message is
  1638. provided, this is considered both the _canonical_ and the _specific_
  1639. message construction variant.
  1640. 2. For each `message` of `messages`:
  1641. 1. For each `receiver` of `message.receivers`:
  1642. 1. If `receiver` is the user, log a warning, remove `receiver` from
  1643. `receivers` and abort these sub-steps.
  1644. 2. If `receiver` is marked as _invalid_, remove `receiver` from
  1645. `receivers and abort these sub-steps.
  1646. 3. If the properties associated to `message` to be constructed for
  1647. `receiver` given its feature mask indicates that the message is
  1648. not exempted from blocking, run the _Identity Blocked Steps_ for
  1649. `receiver`'s identity. If the result indicates that `receiver` is
  1650. blocked, remove `receiver` from `receivers` and abort these
  1651. sub-steps.
  1652. 4. Construct the _specific_ `message` for `receiver` and attach the
  1653. constructed message to `receiver`.
  1654. 5. Run the _Profile Picture Distribution Steps_ with the constructed
  1655. _specific_ message for `receiver`'s type and `receiver` and extend
  1656. `messages` with the result.
  1657. 3. For each `message` of `messages` attach a random nonce for `message` to
  1658. each receiver of `message.receivers`.
  1659. 4. (MD) Let `pending-reflect-acks` be an empty list.
  1660. 5. (MD) For each `message` of `messages`:
  1661. 1. If the properties associated to the _canonical_ `message` do not
  1662. require reflecting outgoing messages, abort these sub-steps.
  1663. 2. Construct a `d2d.OutgoingMessage` from the _canonical_ `message` for
  1664. the associated conversation and reflect it.
  1665. 3. Add the pending acknowledgement to `pending-reflect-acks`.
  1666. 6. (MD) Await all `pending-reflect-acks`.
  1667. 7. Let `pending-csp-acks` and `fs-commit-fns` be empty lists.
  1668. 8. For each `message` of `messages`:
  1669. 1. For each `receiver` of `message.receivers`:
  1670. 1. If the constructed _specific_ message for `receiver` is of type
  1671. `0xa0`, let `outer-messages` be a list including only the
  1672. constructed message for `receiver` and `fs-commit-fns` be an empty
  1673. list.
  1674. 2. If the constructed _specific_ message for `receiver` is not of
  1675. type `0xa0`, run the _FS Encapsulation Steps_ with the constructed
  1676. _specific_ message for `receiver` and let `outer-messages` and
  1677. `fs-commit-fns` be the result.³
  1678. 3. For each `outer-message` of `outer-messages`:
  1679. 1. Create a `payload.message-with-metadata-box` for `outer-message`
  1680. with `receiver` and let `payload` be the result.
  1681. 2. If `payload.flags` does not contain the _no server
  1682. acknowledgement_ (`0x04`) flag, add `payload.message-id` to
  1683. `pending-csp-acks`.
  1684. 3. If the properties associated to `outer-message` requires
  1685. protection against replay, mark the nonce of `outer-message` as
  1686. used.
  1687. 4. Send `payload`.
  1688. 9. Await all `pending-csp-acks`.
  1689. 10. Run each function of `fs-commit-fns`.
  1690. 11. (MD) Let `pending-reflect-acks` be an empty list.
  1691. 12. (MD) For each `message` of `messages`:
  1692. 1. If the properties associated to the _canonical_ `message` is eligible
  1693. for reflecting `OutgoingMessageUpdate.Sent`:
  1694. 1. Create an `OutgoingMessageUpdate.Sent` for `message.id` and the
  1695. associated conversation and reflect it.
  1696. 2. Add the pending acknowledgement to `pending-reflect-acks`.
  1697. 13. (MD) Await all `pending-reflect-acks`.
  1698. 14. For each `message` of `messages`:
  1699. 1. (MD) If the properties associated to the _canonical_ `message` was
  1700. eligible for reflecting `OutgoingMessageUpdate.Sent`, mark it as
  1701. _sent_ with the timestamp from the corresponding `reflect-ack`
  1702. message.
  1703. 2. (non-MD) Mark `message` as _sent_ with the current timestamp.
  1704. ¹: Note that, in groups, this implicitly assigns the same message ID towards
  1705. each group member which in fact is a requirement of the protocol.
  1706. ²: Reflecting with `receivers` empty is a legitimate case that occurs when
  1707. sending a message in a notes group.
  1708. ³: Always invoking the _FS Encapsulation Steps_ ensures that an FS session
  1709. is being initiated as soon as possible, so that messages can be protected by
  1710. FS. Moreover, it ensures that the announced FS session version is up to date
  1711. (a newer version potentially increasing security or making more messages
  1712. eligible for FS protection).
  1713. The following steps are defined as the _Messages Submit Steps_ which must be
  1714. invoked to submit a user-created message in a conversation:
  1715. 1. Let `messages` be a list of messages of the user to be added to
  1716. the conversation with each having the following properties:
  1717. - `id` set to a random message ID,
  1718. - `created-at` set to the current timestamp,
  1719. - `blobs` be an optional set of blobs that must be uploaded prior to
  1720. being able to construct the message,
  1721. - all necessary information to construct a _canonical_ message from it,
  1722. - all necessary information to construct a _specific_ message from it,
  1723. given the specific receiver.
  1724. Note: If only one set of informations to construct a message is
  1725. provided, this is considered both the _canonical_ and the _specific_
  1726. message construction variant.
  1727. 2. If the associated conversation is a 1:1 conversation, run the _1:1
  1728. Messages Submit Steps_ with `messages`.
  1729. 3. If the associated conversation is a group conversation, run the _Group
  1730. Messages Submit Steps_ with `messages`.
  1731. 4. If the associated conversation is a distribution list conversation, run
  1732. the _Distribution List Messages Submit Steps_ with `messages`.
  1733. 5. (Unreachable)
  1734. The following steps are defined as the _1:1 Messages Submit Steps_ which
  1735. must be invoked to submit a user-created message in a 1:1 conversation:
  1736. 1. Let `messages` be a list of messages of the user to be added to
  1737. the conversation with each having the following properties:
  1738. - `id` defaulting to a random message ID,
  1739. - `created-at` defaulting to the current timestamp,
  1740. - `blobs` be an optional set of blobs that must be uploaded prior to
  1741. being able to construct the message,
  1742. - all necessary information to construct a _canonical_ message from it,
  1743. - all necessary information to construct a _specific_ message from it,
  1744. given the specific receiver.
  1745. Note: If only one set of informations to construct a message is
  1746. provided, this is considered both the _canonical_ and the _specific_
  1747. message construction variant.
  1748. 2. Let `receiver` be the conversation's associated contact.
  1749. 3. If `receiver` has acquaintance level _deleted_, discard `messages`,
  1750. log a warning and abort these steps.¹
  1751. 4. Run the _Identity Blocked Steps_ for `receiver`'s identity'. If the
  1752. result indicates that `receiver` is blocked, discard `messages`, log
  1753. a warning and abort these steps.¹
  1754. 5. For each `message` of `messages`, assign a random message ID to
  1755. `message.id`.
  1756. 6. Schedule a persistent task to run the following steps:²
  1757. 1. If the contact for `receiver` no longer exists, log an error,
  1758. discard `messages` and abort these steps.
  1759. 2. For each `message` of `messages`:
  1760. 1. If `message.blob` is not defined, abort these sub-steps.
  1761. 2. Upload all `message.blobs` to the blob server and update
  1762. `message` with the result (so that the message can be
  1763. constructed).
  1764. 3. (MD) If `receiver`'s acquaintance level is not _direct_ or if at
  1765. least one of the `messages` associated properties requires to
  1766. unarchive the conversation and the associated conversation visibility
  1767. is set to _archived_:
  1768. 1. Begin a transaction with scope `CONTACT_SYNC` and the following
  1769. precondition:
  1770. 1. If the contact for `receiver` no longer exists, log an error,
  1771. discard `messages` and abort these steps.
  1772. 2. Let `change` be the following changes as defined by
  1773. `sync.Contact`:
  1774. - `acquaintance_level` set to `DIRECT`,
  1775. - `conversation_visibility` set to `NORMAL` if the associated
  1776. conversation visibility is currently _archived_,
  1777. 3. Reflect a `ContactSync.Update` with `contact` set from `change`.
  1778. 4. Commit the transaction and await acknowledgement.
  1779. 5. Persist the `change` to the `receiver`.³
  1780. 4. Run the _Bundled Messages Send Steps_ for `messages` with the
  1781. following additional properties added to each message:
  1782. - `receivers` set to `receiver`.
  1783. 7. If the the `receiver`'s acquaintance level is not _direct_, update it to
  1784. _direct_.
  1785. 8. If at least one of the `messages` associated properties requires to
  1786. unarchive the conversation and the associated conversation visibility is
  1787. set to _archived_, set it to _normal_.
  1788. 9. For each `message` of `messages`, add `message` to the associated
  1789. conversation or update a stateful message referred to by `message`
  1790. respectively.
  1791. 10. If at least one of the `messages` associated properties requires to
  1792. bump the conversation's _last update_ timestamp, update it to the
  1793. current timestamp.
  1794. ¹: While the UI should not allow to submit a message in these states,
  1795. another device may alter the state just prior to submission, allowing to
  1796. hit these steps in rare circumstances.
  1797. ²: Rationale to not check for acquaintance level _deleted_ or whether the
  1798. receiver is blocked again is the legitimate use case of the user sending a
  1799. final message prior to blocking or removing a contact.
  1800. ³: This is intentionally done only for MD since the user may e.g.
  1801. immediately archive a conversation after submitting a message. This results
  1802. in both the message and the contact sync being queued as tasks whereas in
  1803. the non-MD case only the message task would be queued. In the MD case, the
  1804. conversation briefly flicks back to _unarchived_ once the message has been
  1805. sent but it immediately flicks back to _archived_ once the contact sync task
  1806. has been executed. But because no contact sync task is created in the non-MD
  1807. case, the message task would leave the conversation _unarchived_ which is
  1808. not intended by the user.
  1809. The following steps are defined as the _Group Messages Submit Steps_ which
  1810. must be invoked to submit a user-created message in a group conversation:
  1811. 1. Let `messages` be a list of messages of the user to be added to
  1812. the conversation with each having the following properties:
  1813. - `id` set to a random message ID,
  1814. - `created-at` set to the current timestamp,
  1815. - `blobs` be an optional set of blobs that must be uploaded prior to
  1816. being able to construct the message,
  1817. - all necessary information to construct a _canonical_ message from it,
  1818. - all necessary information to construct a _specific_ message from it,
  1819. given the specific receiver.
  1820. Note: If only one set of informations to construct a message is provided,
  1821. this is considered both the _canonical_ and the _specific_ message
  1822. construction variant.
  1823. 2. If the group is marked as _left_, discard `messages`, log a warning and
  1824. abort these steps.¹
  1825. 3. For each `message` of `messages`, assign a random message ID to
  1826. `message.id`.
  1827. 4. Schedule a persistent task to run the following steps:²
  1828. 1. If the group does not exist or is marked as _left_, log a warning,
  1829. discard `messages` and abort these steps.
  1830. 2. For each `message` of `messages`:
  1831. 1. If `message.blob` is not defined, abort these sub-steps.
  1832. 2. Upload all `message.blobs` to the blob server with the _persist_
  1833. flag and update `message` with the result (so that the message
  1834. can be constructed).
  1835. 3. (MD) If at least one of the `messages` associated properties requires
  1836. to unarchive the conversation and the associated conversation
  1837. visibility is set to _archived_:
  1838. 1. Begin a transaction with scope `GROUP_SYNC` and the following
  1839. precondition:
  1840. 1. If the group does not exist or is marked as left, log a warning
  1841. that a group sync race occurred, discard `messages` and abort
  1842. these steps.
  1843. 2. Let `change` be the following changes as defined by `sync.Group`:
  1844. - `conversation_visibility` set to `NORMAL` if the associated
  1845. conversation visibility is currently _archived_,
  1846. 3. Reflect a `GroupSync.Update` with `group` set from `change`.
  1847. 4. Commit the transaction and await acknowledgement.
  1848. 5. Persist the `change` to the group.³
  1849. 4. Run the _Bundled Messages Send Steps_ for `messages` with the
  1850. following additional properties added to each message:
  1851. - `receivers` set to the group's members.
  1852. 5. If at least one of the `messages` associated properties requires to
  1853. unarchive the conversation and the associated conversation visibility is
  1854. set to _archived_, set it to _normal_.
  1855. 6. For each `message` of `messages`, add `message` to the associated
  1856. conversation or update a stateful message referred to by `message`
  1857. respectively.
  1858. 7. If at least one of the `messages` associated properties requires to
  1859. bump the conversation's _last update_ timestamp, update it to the current
  1860. timestamp.
  1861. ¹: While the UI should not allow to submit a message in these states,
  1862. another device may alter the state just prior to submission, allowing to
  1863. hit these steps in rare circumstances.
  1864. ²: Rationale to not check for acquaintance level _deleted_ or whether the
  1865. receiver is blocked again is the legitimate use case of the user sending a
  1866. final message prior to removing a group.
  1867. ³: This is intentionally done only for MD since the user may e.g.
  1868. immediately archive a conversation after submitting a message. This results
  1869. in both the message and the group sync being queued as tasks whereas in the
  1870. non-MD case only the message task would be queued. In the MD case, the
  1871. conversation briefly flicks back to _unarchived_ once the message has been
  1872. sent but it immediately flicks back to _archived_ once the group sync task
  1873. has been executed. But because no group sync task is created in the non-MD
  1874. case, the message task would leave the conversation _unarchived_ which is
  1875. not intended by the user.
  1876. The following steps are defined as the _Distribution List Messages Submit
  1877. Steps_ which must be invoked to submit a user-composed message in a
  1878. distribution list conversation:
  1879. 1. Let `messages` be a list of messages of the user to be added to
  1880. the conversation with each having the following properties:
  1881. - `id` set to a random message ID,
  1882. - `created-at` set to the current timestamp,
  1883. - `blobs` be an optional set of blobs that must be uploaded prior to
  1884. being able to construct the message,
  1885. - all necessary information to construct a _canonical_ message from it,
  1886. - all necessary information to construct a _specific_ message from it,
  1887. given the specific receiver.
  1888. Note: If only one set of informations to construct a message is
  1889. provided, this is considered both the _canonical_ and the _specific_
  1890. message construction variant.
  1891. 2. For each `message` of `messages`, assign a random message ID to
  1892. `message.id`.
  1893. 3. Schedule a persistent task to run the following steps:
  1894. 1. If the distribution list does not exist, log a warning, discard
  1895. `messages` and abort these steps.
  1896. 2. For each `message` of `messages`:
  1897. 1. If `message.blob` is not defined, abort these sub-steps.
  1898. 2. Upload all `message.blobs` to the blob server with the _persist_
  1899. flag and update `message` with the result (so that the message
  1900. can be constructed).
  1901. 3. (non-MD) Let `members` be all current members of the distribution
  1902. list. Remove any members with acquaintance level _deleted_ from
  1903. `members`.¹
  1904. 4. (MD) If at least one of the `messages` associated properties requires
  1905. to unarchive the conversation and the associated conversation
  1906. visibility is set to _archived_:
  1907. 1. Begin a transaction with scope `DISTRIBUTION_LIST_SYNC` and the
  1908. following precondition:
  1909. 1. If the distribution list does not exist, log a warning that a
  1910. distribution list sync race occurred, discard `messages` and
  1911. abort these steps.
  1912. 2. Let `members` be all current members of the distribution list.
  1913. Remove any members with acquaintance level _deleted_ from `members`.¹
  1914. 3. Let `change` be the following changes as defined by
  1915. `sync.DistributionList`:
  1916. - `member_identities` from `members`,
  1917. - `conversation_visibility` set to `NORMAL` if the associated
  1918. conversation visibility is currently _archived_,
  1919. 4. Reflect a `DistributionList.Update` with `distribution_list` set from `change`.
  1920. 5. Commit the transaction and await acknowledgement.
  1921. 6. Persist the `change` to the distribution list.²
  1922. 5. Run the _Bundled Messages Send Steps_ for `messages` with the
  1923. following additional properties added to each message:
  1924. - `receivers` from `members`.
  1925. 4. If at least one of the `messages` associated properties requires to
  1926. unarchive the conversation and the associated conversation visibility is
  1927. set to _archived_, set it to _normal_.
  1928. 5. For each `message` of `messages`, add `message` to the associated
  1929. conversation or update a stateful message referred to by `message`
  1930. respectively.
  1931. 6. If at least one of the `messages` associated properties requires to
  1932. bump the conversation's _last update_ timestamp, let `last-update-at` be
  1933. the current timestamp.
  1934. 7. If `last-update-at` is defined, update the associated _last update_
  1935. timestamp of the conversation to `last-update-at`.
  1936. 8. For each `member` of the distribution list:
  1937. 1. Add each message of `messages` to the 1:1 conversation associated to
  1938. `member`.
  1939. 2. If `last-update-at` is defined, update the associated _last update_
  1940. timestamp of the 1:1 conversation of `member` to `last-update-at`.
  1941. ¹: There should be no receivers in a distribution list that have
  1942. acquaintance level _deleted_, so the filtering is only done for safety.
  1943. ²: This is intentionally done only for MD since the user may e.g.
  1944. immediately archive a conversation after submitting a message. This results
  1945. in both the message and the distribution list sync being queued as tasks
  1946. whereas in the non-MD case only the message task would be queued. In the MD
  1947. case, the conversation briefly flicks back to _unarchived_ once the message
  1948. has been sent but it immediately flicks back to _archived_ once the
  1949. distribution list sync task has been executed. But because no distribution
  1950. list sync task is created in the non-MD case, the message task would leave
  1951. the conversation _unarchived_ which is not intended by the user.
  1952. ### Receiving
  1953. The following steps are defined as _Common Group Receive Steps_ and will
  1954. be applied in most cases for group messages:
  1955. 1. Look up the group.
  1956. 2. If the group could not be found:
  1957. 1. If the user is the creator of the group, discard the message and abort
  1958. these steps.
  1959. 2. Run the _Identity Blocked Steps_ for the creator of the group. If
  1960. the result indicates that the creator is blocked, discard the message
  1961. and abort these steps.
  1962. 3. Run the _Group Sync Request Steps_ for the group, discard the
  1963. message and abort these steps.
  1964. 3. If the group is marked as _left_:
  1965. 1. If the user is the creator of the group, run the _Bundled Messages
  1966. Send Steps_ with the following properties:
  1967. - `id` set to a random message ID,
  1968. - `created-at` set to the current timestamp,
  1969. - `receivers` set to the sender,
  1970. - to construct a
  1971. [`group-setup`](ref:e2e.group-setup) (wrapped by
  1972. [`group-creator-container`](ref:e2e.group-creator-container)) with
  1973. an empty members set
  1974. 2. If the user is not the creator of the group, run the _Bundled
  1975. Messages Send Steps_ with the following properties:
  1976. - `id` set to a random message ID,
  1977. - `created-at` set to the current timestamp,
  1978. - `receivers` set to the sender,
  1979. - to construct a
  1980. [`group-leave`](ref:e2e.group-leave) (wrapped by
  1981. [`group-member-container`](ref:e2e.group-member-container))
  1982. 3. Discard the message and abort these steps.
  1983. 4. If the sender is not a member of the group:
  1984. 1. If the user is the creator of the group, run the _Bundled Messages
  1985. Send Steps_ with the following properties:
  1986. - `id` set to a random message ID,
  1987. - `created-at` set to the current timestamp,
  1988. - `receivers` set to the sender,
  1989. - to construct a
  1990. [`group-setup`](ref:e2e.group-setup) (wrapped by
  1991. [`group-creator-container`](ref:e2e.group-creator-container)) with
  1992. an empty members set
  1993. 2. If the user is not the creator of the group, run the _Group Sync
  1994. Request Steps_, then discard the message and abort these steps.
  1995. 3. Discard the message and abort these steps.
  1996. This rule and any exceptions will be referenced/defined explicitly for each
  1997. message.
  1998. Note that steps are not allowed to discard messages from blocked contacts
  1999. prior to running these steps if the message alters group state (group
  2000. control messages), or is stateful (i.e. introduces a poll, poll vote, or a
  2001. group call).
  2002. ### Periodic Group Sync
  2003. When the creator of a group...
  2004. - is about to send a group conversation message, or
  2005. - did just receive a group conversation message,
  2006. it must trigger a _group sync_ for this group if the last time the
  2007. _group sync_ was triggered is more than seven days ago.
  2008. When a _group sync_ is triggered, the creator assumes it has received a
  2009. [`group-sync-request`](ref:e2e.group-sync-request) from every group member
  2010. and must now respond accordingly to each member of the group.
  2011. A newly created group counts as an initial _group sync_ trigger. In other
  2012. words, the first group sync of a newly created group triggers seven days
  2013. in the future when one of the above described conditions is met.
  2014. This provides a form of self-healing in case a device lost its group state
  2015. (e.g. due to a backup restore) and was unable to correct this mischief.
  2016. [//]: # "TODO(SE-40): Group states"
  2017. ### Blobs
  2018. Since messages have a strict maximum size limitation, large binary blobs
  2019. are uploaded to the blob server. Blobs currently have a maximum size of
  2020. 100 MiB.
  2021. When Multi-Device is activated, all Blobs must be downloaded via the
  2022. respective Blob Mirror unless explicitly stated otherwise.
  2023. The following steps are defined as the _Blob Credentials Refresh Steps_:
  2024. 1. Let `credentials` be the most recently used cached blob credentials.
  2025. 2. If `credentials` is defined and is not yet expired, return `credentials`.
  2026. 3. Request Blob Server Credentials via the Directory Server API and set
  2027. `credentials` to the result. If no credentials could be obtained within 10s
  2028. or the request was unsuccessful, exceptionally abort these steps.
  2029. 4. Cache `credentials` with the provided expiration date.
  2030. 5. Return `credentials`.
  2031. #### Upload
  2032. The following steps are defined as the _Blob Upload Steps_:
  2033. 1. Let `blob` be the following properties:
  2034. - `data` being the encrypted binary data to be uploaded,
  2035. - `scope` being either _public_ (for public facing blobs) or _local_ (for
  2036. device group facing blobs).
  2037. - `persist` being a mark (primarily for usage within groups).
  2038. 2. Run the _Blob Credentials Refresh Steps_ and let `credentials` be the
  2039. result.
  2040. 3. (non-MD) Upload to the blob server from `blob` and `credentials`.
  2041. 4. (MD) Upload to the blob mirror server from `blob`, `credentials` and the
  2042. device group information.
  2043. 5. If the upload stream stalls for more than 10s, exceptionally abort these
  2044. steps.
  2045. 6. Return the resulting blob ID.
  2046. #### Download
  2047. The following steps are defined as the _Blob Download Steps_:
  2048. 1. Let `blob` be the following properties:
  2049. - `id` being the blob ID,
  2050. - `scope` being either _public_ (for public facing blobs) or _local_ (for
  2051. device group facing blobs).
  2052. 2. Run the _Blob Credentials Refresh Steps_ and let `credentials` be the
  2053. result.
  2054. 3. (non-MD) Download the blob data from the blob server using `blob` and
  2055. `credentials`.
  2056. 4. (MD) Download the blob data from the blob mirror server using `blob`,
  2057. `credentials` and the device group information.
  2058. 5. If the download stream stalls for more than 10s, exceptionally abort
  2059. these steps.
  2060. 6. Schedule a volatile background task to run the following steps:
  2061. 1. Run the _Blob Credentials Refresh Steps_ and let `credentials` be the
  2062. result.
  2063. 2. (non-MD) Request to mark the blob download from the blob server of
  2064. `blob.id` as _done_ with `credentials`.
  2065. 3. (MD) Request to mark the blob download from the blob mirror server of
  2066. `blob.id` as _done_ with `credentials` and the device group
  2067. information.
  2068. 4. If no response could be obtained within 10s or the request was
  2069. unsuccessful, log a warning.
  2070. 7. Return the resulting blob data.
  2071. ### Image, Audio, Video vs. File
  2072. Images, as well as audio and video sources can be either send as special
  2073. media messages or as files. When sending as a file, i.e. a
  2074. [`file`](ref:e2e.file) message struct with rendering type `0x00` (file), no
  2075. transcoding is necessary and no media type restrictions apply.
  2076. Clients should intelligently choose between a media message and a file
  2077. message but always leave the final choice to the user.
  2078. The following sections describe what restrictions apply and modifications
  2079. need to be made in case the source is sent as a media message, i.e. one
  2080. of the specialised (deprecated) media structs or a [`file`](ref:e2e.file)
  2081. message struct with rendering type `0x01` (media) or `0x02` (sticker).
  2082. ### Images
  2083. Images must be in JPEG format for the legacy
  2084. [`deprecated-image`](ref:e2e.deprecated-image) message and for profile
  2085. pictures.
  2086. When using the [`file`](ref:e2e.file) message struct, the following media
  2087. types are explicitly supported:
  2088. - image/gif
  2089. - image/jpeg
  2090. - image/png
  2091. - image/webp
  2092. The following media types are explicitly not supported:
  2093. - image/svg+xml
  2094. Other media types _may_ be supported.
  2095. Keep the format when resizing images or creating thumbnails, if possible
  2096. (e.g. if the source is a JPEG, make the thumbnail a JPEG). When the format
  2097. cannot be kept, use PNG for source images with transparency or
  2098. lossless encoding (e.g. screenshots) and JPEG for images without
  2099. transparency or lossy encoding (e.g. photos).
  2100. Recommended maximum dimensions:
  2101. - Small: 640x640
  2102. - Medium: 1024x1024
  2103. - Large: 1600x1600
  2104. - Extra Large: 2592x2592
  2105. - Original: As is
  2106. ### Thumbnails
  2107. Apply the logic described for images to all thumbnails with recommended
  2108. maximum dimensions of 512x512.
  2109. ### User Profile Distribution
  2110. The shareable part of the user profile consists of the user's public
  2111. nickname and the profile picture:
  2112. - The nickname is sent along with outgoing messages as `sender-nickname`
  2113. inside the [`legacy-message`](ref:payload.legacy-message) or as part of
  2114. the metadata in
  2115. [`message-with-metadata-box`](ref:payload.message-with-metadata-box).
  2116. - The profile picture is distributed as described in
  2117. [Profile Picture Distribution](ref:e2e#profile-picture-distribution).
  2118. Whether user profile distribution should be triggered by an outgoing message
  2119. is specified in the description of every message type below.
  2120. ### Profile Pictures
  2121. Apply the logic described for images to all profile pictures with
  2122. recommended maximum dimensions of 512x512 with a square aspect ratio.
  2123. #### Profile Picture Distribution
  2124. Every time a message is being sent to a specific contact or a group of
  2125. contacts, the sender needs to evaluate whether the profile picture needs to
  2126. be sent. If the receiver of the message is a group, the evaluation needs to
  2127. be done for each contact of that group.
  2128. The following steps are defined as the _Profile Picture Distribution Steps_:
  2129. 1. Let `type` be a message type associated to a message that is about to be
  2130. sent.
  2131. 2. Let `receiver` be the receiver of the message.
  2132. 3. If the properties associated to `type` do not require _User Profile
  2133. Distribution_, abort these steps without a message.
  2134. 4. If `receiver`'s Threema ID is `ECHOECHO` or a Threema Gateway ID (starts
  2135. with a `*`), abort these steps without a message.
  2136. 5. Let `cache` be the most recently distributed profile picture message
  2137. variant towards `receiver`, being either
  2138. - a blob ID if the user's profile picture was distributed via a
  2139. [`set-profile-picture`](ref:e2e.set-profile-picture) message, or
  2140. - a _remove_ mark and a timestamp if the user's profile picture was
  2141. removed via a
  2142. [`delete-profile-picture`](ref:e2e.delete-profile-picture) message.
  2143. 6. If the user has no profile picture or the settings indicate that the
  2144. user's profile picture should be shared with nobody or the settings
  2145. associated to `receiver` indicate that the profile picture should not be
  2146. distributed to it:
  2147. 1. If `cache` is a _remove_ mark and indicates that the most recent
  2148. [`delete-profile-picture`](ref:e2e.delete-profile-picture) message
  2149. towards `receiver` was sent less than seven days ago, abort these
  2150. steps without a message.
  2151. 2. Update the `cache` for `receiver` to a _remove_ mark with the current
  2152. timestamp.
  2153. 3. Return the following properties:
  2154. - `id` being a random message ID,
  2155. - `created-at` set to the current timestamp,
  2156. - `receivers` set to `receiver`,
  2157. - to construct a
  2158. [`delete-profile-picture`](ref:e2e.delete-profile-picture).
  2159. 7. If there is a cached profile picture of the user and the associated blob
  2160. was uploaded more than seven days ago, remove the cached profile
  2161. picture.
  2162. 8. If `cache` contains a blob ID of the most recent
  2163. [`set-profile-picture`](ref:e2e.set-profile-picture) message sent
  2164. towards `receiver` that equals the blob ID of the cached profile
  2165. picture, abort these steps without a message.
  2166. 9. If there is no cached profile picture, encrypt the user's profile
  2167. picture with a random symmetric key and upload it to the blob server.
  2168. Store the key and the resulting blob ID as the cached profile picture of
  2169. the user.
  2170. 10. Update the `cache` for `receiver` to the blob ID of the cached profile
  2171. picture.
  2172. 11. Return the following properties:
  2173. - `id` being a random message ID,
  2174. - `created-at` set to the current timestamp,
  2175. - `receivers` set to `receiver`,
  2176. - to construct a [`set-profile-picture`](ref:e2e.set-profile-picture)
  2177. message using the cached profile picture's blob ID and key.
  2178. When the user changes the profile picture, run the steps associated to
  2179. update the user's profile with the new profile picture or the newly removed
  2180. profile picture.
  2181. #### Profile Picture Sharing Settings
  2182. In the client settings, there are three profile picture sharing options that
  2183. the user can choose from:
  2184. - Share with nobody
  2185. - Share with everybody you write to
  2186. - Share with selected contacts only
  2187. The default is to share the profile picture with everyone.
  2188. #### Contact Profile Picture Precedence
  2189. There are three different sources of profile pictures, ordered by
  2190. precedence:
  2191. 1. _contact-defined_: Set by the contact, distributed through a
  2192. [`set-profile-picture`](ref:e2e.set-profile-picture) message.
  2193. 2. _gateway-defined_: Set by the creator in the Threema Gateway (or Threema
  2194. Broadcast) control panel and distributed through `avatar.threema.ch`.
  2195. Only applicable to Threema Gateway IDs (starting with a `*`).
  2196. 3. _user-defined_: Set by the app user for this contact or imported from
  2197. the address book. Applicable to all Threema IDs which are not Threema
  2198. Gateway IDs.
  2199. The following steps are defined as _Contact Profile Picture Selection Steps_
  2200. and will be applied to determine the contact's profile picture that should
  2201. be displayed:
  2202. 1. Let `id` be the Threema ID of the contact.
  2203. 2. If the _contact-defined_ picture is set for the contact, apply it and
  2204. abort these steps.
  2205. 3. If `id` starts with a `*` (is a Threema Gateway ID) and the
  2206. _gateway-defined_ picture is set for the contact, apply it and abort
  2207. these steps.
  2208. 4. If `id` does not start with `*` and the _user-defined_ picture is set
  2209. for the contact, apply it and abort these steps.
  2210. 5. Apply a fallback picture.
  2211. #### Recurring Gateway Contact Profile Picture Refresh
  2212. For contacts with a Threema Gateway ID (starting with a `*`), the profile
  2213. picture needs to be fetched recurringly:
  2214. 1. Fetch the profile picture for the ID from `avatar.threema.ch`.
  2215. 2. If no profile picture could be found, schedule the next refresh in 24h
  2216. and abort these steps.
  2217. 3. Store the profile picture as the _gateway-defined_ picture.
  2218. 4. Schedule the next refresh according to the `expires` header of the HTTP
  2219. response.
  2220. 5. Run the _Contact Profile Picture Selection Steps_ for this contact.
  2221. ### Audio
  2222. Audio must be in AAC format.
  2223. If the source is already in AAC, no transcoding is necessary. Otherwise,
  2224. the recommended transcoding settings are: Bitrate 128 kbit/s, 2 channels.
  2225. When recording audio (i.e. a voice message), the recommended recording
  2226. settings are: Sample rate 44.1 kHz, bitrate 32 kbit/s, 1 channel.
  2227. ### Video
  2228. Videos must be encoded in H.264 and the MP4 container format.
  2229. Recommended encoding settings for all videos:
  2230. - Low: 480x480, scale by maintaining aspect ratio to nearest multiple
  2231. of 16px. Video bitrate 384 kbit/s, audio bitrate 32 kbit/s (2
  2232. channels). Baseline Profile, Level 3.1.
  2233. - High: 848x848, scale by maintaining aspect ratio to nearest multiple
  2234. of 16px. Video bitrate 1500 kbit/s, audio bitrate 64 kbit/s (2
  2235. channels). Baseline Profile, Level 3.1.
  2236. - Original: As is. Still needs transcoding in case a different codec has
  2237. been used.
  2238. When recording a video, the following recording settings are recommended
  2239. to avoid post-reencoding: 1280x720 / 720x1280. Video bitrate 2000 kbit/s
  2240. at 30 fps, audio bitrate 128 kbit/s (2 channels).
  2241. ### Call Features
  2242. Call features are transmitted within either a
  2243. [`call-offer`](ref:e2e.call-offer) or a [`call-answer`](ref:e2e.call-answer)
  2244. message. It is an optional object containing the below defined fields. If
  2245. the object is not provided, assume an empty features object.
  2246. - Video Support (`'video'`): Set this field to `null` or an empty object if
  2247. video calls are enabled. If either side omits this field, video support
  2248. is disabled for the upcoming call.
  2249. ### Application Entrypoints
  2250. #### Work Credentials URL
  2251. The following steps are defined as _Application Work Credentials URL
  2252. Entrypoint Steps_ and must be run when the application is built for the
  2253. _Work_ flavour and is invoked by a Work credentials URL:
  2254. 1. Decode the Work credentials URL and let `work-credentials` be the result.
  2255. 2. Run the _Common Application Entrypoint Steps_ with `work-credentials`.
  2256. #### OnPrem Server/License URL
  2257. The following steps are defined as _Application OnPrem Server/License URL
  2258. Entrypoint Steps_ and must be run when the application is built for the
  2259. _OnPrem_ flavour and is invoked via an OnPrem server/license URL:
  2260. 1. Decode the OnPrem server/license URL¹ and let `on-prem-server-url` and
  2261. `work-credentials` be the result.
  2262. 2. Run the _Common Application Entrypoint Steps_ with `on-prem-server-url`
  2263. and `work-credentials`.
  2264. ¹: While the OnPrem server URL only provides the path to the OPPF file, the
  2265. OnPrem license URL additionally provides the Work credentials.
  2266. #### Default
  2267. The following steps are defined as the _Common Application Entrypoint Steps_
  2268. and resemble the default entrypoint if no specific entrypoint was invoked by
  2269. a user interaction:
  2270. 1. If identity data exists:
  2271. 1. (OnPrem: Refresh the OPPF file and apply its configuration to the
  2272. application. TODO(SE-137): Specify more clearly.)
  2273. 2. [...]
  2274. 3. Abort these steps.
  2275. 2. (Identity data is missing at this point.)
  2276. 3. (If the application is built for the _Consumer_ flavour,
  2277. request/verify the license. TODO(SE-137): Specify more clearly.)
  2278. 4. If the application is built for the _Work_ flavour:
  2279. 1. Let `work-credentials` be the provided parameters.
  2280. 2. If `work-credentials` is not defined, request the user to provide
  2281. this information and update `work-credentials` with the result.
  2282. 3. (Verify the Work license. TODO(SE-137): Specify more clearly.)
  2283. 5. If the application is built for the _OnPrem_ flavour:
  2284. 1. Let `on-prem-server-url` and `work-credentials` be the provided
  2285. parameters.
  2286. 2. If the application is built for the regular _OnPrem_ flavour:
  2287. 1. If the MDM parameter `th_onprem_server` is defined:
  2288. 1. If `on-prem-server-url` is defined and its canonical¹
  2289. representation does not equal the canonical¹ representation of
  2290. the MDM parameter `th_onprem_server`, show an error to the user
  2291. that an incorrect OnPrem server/license URL has been used and
  2292. abort these steps.
  2293. 2. Set `on-prem-server-url` to the MDM parameter `th_onprem_server`.
  2294. 2. If `on-prem-server-url` or `work-credentials` is not defined,
  2295. request the user to provide the missing information and update
  2296. `on-prem-server-url` and `work-credentials` with the result.
  2297. 3. If the application is built for the _White-Labeled OnPrem_ flavour²:
  2298. 1. If `on-prem-server-url` is defined and its canonical¹
  2299. representation does not equal the canonical¹ representation of the
  2300. preconfigured OnPrem server URL, show an error to the user that an
  2301. incorrect OnPrem server/license URL has been used and abort these
  2302. steps.
  2303. 2. Set `on-prem-server-url` to the preconfigured OnPrem server URL.
  2304. 3. If `work-credentials` is not defined, request the user to provide
  2305. the Work credentials and update `work-credentials` with the result.
  2306. 4. (Verify the OnPrem/Work license. TODO(SE-137): Specify more
  2307. clearly.)
  2308. 6. Run the _Application Setup Steps_.
  2309. ¹: The canonical URL is constructed by appending `/prov/config.oppf` if the
  2310. URL does not end with `.oppf`.
  2311. ²: Note that the `th_onprem_server` parameter is intentionally being ignored
  2312. in this case.
  2313. ### Application Setup
  2314. The following steps are defined as _Application Setup Steps_ and must be run
  2315. when no identity data exists (i.e. the application is installed for the
  2316. first time or the Threema ID and associated identity data has been removed):
  2317. 1. [...]
  2318. 2. (The application allows to create a new Threema ID or restore a backup
  2319. here. TODO(SE-137): Specify more clearly.)
  2320. 3. If OnPrem sub-flavour and the MDM parameter `th_enable_remote_secret` is
  2321. `true`, run the _Remote Secret Activate Steps_.
  2322. 4. If application state has not been set up by the _Device Join Protocol_
  2323. (meaning that multi-device is deactivated), run the following steps:
  2324. 1. [...]
  2325. 2. Update the user's feature mask on the directory server.
  2326. 3. Let `contacts` be the list of all contacts, including those with an
  2327. acquaintance level different than _direct_.
  2328. 4. Call the _Work Sync_ endpoint with `contacts` and update `contacts`
  2329. and the settings with the result.
  2330. 5. Refresh the state, type and feature mask of all `contacts` from the
  2331. directory server and make any changes persistent.
  2332. 6. Let `solicited-contacts` be a copy of `contacts` filtered in the
  2333. following way. For each `contact`:
  2334. 1. If the `contact`'s activity state is _invalid_ (i.e. it does not
  2335. exist or has been revoked), remove `contact` from the list and
  2336. abort these sub-steps.
  2337. 2. If `contact` is part of a group that is not marked as _left_, add
  2338. `contact` to the list and abort these sub-steps.
  2339. 3. Lookup the 1:1 conversation with `contact` and let `last-update`
  2340. be the associated _last update_ timestamp.
  2341. 4. If `last-update` is defined, add `contact` to the list and abort
  2342. these sub-steps.
  2343. 5. Remove `contact` from the list.
  2344. 7. If FS is supported by the client, run the _FS Refresh Steps_ with
  2345. `solicited-contacts`.
  2346. 8. For each `contact` of `solicited-contacts` run the _Bundled Messages
  2347. Send Steps_ with the following properties:
  2348. - `id` being a random message ID,
  2349. - `created-at` set to the current timestamp,
  2350. - `receivers` set to `contact`,
  2351. - to construct a
  2352. [`contact-request-profile-picture`](ref:e2e.contact-request-profile-picture)
  2353. 9. For each group not marked as _left_:
  2354. 1. If the user is the creator of the group, trigger a _group sync_
  2355. for that group.
  2356. 2. If the user is not the creator of the group, run the _Group Sync
  2357. Request Steps_ for the group.
  2358. 10. [...]
  2359. 5. Commit the application state with the updated `contacts` and settings,
  2360. outer storage potentially protected by a passphrase (if provided) and
  2361. inner storage potentially protected by RS (if created).
  2362. ### Application Update
  2363. The following steps are defined as _Application Update Steps_ and must be
  2364. run as a persistent task when the application has just been updated to a new
  2365. version or downgraded to a previous version:
  2366. 1. [...]
  2367. 2. Update the user's feature mask on the directory server.
  2368. 3. Let `contacts` be the list of all contacts (regardless of the
  2369. acquaintance level).
  2370. 4. Refresh the state, type and feature mask of all `contacts` from the
  2371. directory server and make any changes persistent.
  2372. 5. For each `contact` of `contacts`:
  2373. 1. If an associated FS session with `contact` exists and any of the FS
  2374. states is unknown or any of the stored FS versions (local or remote)
  2375. is unknown, terminate the FS session by running the _Bundled Messages
  2376. Send Steps_ with the following properties:
  2377. - `id` being a random message ID,
  2378. - `created-at` set to the current timestamp,
  2379. - `receivers` set to `contact`,
  2380. - to construct a `csp-e2e-fs.Terminate` message with cause `RESET`.
  2381. 6. [...]
  2382. Note: Reactivation of FS due to disabling multi-device should run the
  2383. _Application Setup Steps_ step 2.2. through 2.6. TODO(SE-199): This note
  2384. will be removed once multi-device supports FS.
  2385. ### Application Start
  2386. The following steps are defined as _Application Start Steps_ and must be run
  2387. as a blocking task when the application starts before running any further
  2388. sequences:
  2389. 1. [...]
  2390. 2. Attempt to unlock the outer storage, potentially protected by a
  2391. passphrase (if provided).
  2392. 3. If the Remote Secret feature is active, run the _Remote Secret Monitor
  2393. Steps_ until it yields RS and let it continue as a volatile background
  2394. task bound to the application.
  2395. 4. Unlock the inner storage, optionally protected by RS (if activated).
  2396. 5. [...]
  2397. 6. Initialise the application from the unlocked storage.
  2398. container:
  2399. _group: Header
  2400. _doc: |-
  2401. Contains an end-to-end encrypted message.
  2402. fields:
  2403. - _doc: |-
  2404. Type of the message (`common.CspE2eMessageType`).
  2405. name: type
  2406. type: u8
  2407. - _doc: |-
  2408. Inner message. Needs to be parsed according to the `type` field.
  2409. Padded with a random amount from 1 to 255 bytes in [PKCS#7
  2410. format](https://datatracker.ietf.org/doc/html/rfc5652#section-6.3).
  2411. Additionally, for security reasons, the total size of `padded-data`
  2412. should be at least 32 bytes, to avoid leaking information about the
  2413. contents.
  2414. Example padding (hex representation):
  2415. - 1 byte: `01`
  2416. - 3 bytes: `030303`
  2417. - 10 bytes: `0A0A0A0A0A0A0A0A0A0A`
  2418. To add padding without information leaks, run the following steps:
  2419. 1. Let `data` be the data to be padded.
  2420. 2. Let `pad-length` be a random number between (inclusive) 1 and 255.
  2421. 3. If the sum of the byte length of `data` and `pad-length` is less
  2422. than 32, update `pad-length` so the sum is precisely 32.
  2423. 4. Let `pad-byte` be the encoded unsigned 8-bit integer
  2424. representation of `pad-length`.
  2425. 5. Let `padded-data` be the padded data by adding `pad-length`
  2426. trailing `pad-byte` bytes to `data`.
  2427. To remove padding:
  2428. 1. Let `pad-length` be the decoded unsigned 8-bit integer
  2429. representation of the last byte of `padded-data`.
  2430. 2. Let `data` be the unpadded data by ignoring the trailing
  2431. `pad-length` bytes of `padded-data`.
  2432. name: padded-data
  2433. type: b*
  2434. group-creator-container:
  2435. _group: Header
  2436. _doc: |-
  2437. Container that is wrapped around some special group messages sent by the
  2438. creator to normal group members and vice versa.
  2439. fields:
  2440. - _doc: |-
  2441. 8 byte random group ID. Uniquely identifies the group when combined
  2442. with the creator's Threema ID.
  2443. name: group-id
  2444. type: *group-id
  2445. - _doc: |-
  2446. Inner message struct.
  2447. name: inner-data
  2448. type: b*
  2449. group-member-container:
  2450. _group: Header
  2451. _doc: |-
  2452. Container that is wrapped around most messages sent by group members to
  2453. other group members.
  2454. fields:
  2455. - _doc: |-
  2456. The group creator's Threema ID.
  2457. name: creator-identity
  2458. type: *identity
  2459. - _doc: |-
  2460. 8 byte random group ID assigned to the group by the creator.
  2461. name: group-id
  2462. type: *group-id
  2463. - _doc: |-
  2464. Inner message struct.
  2465. name: inner-data
  2466. type: b*
  2467. empty:
  2468. _doc: |-
  2469. An empty message (duh).
  2470. Only used when encapsulated by an `csp_e2e_fs.Envelope` to announce a new
  2471. FS version without explicit renegotiation.
  2472. **Properties**:
  2473. - Kind: 1:1
  2474. - Flags: None
  2475. - User profile distribution: No
  2476. - Exempt from blocking: Yes
  2477. - Implicit _direct_ contact creation: No
  2478. - Protect against replay: Yes
  2479. - Unarchive: No
  2480. - Bump _last update_: No
  2481. - Reflect:
  2482. - Incoming: No
  2483. - Outgoing: No
  2484. - _Sent_ update: No
  2485. - Delivery receipts: No
  2486. - Reactions: No
  2487. - When rejected: N/A (ignored)
  2488. - Send to Threema Gateway ID group creator: N/A
  2489. When the user submits this message in a 1:1, group or distribution list,
  2490. _Rick Astley - Never Gonna Give You Up_ must be played and looped
  2491. indefinitely on the user's device.
  2492. When receiving this message, a mechanical finger must be unlatched from
  2493. the device and boop the receiving user on the nose.
  2494. text:
  2495. _group: Conversation Messages
  2496. _doc: |-
  2497. A text message.
  2498. **Properties (1:1)**:
  2499. - Kind: 1:1
  2500. - Flags:
  2501. - `0x01`: Send push notification.
  2502. - User profile distribution: Yes
  2503. - Exempt from blocking: No
  2504. - Implicit _direct_ contact creation: Yes
  2505. - Protect against replay: Yes
  2506. - Unarchive: Yes
  2507. - Bump _last update_: Yes
  2508. - Reflect:
  2509. - Incoming: Yes
  2510. - Outgoing: Yes
  2511. - _Sent_ update: Yes
  2512. - Delivery receipts: Yes
  2513. - Reactions: Yes
  2514. - When rejected: Re-send after confirmation
  2515. - Edit applies to: Text
  2516. - Deletable by: User and sender
  2517. - Include in history: Yes
  2518. - Send to Threema Gateway ID group creator: N/A
  2519. **Properties (Group)**:
  2520. - Kind: Group
  2521. - Flags:
  2522. - `0x01`: Send push notification.
  2523. - User profile distribution: Yes
  2524. - Exempt from blocking: No
  2525. - Implicit _direct_ contact creation: No
  2526. - Protect against replay: Yes
  2527. - Unarchive: Yes
  2528. - Bump _last update_: Yes
  2529. - Reflect:
  2530. - Incoming: Yes
  2531. - Outgoing: Yes
  2532. - _Sent_ update: Yes
  2533. - Delivery receipts: N/A
  2534. - Reactions: Yes
  2535. - When rejected: Re-send after confirmation
  2536. - Edit applies to: Text
  2537. - Deletable by: User and sender
  2538. - Include in history: Yes
  2539. - Send to Threema Gateway ID group creator: If capture is enabled
  2540. When the user submits this message in a 1:1, group or distribution list
  2541. conversation:
  2542. 1. Split the provided text into multiple segments with at most 6000 UTF-8
  2543. encoded bytes while preserving grapheme clusters at boundaries and let
  2544. `text-segments` be the result.¹
  2545. 2. Run the _Messages Submit Steps_ with `messages` set from
  2546. `text-segments` (for a group, wrapped by
  2547. [`group-member-container`](ref:e2e.group-member-container)).
  2548. ¹: The UI may warn the user that the message will be split if the UTF-8
  2549. encoded text exceeds 6000 bytes and request confirmation before
  2550. submission.
  2551. When reflected from another device as an incoming or outgoing 1:1
  2552. message:
  2553. 1. Add the message to the associated 1:1 conversation.
  2554. When receiving this message as a 1:1 message:
  2555. 1. Add the message to the associated 1:1 conversation.
  2556. When reflected from another device as an incoming or outgoing group
  2557. message (wrapped by
  2558. [`group-member-container`](ref:e2e.group-member-container)):
  2559. 1. Add the message to the associated group conversation.
  2560. When receiving this message as a group message (wrapped by
  2561. [`group-member-container`](ref:e2e.group-member-container)):
  2562. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  2563. message has been discarded, abort these steps.
  2564. 2. Add the message to the associated group conversation.
  2565. fields:
  2566. - _doc: |-
  2567. UTF-8 encoded text.
  2568. name: text
  2569. type: b*
  2570. deprecated-image:
  2571. _group: Conversation Messages
  2572. _doc: |-
  2573. An image message.
  2574. Note: This message is deprecated and may be phased out eventually. When
  2575. sending images, use the [`file`](ref:e2e.file) message with the rendering
  2576. type `0x01` (media).
  2577. **Properties**:
  2578. - Kind: 1:1
  2579. - Flags:
  2580. - `0x01`: Send push notification.
  2581. - User profile distribution: Yes
  2582. - Exempt from blocking: No
  2583. - Implicit _direct_ contact creation: Yes
  2584. - Protect against replay: Yes
  2585. - Unarchive: Yes
  2586. - Bump _last update_: Yes
  2587. - Reflect:
  2588. - Incoming: Yes
  2589. - Outgoing: N/A
  2590. - _Sent_ update: Yes
  2591. - Delivery receipts: Yes
  2592. - Reactions: Yes
  2593. - When rejected: N/A (deprecated message is not being sent)
  2594. - Edit applies to: N/A
  2595. - Deletable by: User and sender
  2596. - Include in history: Yes
  2597. - Send to Threema Gateway ID group creator: N/A
  2598. The image must be in JPEG format, is uploaded to the blob server and
  2599. encrypted by:
  2600. XSalsa20-Poly1305(
  2601. key=X25519HSalsa20(<sender.CK>.secret, <receiver.CK>.public),
  2602. nonce=<deprecated-image.nonce>,
  2603. )
  2604. This message is deprecated and may no longer be submitted.
  2605. When reflected from another device as an incoming message:
  2606. 1. Run the _Common Deprecated Image Receive Steps_.
  2607. When receiving this message:
  2608. 1. Run the _Common Deprecated Image Receive Steps_.
  2609. The following steps are defined as the _Common Deprecated Image Receive
  2610. Steps_:
  2611. 1. Add the message to the associated 1:1 conversation.
  2612. 2. If this message is eligible for auto-download, schedule downloading the
  2613. image data from the blob server and request the blob to be removed.
  2614. fields:
  2615. - _doc: |-
  2616. Blob ID to obtain the image data.
  2617. name: image-blob-id
  2618. type: *blob-id
  2619. - _doc: |-
  2620. Image size in bytes.
  2621. name: image-size
  2622. type: u32-le
  2623. - _doc: |-
  2624. Random nonce used to encrypt the image data.
  2625. name: nonce
  2626. type: *nonce
  2627. deprecated-group-image:
  2628. _group: Conversation Messages
  2629. _doc: |-
  2630. An image message (only used by groups).
  2631. Note: This message is deprecated and may be phased out eventually. When
  2632. sending images, use the [`file`](ref:e2e.file) message with the rendering
  2633. type `0x01` (media).
  2634. **Properties**:
  2635. - Kind: Group
  2636. - Flags:
  2637. - `0x01`: Send push notification.
  2638. - User profile distribution: Yes
  2639. - Exempt from blocking: No
  2640. - Implicit _direct_ contact creation: No
  2641. - Protect against replay: Yes
  2642. - Unarchive: Yes
  2643. - Bump _last update_: Yes
  2644. - Reflect:
  2645. - Incoming: Yes
  2646. - Outgoing: N/A
  2647. - _Sent_ update: Yes
  2648. - Delivery receipts: N/A
  2649. - Reactions: Yes
  2650. - When rejected: N/A (deprecated message is not being sent)
  2651. - Edit applies to: N/A
  2652. - Deletable by: User and sender
  2653. - Include in history: Yes
  2654. - Send to Threema Gateway ID group creator: If capture is enabled
  2655. The image must be in JPEG format, is uploaded to the blob server and
  2656. encrypted by:
  2657. XSalsa20-Poly1305(key=<deprecated-group-image.key>, nonce=00..01)
  2658. This message is deprecated and may no longer be submitted.
  2659. When reflected from another device as an incoming message (wrapped by
  2660. [`group-member-container`](ref:e2e.group-member-container)):
  2661. 1. Run the _Common Deprecated Group Image Receive Steps_.
  2662. When receiving this message (wrapped by
  2663. [`group-member-container`](ref:e2e.group-member-container)):
  2664. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  2665. message has been discarded, abort these steps.
  2666. 2. Run the _Common Deprecated Group Image Receive Steps_.
  2667. The following steps are defined as the _Common Deprecated Group Image
  2668. Receive Steps_:
  2669. 1. Add the message to the associated group conversation.
  2670. 2. If this message is eligible for auto-download, schedule downloading the
  2671. image data from the blob server but do not request the blob to be
  2672. removed.
  2673. fields:
  2674. - _doc: |-
  2675. Blob ID to obtain the image data.
  2676. name: image-blob-id
  2677. type: *blob-id
  2678. - _doc: |-
  2679. Image size in bytes.
  2680. name: image-size
  2681. type: u32-le
  2682. - _doc: |-
  2683. Random symmetric key used to encrypt the image data.
  2684. name: key
  2685. type: *key
  2686. location:
  2687. _group: Conversation Messages
  2688. _doc: |-
  2689. A location message.
  2690. **Properties (1:1)**:
  2691. - Kind: 1:1
  2692. - Flags:
  2693. - `0x01`: Send push notification.
  2694. - User profile distribution: Yes
  2695. - Exempt from blocking: No
  2696. - Implicit _direct_ contact creation: Yes
  2697. - Protect against replay: Yes
  2698. - Unarchive: Yes
  2699. - Bump _last update_: Yes
  2700. - Reflect:
  2701. - Incoming: Yes
  2702. - Outgoing: Yes
  2703. - _Sent_ update: Yes
  2704. - Delivery receipts: Yes
  2705. - Reactions: Yes
  2706. - When rejected: Re-send after confirmation
  2707. - Edit applies to: N/A
  2708. - Deletable by: User and sender
  2709. - Include in history: Yes
  2710. - Send to Threema Gateway ID group creator: N/A
  2711. **Properties (Group)**:
  2712. - Kind: Group
  2713. - Flags:
  2714. - `0x01`: Send push notification.
  2715. - User profile distribution: Yes
  2716. - Exempt from blocking: No
  2717. - Implicit _direct_ contact creation: No
  2718. - Protect against replay: Yes
  2719. - Unarchive: Yes
  2720. - Bump _last update_: Yes
  2721. - Reflect:
  2722. - Incoming: Yes
  2723. - Outgoing: Yes
  2724. - _Sent_ update: Yes
  2725. - Delivery receipts: N/A
  2726. - Reactions: Yes
  2727. - When rejected: Re-send after confirmation
  2728. - Edit applies to: N/A
  2729. - Deletable by: User and sender
  2730. - Include in history: Yes
  2731. - Send to Threema Gateway ID group creator: If capture is enabled
  2732. When the user submits this message in a 1:1, group or distribution list
  2733. conversation:
  2734. 1. Let `location` be the provided location with the following properties:
  2735. - `latitude` being a WGS-84 string,
  2736. - `longitude` being a WGS-84 string,
  2737. - `accuracy` being a floating point number or undefined,
  2738. - `address` being an address of a point of interest or undefined,
  2739. - `name` being a name for the point of interest or undefined,
  2740. 2. If `location.name` is defined but `location.address` is not defined,
  2741. discard `location`, log an error and abort these steps.¹
  2742. 3. If the UTF-8 encoded bytes of `location.address` or `location.name`
  2743. exceed 512 bytes, discard `location`, log an error and abort these
  2744. steps.¹
  2745. 4. Run the _Messages Submit Steps_ with `messages` set from `location`
  2746. (for a group, wrapped by
  2747. [`group-member-container`](ref:e2e.group-member-container)).
  2748. ¹: The UI should prevent submission in these cases.
  2749. When reflected from another device as an incoming or outgoing 1:1
  2750. message:
  2751. 1. Add the message to the associated 1:1 conversation.
  2752. When receiving this message as a 1:1 message:
  2753. 1. Add the message to the associated 1:1 conversation.
  2754. When reflected from another device as an incoming or outgoing group
  2755. message (wrapped by
  2756. [`group-member-container`](ref:e2e.group-member-container)):
  2757. 1. Add the message to the associated group conversation.
  2758. When receiving this message as a group message (wrapped by
  2759. [`group-member-container`](ref:e2e.group-member-container)):
  2760. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  2761. message has been discarded, abort these steps.
  2762. 2. Add the message to the associated group conversation.
  2763. fields:
  2764. - _doc: |-
  2765. Location coordinates and meta information encoded in comma- and
  2766. line-separated UTF-8:
  2767. <latitude>,<longitude>[,<accuracy>]
  2768. or
  2769. <latitude>,<longitude>[,<accuracy>]
  2770. <address>
  2771. or
  2772. <latitude>,<longitude>[,<accuracy>]
  2773. <name>
  2774. <address>
  2775. Values:
  2776. - `latitude` and `longitude` are the geographic coordinates
  2777. represented in a WGS-84 string.
  2778. - `accuracy` is the accuracy in meters represented by a floating
  2779. point number formatted as a string.
  2780. - `address` is a full address. If it contains multiple lines, each
  2781. line feed must be escaped (literal `\n`).
  2782. - `name` is the name of a point of interest.
  2783. _Latitude_ and _longitude_ must always be present while _accuracy_
  2784. is optional and should only be provided when the current location of
  2785. the device is being sent. These values are comma-separated.
  2786. Following values are optional and separated by line feeds (`\n`).
  2787. This may be either:
  2788. - a single line containing the _address_ representing the closest
  2789. address matching the coordinates, or
  2790. - two lines containing a point of interest _name_ and _address_
  2791. (which means that the coordinates refer to the point of interest).
  2792. name: location
  2793. type: b*
  2794. deprecated-audio:
  2795. _group: Conversation Messages
  2796. _doc: |-
  2797. An audio message.
  2798. Note: This message is deprecated and may be phased out eventually. When
  2799. sending audio, use the [`file`](ref:e2e.file) message with the
  2800. rendering type `0x01` (media).
  2801. **Properties (1:1)**:
  2802. - Kind: 1:1
  2803. - Flags:
  2804. - `0x01`: Send push notification.
  2805. - User profile distribution: Yes
  2806. - Exempt from blocking: No
  2807. - Implicit _direct_ contact creation: Yes
  2808. - Protect against replay: Yes
  2809. - Unarchive: Yes
  2810. - Bump _last update_: Yes
  2811. - Reflect:
  2812. - Incoming: Yes
  2813. - Outgoing: N/A
  2814. - _Sent_ update: Yes
  2815. - Delivery receipts: Yes
  2816. - Reactions: Yes
  2817. - When rejected: N/A (deprecated message is not being sent)
  2818. - Edit applies to: N/A
  2819. - Deletable by: User and sender
  2820. - Include in history: Yes
  2821. - Send to Threema Gateway ID group creator: N/A
  2822. **Properties (Group)**:
  2823. - Kind: Group
  2824. - Flags:
  2825. - `0x01`: Send push notification.
  2826. - User profile distribution: Yes
  2827. - Exempt from blocking: No
  2828. - Implicit _direct_ contact creation: No
  2829. - Protect against replay: Yes
  2830. - Unarchive: Yes
  2831. - Bump _last update_: Yes
  2832. - Reflect:
  2833. - Incoming: Yes
  2834. - Outgoing: N/A
  2835. - _Sent_ update: Yes
  2836. - Delivery receipts: N/A
  2837. - Reactions: Yes
  2838. - When rejected: N/A (deprecated message is not being sent)
  2839. - Edit applies to: N/A
  2840. - Deletable by: User and sender
  2841. - Include in history: Yes
  2842. - Send to Threema Gateway ID group creator: If capture is enabled
  2843. The audio is uploaded to the blob server and encrypted by:
  2844. XSalsa20-Poly1305(key=<deprecated-audio.key>, nonce=00..01)
  2845. This message is deprecated and may no longer be submitted.
  2846. When reflected from another device as an incoming 1:1 message:
  2847. 1. Run the _Common Deprecated Audio Receive Steps_.
  2848. When receiving this message as a 1:1 message:
  2849. 1. Run the _Common Deprecated Audio Receive Steps_.
  2850. When reflected from another device as an incoming group message (wrapped
  2851. by [`group-member-container`](ref:e2e.group-member-container)):
  2852. 1. Run the _Common Deprecated Audio Receive Steps_.
  2853. When receiving this message as a group message (wrapped by
  2854. [`group-member-container`](ref:e2e.group-member-container)):
  2855. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  2856. message has been discarded, abort these steps.
  2857. 2. Run the _Common Deprecated Audio Receive Steps_.
  2858. The following steps are defined as the _Common Deprecated Audio Receive
  2859. Steps_:
  2860. 1. Add the message to the associated conversation.
  2861. 2. If this message is eligible for auto-download, schedule downloading the
  2862. audio data from the blob server. Only request the blob to be removed if
  2863. the associated conversation is a 1:1 conversation.
  2864. fields:
  2865. - _doc: |-
  2866. Audio duration in seconds.
  2867. name: duration
  2868. type: u16-le
  2869. - _doc: |-
  2870. Blob ID to obtain the audio data.
  2871. name: audio-blob-id
  2872. type: *blob-id
  2873. - _doc: |-
  2874. Audio size in bytes.
  2875. name: audio-size
  2876. type: u32-le
  2877. - _doc: |-
  2878. Random symmetric key used to encrypt the audio data.
  2879. name: key
  2880. type: *key
  2881. deprecated-video:
  2882. _group: Conversation Messages
  2883. _doc: |-
  2884. A video message.
  2885. Note: This message is deprecated and may be phased out eventually. When
  2886. sending video, use the [`file`](ref:e2e.file) message with the
  2887. rendering type `0x01` (media).
  2888. **Properties (1:1)**:
  2889. - Kind: 1:1
  2890. - Flags:
  2891. - `0x01`: Send push notification.
  2892. - User profile distribution: Yes
  2893. - Exempt from blocking: No
  2894. - Implicit _direct_ contact creation: Yes
  2895. - Protect against replay: Yes
  2896. - Unarchive: Yes
  2897. - Bump _last update_: Yes
  2898. - Reflect:
  2899. - Incoming: Yes
  2900. - Outgoing: N/A
  2901. - _Sent_ update: Yes
  2902. - Delivery receipts: Yes
  2903. - Reactions: Yes
  2904. - When rejected: N/A (deprecated message is not being sent)
  2905. - Edit applies to: N/A
  2906. - Deletable by: User and sender
  2907. - Include in history: Yes
  2908. - Send to Threema Gateway ID group creator: N/A
  2909. **Properties (Group)**:
  2910. - Kind: Group
  2911. - Flags:
  2912. - `0x01`: Send push notification.
  2913. - User profile distribution: Yes
  2914. - Exempt from blocking: No
  2915. - Implicit _direct_ contact creation: No
  2916. - Protect against replay: Yes
  2917. - Unarchive: Yes
  2918. - Bump _last update_: Yes
  2919. - Reflect:
  2920. - Incoming: Yes
  2921. - Outgoing: N/A
  2922. - _Sent_ update: Yes
  2923. - Delivery receipts: N/A
  2924. - Reactions: Yes
  2925. - When rejected: N/A (deprecated message is not being sent)
  2926. - Edit applies to: N/A
  2927. - Deletable by: User and sender
  2928. - Include in history: Yes
  2929. - Send to Threema Gateway ID group creator: If capture is enabled
  2930. The video is uploaded to the blob server and encrypted by:
  2931. XSalsa20-Poly1305(key=<deprecated-video.key>, nonce=00..01)
  2932. The thumbnail must be in JPEG format, is uploaded to the blob server
  2933. and encrypted by:
  2934. XSalsa20-Poly1305(key=<deprecated-video.key>, nonce=00..02)
  2935. This message is deprecated and may no longer be submitted.
  2936. When reflected from another device as an incoming 1:1 message:
  2937. 1. Run the _Common Deprecated Audio Receive Steps_.
  2938. When receiving this message as a 1:1 message:
  2939. 1. Run the _Common Deprecated Audio Receive Steps_.
  2940. When reflected from another device as an incoming group message (wrapped
  2941. by [`group-member-container`](ref:e2e.group-member-container)):
  2942. 1. Run the _Common Deprecated Audio Receive Steps_.
  2943. When receiving this message as a group message (wrapped by
  2944. [`group-member-container`](ref:e2e.group-member-container)):
  2945. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  2946. message has been discarded, abort these steps.
  2947. 2. Run the _Common Deprecated Audio Receive Steps_.
  2948. The following steps are defined as the _Common Deprecated Video Receive
  2949. Steps_:
  2950. 1. Add the message to the associated conversation.
  2951. 2. If this message is eligible for auto-download, schedule downloading the
  2952. video data from the blob server. Only request the blob to be removed if
  2953. the associated conversation is a 1:1 conversation.
  2954. fields:
  2955. - _doc: |-
  2956. Video duration in seconds.
  2957. name: duration
  2958. type: u16-le
  2959. - _doc: |-
  2960. Blob ID to obtain the video data.
  2961. name: video-blob-id
  2962. type: *blob-id
  2963. - _doc: |-
  2964. Video size in bytes.
  2965. name: video-size
  2966. type: u32-le
  2967. - _doc: |-
  2968. Blob ID to obtain the thumbnail in JPEG format.
  2969. name: thumbnail-blob-id
  2970. type: *blob-id
  2971. - _doc: |-
  2972. Thumbnail size in bytes.
  2973. name: thumbnail-size
  2974. type: u32-le
  2975. - _doc: |-
  2976. Random symmetric key used to encrypt the video and thumbnail data.
  2977. name: key
  2978. type: *key
  2979. file:
  2980. _group: Conversation Messages
  2981. _doc: |-
  2982. A file or media message.
  2983. **Properties (1:1)**:
  2984. - Kind: 1:1
  2985. - Flags:
  2986. - `0x01`: Send push notification.
  2987. - User profile distribution: Yes
  2988. - Exempt from blocking: No
  2989. - Implicit _direct_ contact creation: Yes
  2990. - Protect against replay: Yes
  2991. - Unarchive: Yes
  2992. - Bump _last update_: Yes
  2993. - Reflect:
  2994. - Incoming: Yes
  2995. - Outgoing: Yes
  2996. - _Sent_ update: Yes
  2997. - Delivery receipts: Yes
  2998. - Reactions: Yes
  2999. - When rejected: Re-send after confirmation
  3000. - Edit applies to: Caption
  3001. - Deletable by: User and sender
  3002. - Include in history: Yes
  3003. - Send to Threema Gateway ID group creator: N/A
  3004. **Properties (Group)**:
  3005. - Kind: Group
  3006. - Flags:
  3007. - `0x01`: Send push notification.
  3008. - User profile distribution: Yes
  3009. - Exempt from blocking: No
  3010. - Implicit _direct_ contact creation: No
  3011. - Protect against replay: Yes
  3012. - Unarchive: Yes
  3013. - Bump _last update_: Yes
  3014. - Reflect:
  3015. - Incoming: Yes
  3016. - Outgoing: Yes
  3017. - _Sent_ update: Yes
  3018. - Delivery receipts: N/A
  3019. - Reactions: Yes
  3020. - When rejected: Re-send after confirmation
  3021. - Edit applies to: Caption
  3022. - Deletable by: User and sender
  3023. - Include in history: Yes
  3024. - Send to Threema Gateway ID group creator: If capture is enabled
  3025. The file is uploaded to the blob server and encrypted by:
  3026. XSalsa20-Poly1305(key=<file.key>, nonce=00..01)
  3027. The thumbnail is uploaded to the blob server and encrypted by:
  3028. XSalsa20-Poly1305(key=<file.key>, nonce=00..02)
  3029. When the user submits this message in a 1:1, group or distribution list
  3030. conversation:
  3031. 1. Let `file` be all necessary properties to construct this message.
  3032. 2. If the UTF-8 encoded bytes of `file.name` exceed 256 bytes, discard
  3033. `file`, log an error and abort these steps.¹
  3034. 3. If the UTF-8 encoded bytes of `file.caption` exceed 6000 bytes, discard
  3035. `file`, log an error and abort these steps.¹
  3036. 4. Run the _Messages Submit Steps_ with `messages` set from `file` (for a
  3037. group, wrapped by
  3038. [`group-member-container`](ref:e2e.group-member-container)).
  3039. ¹: The UI should prevent submission in these cases.
  3040. When reflected from another device as an incoming or outgoing 1:1
  3041. message:
  3042. 1. Run the _Common File Receive Steps_.
  3043. When receiving this message as a 1:1 message:
  3044. 1. Run the _Common File Receive Steps_.
  3045. When reflected from another device as an incoming or outgoing group
  3046. message (wrapped by
  3047. [`group-member-container`](ref:e2e.group-member-container)):
  3048. 1. Run the _Common File Receive Steps_.
  3049. When receiving this message as a group message (wrapped by
  3050. [`group-member-container`](ref:e2e.group-member-container)):
  3051. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  3052. message has been discarded, abort these steps.
  3053. 2. Run the _Common File Receive Steps_.
  3054. The following steps are defined as the _Common File Receive Steps_:
  3055. 1. Add the message to the associated conversation.
  3056. 2. Schedule auto-downloading the thumbnail data from the blob server. Only
  3057. request the blob to be removed if the associated conversation is a 1:1
  3058. conversation.
  3059. 3. If this message is eligible for auto-download, schedule downloading the
  3060. file data from the blob server. Only request the blob to be removed if
  3061. the associated conversation is a 1:1 conversation.
  3062. fields:
  3063. - _doc: |-
  3064. UTF-8, JSON-encoded object with the following fields:
  3065. - Rendering type (`'j'`):
  3066. - `0`: Render as a file.
  3067. - `1`: Render as media (e.g. an image, audio or video).
  3068. - `2`: Render as a sticker (for transparent images).
  3069. If this field is not set, fall back to the value of `'i'`. If no
  3070. value could be determined or the rendering type is unassigned,
  3071. assume `0`.
  3072. - Deprecated (`'i'`): Set this to the integer `1` if the rendering
  3073. type is `1` or `2`, otherwise set this to the integer `0`.
  3074. - Encryption key (`'k'`): Random symmetric key used to encrypt the
  3075. blobs (file and thumbnail data) in lowercase hex string.
  3076. - File blob ID (`'b'`): Blob ID in lowercase hex string
  3077. representation to obtain the file data.
  3078. - File media type (`'m'`): The media type of the file.
  3079. - File name (`'n'`): Optional filename of the file.
  3080. - File size (`'s'`): File size in bytes.
  3081. - Thumbnail Blob ID (`'t'`): Optional blob containing the thumbnail
  3082. file data.
  3083. - Thumbnail media type (`'p'`): Media type of the thumbnail.
  3084. If not set, assume `image/jpeg`.
  3085. - Caption (`'d'`): Optional caption text.
  3086. - Correlation ID (`'c'`): Optional random 32 byte ASCII string to
  3087. collocate multiple media files.
  3088. - Metadata (`'x'`): An optional metadata object as defined below.
  3089. Metadata object fields depend on the media type of the file. All
  3090. fields are optional but recommended to set in order to determine the
  3091. layout logic while the file is being downloaded. Once the file has
  3092. been parsed, the parsed data supersedes this object.
  3093. For images:
  3094. - Width (`'w'`): The width as an integer in px.
  3095. - Height (`'h'`): The height as an integer in px.
  3096. - Animated (`'a'`): Set this to the boolean `true` if the image is
  3097. animated (e.g. an animated GIF).
  3098. For audio:
  3099. - Duration (`'d'`): The duration as a float in seconds.
  3100. For video:
  3101. - Width (`'w'`): The width as an integer in px.
  3102. - Height (`'h'`): The height as an integer in px.
  3103. - Duration (`'d'`): The duration as a float in seconds.
  3104. Note that the rendering logic depends on three key fields which
  3105. should be set accordingly:
  3106. - Media type,
  3107. - Rendering type,
  3108. - Animated flag in the metadata object.
  3109. name: file
  3110. type: b*
  3111. poll-setup:
  3112. _group: Conversation Messages
  3113. _doc: |-
  3114. Creates a new poll or finalises an existing poll.
  3115. During the lifecycle of a poll, this message will be used exactly twice:
  3116. Once to create the poll, and once to close it.
  3117. **Properties (1:1)**:
  3118. - Kind: 1:1
  3119. - Flags:
  3120. - `0x01`: Send push notification.
  3121. - User profile distribution: Yes
  3122. - Exempt from blocking: No
  3123. - Implicit _direct_ contact creation: Yes
  3124. - Protect against replay: Yes
  3125. - Unarchive: Yes
  3126. - Bump _last update_: Yes
  3127. - Reflect:
  3128. - Incoming: Yes
  3129. - Outgoing: Yes
  3130. - _Sent_ update: Yes
  3131. - Delivery receipts: Yes
  3132. - Reactions: Yes
  3133. - When rejected: Re-send after confirmation
  3134. - Edit applies to: N/A
  3135. - Deletable by: User only (TODO(SE-383))
  3136. - Include in history: Yes
  3137. - Send to Threema Gateway ID group creator: N/A
  3138. **Properties (Group)**:
  3139. - Kind: Group
  3140. - Flags:
  3141. - `0x01`: Send push notification.
  3142. - User profile distribution: Yes
  3143. - Exempt from blocking: Yes
  3144. - Implicit _direct_ contact creation: No
  3145. - Protect against replay: Yes
  3146. - Unarchive: Yes
  3147. - Bump _last update_: Yes
  3148. - Reflect:
  3149. - Incoming: Yes
  3150. - Outgoing: Yes
  3151. - _Sent_ update: Yes
  3152. - Delivery receipts: N/A
  3153. - Reactions: Yes
  3154. - When rejected: Re-send after confirmation
  3155. - Edit applies to: N/A
  3156. - Deletable by: User only (TODO(SE-383))
  3157. - Include in history: Yes
  3158. - Send to Threema Gateway ID group creator: If capture is enabled
  3159. When the user submits this message in a 1:1 or group conversation:
  3160. 1. Let `poll` be all necessary properties to construct this message.
  3161. 2. If the UTF-8 encoded bytes of `poll.description` exceed 256 bytes,
  3162. discard `poll`, log an error and abort these steps.¹
  3163. 3. If the UTF-8 encoded bytes of any of the `poll.choices` exceeds 256
  3164. bytes, discard `poll`, log an error and abort these steps.¹
  3165. 4. JSON encode `poll` and let `encoded-poll` be the UTF-8 encoded result.
  3166. 5. If `encoded-poll` exceeds 6000 bytes, discard `poll` (and
  3167. `encoded-poll`), log an error and abort these steps.¹
  3168. 6. Run the _Messages Submit Steps_ with `messages` set from
  3169. `encoded-poll` (for a group, wrapped by
  3170. [`group-member-container`](ref:e2e.group-member-container)).
  3171. ¹: The UI should prevent submission in these cases.
  3172. When reflected from another device as an incoming or outgoing 1:1
  3173. message:
  3174. 1. Run the _Common Poll Setup Receive Steps_.
  3175. When receiving this message as a 1:1 message:
  3176. 1. Run the _Common Poll Setup Receive Steps_.
  3177. When reflected from another device as an incoming or outgoing group
  3178. message (wrapped by
  3179. [`group-member-container`](ref:e2e.group-member-container)):
  3180. 1. Run the _Common Poll Setup Receive Steps_.
  3181. When receiving this message as a group message (wrapped by
  3182. [`group-member-container`](ref:e2e.group-member-container)):
  3183. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  3184. message has been discarded, abort these steps.
  3185. 2. Run the _Common Poll Setup Receive Steps_.
  3186. The following steps are defined as the _Common Poll Setup Receive Steps_:
  3187. 1. Let `state` be the _State_ field of the message. Let `participants` be
  3188. the _Participants_ field of the message.
  3189. 2. Look up the poll with the given ID within the conversation.
  3190. 3. If no associated poll could be found:
  3191. 1. If `state` is `1` (closed), discard the message and abort these steps.
  3192. 2. Add the poll to the associated conversation with the provided
  3193. fields of the message and abort these steps.
  3194. 4. If the associated poll is closed, discard the message and abort these steps.
  3195. 5. If `state` is `0` (open), discard the message and abort these steps.
  3196. 6. Close the poll with the given `participants`, ignore any other fields
  3197. of the message.
  3198. fields:
  3199. - _doc: |-
  3200. Random unique (per creator within this conversation) ID of the poll.
  3201. name: id
  3202. type: *poll-id
  3203. - _doc: |-
  3204. UTF-8, JSON-encoded object with the following fields:
  3205. - Description (`'d'`): A short description/topic string for the poll.
  3206. - State (`'s'`):
  3207. - `0`: Poll is _open_ for votes.
  3208. - `1`: Poll has been _closed_.
  3209. A state transition from _closed_ to _open_ is illegal and must be
  3210. ignored by the receiving client.
  3211. - Answer type (`'a'`):
  3212. - `0`: Single choice poll.
  3213. - `1`: Multiple choice poll.
  3214. Any transition from one of the types to another is illegal and
  3215. must be ignored by the receiving client.
  3216. - Announce type (`'t'`):
  3217. - `0`: Announce votes in form of the `poll-vote` message
  3218. only to the creator of the ballot. Results are invisible until
  3219. the creator closes the vote and reports the final results.
  3220. - `1`: Announce votes in form of the `poll-vote` message to
  3221. everyone in the conversation. Interim results are therefore
  3222. visible to everyone.
  3223. Any transition from one of the types to another is illegal and
  3224. must be ignored by the receiving client.
  3225. - Display mode (`'u'`):
  3226. - `0`: List mode. List choices of all participants as presented
  3227. by this message.
  3228. - `1`: Summary mode. Only display the total amount of votes per
  3229. choice and the user's vote (if any).
  3230. If the field is not present, assume _list_ mode (`0`). Any
  3231. transition from one of the modes to another is illegal and must be
  3232. ignored by the receiving client.
  3233. - Choices type (`'o'`, DEPRECATED): Always set this to the integer `0`.
  3234. - Participants (`'p'`): A list of Threema IDs that participated in
  3235. the poll (i.e. they cast a vote). This field must only be
  3236. present if the poll is being _closed_. In display mode _summary_,
  3237. this field should be an empty list and must be ignored by the
  3238. receiver.
  3239. - Choices (`'c'`): A list of choice objects as defined below.
  3240. Choice object fields:
  3241. - Choice ID (`'i'`): A per-poll unique ID of the choice in form of
  3242. an integer. Used when casting a vote.
  3243. - Description (`'n'`): Choice description in form of a string.
  3244. - Sort key (`'o'`, DEPRECATED): Set this to the index of the choice
  3245. object within the _choices_ list.
  3246. - Participant votes (`'r'`): A list of votes for this choice in the
  3247. same order as the `participants` (i.e. mapped by their associated
  3248. index). The integer `0` indicates that the participant did not vote
  3249. for this choice. Any integer value other than `0` indicates that the
  3250. participant voted for this choice. Must be of same length as
  3251. `participants`. This field must only be present if the poll is being
  3252. _closed_. In display mode _summary_ this should be an empty list and
  3253. must be ignored by the receiver.
  3254. - Total amount of votes (`'t'`): The total amount of votes for this
  3255. choice. This field must only be present if the poll is being
  3256. _closed_. In display mode _normal_ this field should not be
  3257. present and must be ignored by the receiver.
  3258. name: poll
  3259. type: b*
  3260. poll-vote:
  3261. _group: Conversation Messages
  3262. _doc: |-
  3263. Cast a vote on a poll.
  3264. **Properties (1:1)**:
  3265. - Kind: 1:1
  3266. - Flags: None
  3267. - User profile distribution: Yes
  3268. - Exempt from blocking: No
  3269. - Implicit _direct_ contact creation: No
  3270. - Protect against replay: Yes
  3271. - Unarchive: No¹
  3272. - Bump _last update_: No¹
  3273. - Reflect:
  3274. - Incoming: Yes
  3275. - Outgoing: Yes
  3276. - _Sent_ update: No
  3277. - Delivery receipts: No
  3278. - Reactions: No
  3279. - When rejected: N/A (ignored)
  3280. - Edit applies to: N/A (can just send another `poll-vote`)
  3281. - Deletable by: User only (TODO(SE-383))
  3282. - Include in history: Yes
  3283. - Send to Threema Gateway ID group creator: N/A
  3284. **Properties (Group)**:
  3285. - Kind: Group
  3286. - Flags: None
  3287. - User profile distribution: Yes
  3288. - Exempt from blocking: Yes
  3289. - Implicit _direct_ contact creation: No
  3290. - Protect against replay: Yes
  3291. - Unarchive: No¹
  3292. - Bump _last update_: No¹
  3293. - Reflect:
  3294. - Incoming: Yes
  3295. - Outgoing: Yes
  3296. - _Sent_ update: No
  3297. - Delivery receipts: N/A
  3298. - Reactions: No
  3299. - When rejected: N/A (ignored)
  3300. - Edit applies to: N/A (can just send another `poll-vote`)
  3301. - Deletable by: User only (TODO(SE-383))
  3302. - Include in history: Yes
  3303. - Send to Threema Gateway ID group creator: If capture is enabled
  3304. ¹: A [`poll-vote`](ref:e2e.poll-vote) updates the poll state initiated by
  3305. a corresponding [`poll-setup`](ref:e2e.poll-setup), meaning it does not
  3306. produce a new visible message.
  3307. When the user submits this message in a 1:1 or group conversation by
  3308. casting a vote:
  3309. 1. Let `vote` be all necessary properties to construct this message.
  3310. 2. JSON encode `vote` and let `encoded-vote` be the UTF-8 encoded result.
  3311. 3. If `encoded-vote` exceeds 6000 bytes, discard `vote` (and
  3312. `encoded-vote`), log an error and abort these steps.¹
  3313. 4. Run the _Messages Submit Steps_ with `messages` set from
  3314. `encoded-vote` (for a group, wrapped by
  3315. [`group-member-container`](ref:e2e.group-member-container)).
  3316. ¹: The UI should prevent submission in these cases.
  3317. When reflected from another device as an incoming or outgoing 1:1
  3318. message:
  3319. 1. Run the _Common Poll Vote Receive Steps_.
  3320. When receiving this message as a 1:1 message:
  3321. 1. Run the _Common Poll Vote Receive Steps_.
  3322. When reflected from another device as an incoming or outgoing group
  3323. message (wrapped by
  3324. [`group-member-container`](ref:e2e.group-member-container)):
  3325. 1. Run the _Common Poll Vote Receive Steps_.
  3326. When receiving this message as a group message (wrapped by
  3327. [`group-member-container`](ref:e2e.group-member-container)):
  3328. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  3329. message has been discarded, abort these steps.
  3330. 2. Run the _Common Poll Vote Receive Steps_.
  3331. The following steps are defined as the _Common Poll Vote Receive Steps_.
  3332. 1. Look up the poll with the given ID within the conversation.
  3333. 2. If no associated poll could be found or if the associated poll is
  3334. closed, discard the message and abort these steps.
  3335. 3. Update the poll with the provided choices of the sender.
  3336. fields:
  3337. - _doc: |-
  3338. The Threema ID of the creator of the poll.
  3339. name: creator-identity
  3340. type: *identity
  3341. - _doc: |-
  3342. ID of the associated poll.
  3343. name: poll-id
  3344. type: *poll-id
  3345. - _doc: |-
  3346. UTF-8, JSON-encoded list containing one or more choice tuples. Each
  3347. choice tuple contains the following two integer values:
  3348. - Choice ID, referring to the Choice ID defined in the
  3349. `poll-setup` message.
  3350. - Selected:
  3351. - `0`: The choice has not been selected.
  3352. - `1`: The choice has been selected.
  3353. Note: For protocol simplicity, a vote must always include all possible
  3354. choices, whether or not they have been selected.
  3355. name: choices
  3356. type: b*
  3357. call-offer:
  3358. _group: Conversation Messages
  3359. _doc: |-
  3360. Initiates a call.
  3361. **Properties**:
  3362. - Kind: 1:1
  3363. - Flags:
  3364. - `0x01`: Send push notification.
  3365. - `0x20`: Short-lived server queuing.
  3366. - User profile distribution: Yes
  3367. - Exempt from blocking: No
  3368. - Implicit _direct_ contact creation: Yes
  3369. - Protect against replay: Yes
  3370. - Unarchive: Yes
  3371. - Bump _last update_: Yes
  3372. - Reflect:
  3373. - Incoming: Yes
  3374. - Outgoing: Yes
  3375. - _Sent_ update: No
  3376. - Delivery receipts: No
  3377. - Reactions: No
  3378. - When rejected: Abort call
  3379. - Edit applies to: N/A
  3380. - Deletable by: User only (TODO(SE-384))
  3381. - Include in history: No
  3382. - Send to Threema Gateway ID group creator: N/A
  3383. [//]: # "When submit / receiving / reflected: TODO(SE-102)"
  3384. fields:
  3385. - _doc: |-
  3386. UTF-8, JSON-encoded object with the following fields:
  3387. - Call ID (`'callId'`): Random 32 bit unsigned integer greater than 0
  3388. that uniquely identifies a call throughout its lifetime. Assume
  3389. `0` if not set.
  3390. - WebRTC Offer (`'offer'`): An offer object.
  3391. - Feature negotiation (`'features'`): Optional Call Features object.
  3392. Offer object fields:
  3393. - WebRTC Offer SDP type (`'sdpType'`): Set this to `'offer'` and ignore
  3394. offers with other types.
  3395. - WebRTC Offer SDP (`'sdp'`): Opaque string containing the SDP.
  3396. name: offer
  3397. type: b*
  3398. call-answer:
  3399. _group: Conversation Messages
  3400. _doc: |-
  3401. Answer or reject a call.
  3402. **Properties**:
  3403. - Kind: 1:1
  3404. - Flags:
  3405. - `0x01`: Send push notification.
  3406. - `0x20`: Short-lived server queuing.
  3407. - User profile distribution: Only if accepted (`action`: `1`)
  3408. - Exempt from blocking: No
  3409. - Implicit _direct_ contact creation: No
  3410. - Protect against replay: Yes
  3411. - Unarchive: No¹
  3412. - Bump _last update_: No¹
  3413. - Reflect:
  3414. - Incoming: Yes
  3415. - Outgoing: Yes
  3416. - _Sent_ update: No
  3417. - Delivery receipts: No
  3418. - Reactions: No
  3419. - When rejected: Abort call
  3420. - Edit applies to: N/A
  3421. - Deletable by: User only (TODO(SE-384))
  3422. - Include in history: No
  3423. - Send to Threema Gateway ID group creator: N/A
  3424. ¹: A [`call-answer`](ref:e2e.call-answer) updates the call state initiated
  3425. by a corresponding [`call-offer`](ref:e2e.call-offer), meaning it does not
  3426. produce a new visible message.
  3427. [//]: # "When submit / receiving / reflected: TODO(SE-102)"
  3428. fields:
  3429. - _doc: |-
  3430. UTF-8, JSON-encoded object with the following fields:
  3431. - Call ID (`'callId'`): Random 32 bit unsigned integer greater than 0
  3432. that uniquely identifies a call throughout its lifetime. Assume
  3433. `0` if not set.
  3434. - Required action (`'action'`):
  3435. - `0`: The call has been rejected and needs to be aborted.
  3436. - `1`: The call has been accepted and a connection needs to be
  3437. established.
  3438. - Rejection reason (`'rejectReason'`): If the call has been rejected,
  3439. this field contains a reject reason:
  3440. - `0`: Generic or unspecified rejection.
  3441. - `1`: The callee is busy (another call is active).
  3442. - `2`: The callee did not accept the call in time.
  3443. - `3`: The callee explicitly rejected the call.
  3444. - `4`: The callee disabled calls.
  3445. - `5`: The callee was called during an off-hour period.
  3446. - WebRTC Answer (`'answer'`): An answer object.
  3447. - Feature negotiation (`'features'`): Optional Call Features object.
  3448. Answer object fields:
  3449. - WebRTC Answer SDP type (`'sdpType'`): Set this to `'answer'` and ignore
  3450. answers with other types.
  3451. - WebRTC Answer SDP (`'sdp'`): Opaque string containing the SDP.
  3452. name: answer
  3453. type: b*
  3454. call-ice-candidate:
  3455. _group: Conversation Messages
  3456. _doc: |-
  3457. An ICE candidate for an ongoing call.
  3458. **Properties**:
  3459. - Kind: 1:1
  3460. - Flags:
  3461. - `0x01`: Send push notification.
  3462. - `0x20`: Short-lived server queuing.
  3463. - User profile distribution: No
  3464. - Exempt from blocking: No
  3465. - Implicit _direct_ contact creation: No
  3466. - Protect against replay: No¹
  3467. - Unarchive: No
  3468. - Bump _last update_: No
  3469. - Reflect:
  3470. - Incoming: Yes
  3471. - Outgoing: No
  3472. - _Sent_ update: No
  3473. - Delivery receipts: No
  3474. - Reactions: No
  3475. - When rejected: N/A (ignored)
  3476. - Edit applies to: N/A
  3477. - Deletable by: N/A
  3478. - Include in history: No
  3479. - Send to Threema Gateway ID group creator: N/A
  3480. ¹: This message does not trigger any kind of reaction and adding ICE
  3481. candidates again has no ill-effect.
  3482. [//]: # "When submit / receiving / reflected: TODO(SE-102)"
  3483. fields:
  3484. - _doc: |-
  3485. UTF-8, JSON-encoded object with the following fields:
  3486. - Call ID (`'callId'`): Random 32 bit unsigned integer greater than 0
  3487. that uniquely identifies a call throughout its lifetime. Assume
  3488. `0` if not set.
  3489. - Deprecated (`'removed'`): Always set this to `false` and ignore
  3490. messages with this field set to `true`.
  3491. - WebRTC Candidates (`'candidates'`): An array of candidate objects.
  3492. Candidate object fields:
  3493. - WebRTC Candidate SDP (`'candidate'`): Opaque string containing the
  3494. ICE candidate SDP.
  3495. - WebRTC MID (`'sdpMid'`): Media stream identification string or
  3496. `null`.
  3497. - WebRTC Media Line Index (`'sdpMLineIndex'`): Media description
  3498. line index integer or `null`.
  3499. - WebRTC Username Fragment (`'ufrag'`): ICE username fragment or
  3500. `null`.
  3501. name: candidates
  3502. type: b*
  3503. call-hangup:
  3504. _group: Conversation Messages
  3505. _doc: |-
  3506. Hang up a call.
  3507. **Properties**:
  3508. - Kind: 1:1
  3509. - Flags:
  3510. - `0x01`: Send push notification.
  3511. - User profile distribution: No
  3512. - Exempt from blocking: No
  3513. - Implicit _direct_ contact creation: No
  3514. - Protect against replay: Yes
  3515. - Unarchive: If no corresponding `call-offer` can be found¹
  3516. - Bump _last update_: If no corresponding `call-offer` can be found¹
  3517. - Reflect:
  3518. - Incoming: Yes
  3519. - Outgoing: Yes
  3520. - _Sent_ update: No
  3521. - Delivery receipts: No
  3522. - Reactions: No
  3523. - When rejected: N/A (ignored)
  3524. - Edit applies to: N/A
  3525. - Deletable by: User only (TODO(SE-384))
  3526. - Include in history: No
  3527. - Send to Threema Gateway ID group creator: N/A
  3528. ¹: A [`call-hangup`](ref:e2e.call-hangup) usually updates the call state
  3529. initiated by a corresponding [`call-offer`](ref:e2e.call-offer), meaning
  3530. it does not produce a new visible message. However, the
  3531. [`call-offer`](ref:e2e.call-offer) uses the _Short-lived server queuing_
  3532. flag and therefore may be lost. In that case, the
  3533. [`call-hangup`](ref:e2e.call-hangup) does create a visible _call missed_
  3534. message.
  3535. [//]: # "When submit / receiving / reflected: TODO(SE-102)"
  3536. fields:
  3537. - _doc: |-
  3538. UTF-8, JSON-encoded object. If this field contains zero bytes, assume
  3539. an empty object. Contains the following fields:
  3540. - Call ID (`'callId'`): Random 32 bit unsigned integer greater than 0
  3541. that uniquely identifies a call throughout its lifetime. Assume
  3542. `0` if not set.
  3543. name: hangup
  3544. type: b*
  3545. call-ringing:
  3546. _group: Conversation Messages
  3547. _doc: |-
  3548. Sent by the callee to indicate that the call is ringing.
  3549. **Properties**:
  3550. - Kind: 1:1
  3551. - Flags:
  3552. - `0x01`: Send push notification.
  3553. - `0x20`: Short-lived server queuing.
  3554. - User profile distribution: No
  3555. - Exempt from blocking: No
  3556. - Implicit _direct_ contact creation: No
  3557. - Protect against replay: Yes
  3558. - Unarchive: No¹
  3559. - Bump _last update_: No¹
  3560. - Reflect:
  3561. - Incoming: Yes
  3562. - Outgoing: Yes
  3563. - _Sent_ update: No
  3564. - Delivery receipts: No
  3565. - Reactions: No
  3566. - When rejected: Abort call
  3567. - Edit applies to: N/A
  3568. - Deletable by: N/A
  3569. - Include in history: No
  3570. - Send to Threema Gateway ID group creator: N/A
  3571. ¹: A [`call-ringing`](ref:e2e.call-ringing) updates the call state
  3572. initiated by a corresponding [`call-offer`](ref:e2e.call-offer), meaning
  3573. it does not produce a new visible message.
  3574. [//]: # "When submit / receiving / reflected: TODO(SE-102)"
  3575. fields:
  3576. - _doc: |-
  3577. UTF-8, JSON-encoded object. If this field contains zero bytes, assume
  3578. an empty object. Contains the following fields:
  3579. - Call ID (`'callId'`): Random 32 bit unsigned integer greater than 0
  3580. that uniquely identifies a call throughout its lifetime. Assume
  3581. `0` if not set.
  3582. name: hangup
  3583. type: b*
  3584. delivery-receipt:
  3585. _group: Status Updates
  3586. _doc: |-
  3587. Confirms reception or delivers detailed status updates of a message.
  3588. **Properties (1:1)**:
  3589. - Kind: 1:1
  3590. - Flags: None
  3591. - User profile distribution: Only for reactions
  3592. - Exempt from blocking: No
  3593. - Implicit _direct_ contact creation: No
  3594. - Protect against replay: Only for reactions¹
  3595. - Unarchive: No
  3596. - Bump _last update_: No
  3597. - Reflect:
  3598. - Incoming: Yes
  3599. - Outgoing: Yes²
  3600. - _Sent_ update: No
  3601. - Delivery receipts: No, that would be silly!
  3602. - Reactions: No (also silly)
  3603. - When rejected: N/A (ignored)
  3604. - Edit applies to: N/A (can just send another `delivery-receipt`)
  3605. - Deletable by: N/A
  3606. - Include in history: Yes
  3607. - Send to Threema Gateway ID group creator: N/A
  3608. ¹: Repeating a status of type _received_ or _read_ has no ill-effects.
  3609. ²: When the message is being _read_ and _read_ receipts are disabled, an
  3610. `d2d.IncomingMessageUpdate` will be reflected instead.
  3611. **Properties (Group)**:
  3612. - Kind: Group
  3613. - Flags: None
  3614. - User profile distribution: Only for reactions
  3615. - Exempt from blocking: No
  3616. - Implicit _direct_ contact creation: No
  3617. - Protect against replay: Only for reactions¹
  3618. - Unarchive: No
  3619. - Bump _last update_: No
  3620. - Reflect:
  3621. - Incoming: Yes
  3622. - Outgoing: Yes. When the message is being _read_ and _read_ receipts
  3623. are disabled, reflect an `d2d.IncomingMessageUpdate` (since no
  3624. `delivery-receipt` is sent in this case).
  3625. - _Sent_ update: No
  3626. - Delivery receipts: No, that would be silly!
  3627. - Reactions: No (also silly)
  3628. - When rejected: N/A (ignored)
  3629. - Edit applies to: N/A (can just send another `delivery-receipt`)
  3630. - Deletable by: N/A
  3631. - Include in history: Yes
  3632. - Send to Threema Gateway ID group creator: If capture is enabled
  3633. ¹: Repeating a status of type _received_ or _read_ has no ill-effects.
  3634. When the user opens a 1:1 conversation or marks it as _read_ by another
  3635. mechanism:
  3636. 1. Let `message-ids` be all message IDs associated to messages of the
  3637. conversation that require _automatic_ delivery receipts and which are
  3638. not yet marked as _read_.
  3639. 2. Split the provided `message-ids` into bundles of at most 875 message
  3640. IDs and let `message-ids-bundles` be the result.¹
  3641. 3. Run the _Messages Submit Steps_ with `messages` set to create one or
  3642. more [`delivery-receipt`](ref:e2e.delivery-receipt)s from
  3643. `message-ids-bundles` with status `0x02`.
  3644. ¹: Each message ID has 8 bytes, divided by at most 7000 bytes.
  3645. When reflected from another device as an incoming 1:1 message:
  3646. 1. Run the _Common Incoming Delivery Receipt Steps_.
  3647. When reflected from another device as an outgoing 1:1 message:
  3648. 1. Run the _Common Outgoing Delivery Receipt Steps_.
  3649. When receiving this message as a 1:1 message:
  3650. 1. Run the _Common Incoming Delivery Receipt Steps_.
  3651. When reflected from another device as an incoming group message (wrapped
  3652. by [`group-member-container`](ref:e2e.group-member-container)):
  3653. 1. If `status` is not `0x03` or `0x04` (i.e. not a reaction), log a
  3654. notice, discard the message and abort these steps.
  3655. 2. Run the _Common Incoming Delivery Receipt Steps_.
  3656. When reflected from another device as an outgoing group message (wrapped
  3657. by [`group-member-container`](ref:e2e.group-member-container)):
  3658. 1. If `status` is not `0x03` or `0x04` (i.e. not a reaction), log a
  3659. notice, discard the message and abort these steps.
  3660. 2. Run the _Common Outgoing Delivery Receipt Steps_.
  3661. When receiving this message as a group message (wrapped by
  3662. [`group-member-container`](ref:e2e.group-member-container)):
  3663. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  3664. message has been discarded, abort these steps.
  3665. 2. If `status` is not `0x03` or `0x04` (i.e. not a reaction), log a
  3666. notice, discard the message and abort these steps.
  3667. 3. Run the _Common Incoming Delivery Receipt Steps_.
  3668. The following steps are defined as the _Common Incoming Delivery Receipt
  3669. Steps_:
  3670. 1. For each `message-id` of `message-ids`:
  3671. 1. Lookup the associated message for `message-id` in the associated
  3672. conversation and let `referred-message` be the result.
  3673. 2. If `referred-message` is not defined, abort these sub-steps.
  3674. 3. If the associated conversation is a 1:1 conversation and the
  3675. original sender of `referred-message` is not the user, abort these
  3676. sub-steps.
  3677. 4. If `status` is `0x01` or `0x02` (i.e. a delivery receipt) and
  3678. `referred-message` allows for delivery receipts (see the associated
  3679. _Delivery receipts_ property), apply and replace the delivery
  3680. receipt of the sender to `referred-message` with the associated
  3681. timestamp set to the message's (the `delivery-receipt`'s)
  3682. `created-at`.
  3683. 5. If `status` is `0x03` or `0x04` (i.e. a reaction) and
  3684. `referred-message` is reactable (see the associated _Reactions_
  3685. property), apply and replace any existing reaction of the sender to
  3686. `referred-message` with the reaction timestamp set to the message's
  3687. (the `delivery-receipt`'s) `created-at`.¹
  3688. The following steps are defined as the _Common Outgoing Delivery Receipt
  3689. Steps_:
  3690. 1. For each `message-id` of `message-ids`:
  3691. 1. Lookup the associated message for `message-id` in the associated
  3692. conversation and let `referred-message` be the result.
  3693. 2. If `referred-message` is not defined, abort these sub-steps.
  3694. 3. If the associated conversation is a 1:1 conversation and the
  3695. original sender of `referred-message` is the user, abort these
  3696. sub-steps.
  3697. 4. If `status` is `0x01` or `0x02` (i.e. a delivery receipt) and
  3698. `referred-message` allows for delivery receipts (see the associated
  3699. _Delivery receipts_ property), apply and replace the delivery
  3700. receipt of the user to `referred-message` with the associated
  3701. timestamp set to the message's (the `delivery-receipt`'s)
  3702. `created-at`.
  3703. 5. If `status` is `0x03` or `0x04` (i.e. a reaction) and
  3704. `referred-message` is reactable (see the associated _Reactions_
  3705. property), apply and replace any existing reaction of the user to
  3706. `referred-message` with the reaction timestamp set to the message's
  3707. (the `delivery-receipt`'s) `created-at`.¹
  3708. ¹: Note that the deprecated reactions transmitted by a `delivery-receipt`
  3709. always replace **all existing reactions** of the respective sender,
  3710. including new-style reactions transmitted by a `csp_e2e.Reaction` message.
  3711. fields:
  3712. - _doc: |-
  3713. Message status:
  3714. - `0x01`: Message was received.
  3715. - `0x02`: Message was read.
  3716. - `0x03`: **Deprecated** Maps to the 👍 emoji (`1F44D`).
  3717. - `0x04`: **Deprecated** Maps to the 👎 emoji (`1F44E`).
  3718. Note that only the `0x01` and `0x02` variants are considered true
  3719. _delivery receipts_ whereas the deprecated `0x03` and `0x04` variants
  3720. are considered _reactions_ (just like `csp_e2e.Reaction`).
  3721. The following replacement logic is to be applied on a message's
  3722. status when displayed:
  3723. 1. `0x02` replaces groups listed below,
  3724. 2. `0x01` replaces the unlisted _created_ status.
  3725. name: status
  3726. type: u8
  3727. - _doc: |-
  3728. One or more `message-id`s whose status should be updated.
  3729. name: message-ids
  3730. type: *message-ids
  3731. typing-indicator:
  3732. _group: Status Updates
  3733. _doc: |-
  3734. Indicates whether a contact is currently typing.
  3735. **Properties**:
  3736. - Kind: 1:1
  3737. - Flags:
  3738. - `0x02`: No server queuing.
  3739. - `0x04`: No server acknowledgement.
  3740. - User profile distribution: No
  3741. - Exempt from blocking: No
  3742. - Implicit _direct_ contact creation: No
  3743. - Protect against replay: No¹
  3744. - Unarchive: No
  3745. - Bump _last update_: No
  3746. - Reflect:
  3747. - Incoming: Yes
  3748. - Outgoing: No
  3749. - _Sent_ update: No
  3750. - Delivery receipts: No
  3751. - Reactions: No
  3752. - When rejected: N/A (ignored)
  3753. - Edit applies to: N/A
  3754. - Deletable by: N/A
  3755. - Include in history: No
  3756. - Send to Threema Gateway ID group creator: N/A
  3757. ¹: It is deemed acceptable if the _typing_ indicator in the UI is replayed
  3758. since there is no further consequence.
  3759. When the user is currently _typing_ while composing a **new**¹ message in
  3760. an associated conversation:
  3761. 1. Schedule a volatile task to run the _Bundled Messages Send Steps_ with
  3762. the following properties:
  3763. - `id` set to a random message ID,
  3764. - `created-at` set to the current timestamp,
  3765. - `receivers` set to the targeted receiver,
  3766. - to construct this message with `is-typing` set to `1`.
  3767. 2. Start a _user is typing_ timer in the conversation to rerun these
  3768. steps in 10s.
  3769. When the user stopped _typing_ while composing a message in an associated
  3770. conversation, or when the user left the conversation view:
  3771. 1. If no _user is typing_ timer is running for the conversation, abort
  3772. these steps.
  3773. 2. Stop the _user is typing_ timer of the conversation.
  3774. 3. Schedule a volatile task to run the _Bundled Messages Send Steps_ with
  3775. the following properties:
  3776. - `id` set to a random message ID,
  3777. - `created-at` set to the current timestamp,
  3778. - `receivers` set to the targeted receiver,
  3779. - to construct this message with `is-typing` set to `0`.
  3780. When reflected from another device as an incoming message:
  3781. 1. Run the _Common Typing Indicator Receive Steps_.
  3782. When receiving this message:
  3783. 1. Run the _Common Typing Indicator Receive Steps_.
  3784. The following steps are defined as the _Common Typing Indicator Receive
  3785. Steps_:
  3786. 1. If `is-typing` is `1`, start a timer to display that the sender is
  3787. typing in the associated conversation for the next 15s.
  3788. 2. If `is-typing` is `0`, cancel any running timer displaying that the
  3789. sender is typing in the associated conversation.
  3790. ¹: Editing a message may not trigger _typing_.
  3791. fields:
  3792. - _doc: |-
  3793. Set to `1` in case the contact is currently typing or `0` in
  3794. case the contact stopped typing. Other values are invalid.
  3795. name: is-typing
  3796. type: u8
  3797. set-profile-picture:
  3798. _group: Contact and Group Control
  3799. _doc: |-
  3800. Set the profile picture of a contact or a group.
  3801. **Properties (1:1)**:
  3802. - Kind: 1:1
  3803. - Flags: None
  3804. - User profile distribution: No (obviously)
  3805. - Exempt from blocking: No
  3806. - Implicit _direct_ contact creation: No
  3807. - Protect against replay: Yes
  3808. - Unarchive: No
  3809. - Bump _last update_: No
  3810. - Reflect:
  3811. - Incoming: Yes
  3812. - Outgoing: Yes
  3813. - _Sent_ update: No
  3814. - Delivery receipts: No
  3815. - Reactions: No
  3816. - When rejected: N/A (ignored)
  3817. - Edit applies to: N/A (can just send another `set-profile-picture`)
  3818. - Deletable by: N/A (can just send a `delete-profile-picture`)
  3819. - Include in history: Yes
  3820. - Send to Threema Gateway ID group creator: N/A
  3821. **Properties (Group)**:
  3822. - Kind: Group
  3823. - Flags: None
  3824. - User profile distribution: No (obviously)
  3825. - Exempt from blocking: Yes
  3826. - Implicit _direct_ contact creation: No
  3827. - Protect against replay: Yes
  3828. - Unarchive: No
  3829. - Bump _last update_: No
  3830. - Reflect:
  3831. - Incoming: Yes
  3832. - Outgoing: Yes
  3833. - _Sent_ update: No
  3834. - Delivery receipts: N/A
  3835. - Reactions: No
  3836. - When rejected: N/A¹
  3837. - Edit applies to: N/A (can just send another `set-profile-picture`)
  3838. - Deletable by: N/A (can just send a `delete-profile-picture`)
  3839. - Include in history: Yes
  3840. - Send to Threema Gateway ID group creator: N/A
  3841. ¹: For the group creator it will be handled as if `group-sync-request` was
  3842. received, re-sending the group profile picture state, implicitly triggered
  3843. by FS `Reject` receive steps.
  3844. The profile picture must be in JPEG format, is uploaded to the blob
  3845. server and encrypted by:
  3846. XSalsa20-Poly1305(key=<set-profile-picture.key>, nonce=00..01)
  3847. When reflected from another device as an outgoing 1:1 message:
  3848. 1. Update the most recently distributed profile picture cache for the
  3849. contact to the enclosed blob ID.
  3850. When receiving this message as a 1:1 message:
  3851. 1. Download the picture from the blob server but do not request the blob
  3852. to be removed. Store the profile picture.
  3853. 2. Store the picture as the _contact-defined_ profile picture and run the
  3854. _Contact Profile Picture Selection Steps_.
  3855. When receiving this message as a group message (wrapped by
  3856. [`group-creator-container`](ref:e2e.group-creator-container)):
  3857. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  3858. message has been discarded, abort these steps.
  3859. 2. Download the picture from the blob server but do not request the blob
  3860. to be removed. Let `profile-picture` be the result.
  3861. 3. Let `group` be a snapshot of the current group state.
  3862. 4. If `group.profile-picture` is defined and equals `profile-picture`
  3863. (i.e. no changes), discard the message and abort these steps.
  3864. 5. (MD) Run the following sub-steps:
  3865. 1. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  3866. precondition:
  3867. 1. If the group does not exist or the group is marked as _left_, log
  3868. a warning that a group sync race occurred, discard the message
  3869. and abort these steps.
  3870. 2. (MD) Let `group` be a snapshot of the current group state.
  3871. 3. (MD) If `group.profile-picture` is defined and equals
  3872. `profile-picture`, log a warning that a group sync race occurred.
  3873. 4. (MD) Reflect a `GroupSync.Update` with `group` set to contain
  3874. `profile_picture` set to `profile-picture.
  3875. 5. (MD) Commit the transaction and await acknowledgement.
  3876. 6. Store the profile picture and and apply it to the group.
  3877. fields:
  3878. - _doc: |-
  3879. Blob ID to obtain the image data.
  3880. name: picture-blob-id
  3881. type: *blob-id
  3882. - _doc: |-
  3883. Profile picture size in bytes.
  3884. name: picture-size
  3885. type: u32-le
  3886. - _doc: |-
  3887. Random symmetric key used to encrypt the image data.
  3888. name: key
  3889. type: *key
  3890. delete-profile-picture:
  3891. _group: Contact and Group Control
  3892. _doc: |-
  3893. Delete the profile picture of a contact.
  3894. **Properties (1:1)**:
  3895. - Kind: 1:1
  3896. - Flags: None
  3897. - User profile distribution: No (obviously)
  3898. - Exempt from blocking: No
  3899. - Implicit _direct_ contact creation: No
  3900. - Protect against replay: Yes
  3901. - Unarchive: No
  3902. - Bump _last update_: No
  3903. - Reflect:
  3904. - Incoming: Yes
  3905. - Outgoing: Yes
  3906. - _Sent_ update: No
  3907. - Delivery receipts: No
  3908. - Reactions: No
  3909. - When rejected: N/A (ignored)
  3910. - Edit applies to: N/A (can just send another `delete-profile-picture`)
  3911. - Deletable by: N/A
  3912. - Include in history: Yes
  3913. - Send to Threema Gateway ID group creator: N/A
  3914. **Properties (Group)**:
  3915. - Kind: Group
  3916. - Flags: None
  3917. - User profile distribution: No (obviously)
  3918. - Exempt from blocking: Yes
  3919. - Implicit _direct_ contact creation: No
  3920. - Protect against replay: Yes
  3921. - Unarchive: No
  3922. - Bump _last update_: No
  3923. - Reflect:
  3924. - Incoming: Yes
  3925. - Outgoing: Yes
  3926. - _Sent_ update: No
  3927. - Delivery receipts: N/A
  3928. - Reactions: No
  3929. - When rejected: N/A¹
  3930. - Edit applies to: N/A (can just send another `delete-profile-picture`)
  3931. - Deletable by: N/A
  3932. - Include in history: Yes
  3933. - Send to Threema Gateway ID group creator: N/A
  3934. ¹: For the group creator it will be handled as if `group-sync-request` was
  3935. received, re-sending the group profile picture state, implicitly triggered
  3936. by FS `Reject` receive steps.
  3937. When reflected from another device as an incoming 1:1 message:
  3938. 1. Remove the _contact-defined_ profile picture and run the _Contact
  3939. Profile Picture Selection Steps_.
  3940. When reflected from another device as an outgoing 1:1 message:
  3941. 1. Update the most recently distributed profile picture cache for the
  3942. contact to a _remove_ mark with the reflected timestamp.
  3943. When receiving this message as a 1:1 message:
  3944. 1. Remove the _contact-defined_ profile picture and run the _Contact
  3945. Profile Picture Selection Steps_.
  3946. When receiving this message as a group message (wrapped by
  3947. [`group-creator-container`](ref:e2e.group-creator-container)):
  3948. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  3949. message has been discarded, abort these steps.
  3950. 2. Let `group` be a snapshot of the current group state.
  3951. 3. If `group.profile-picture` is not defined (i.e. no change), discard the
  3952. message and abort these steps.
  3953. 4. (MD) Run the following sub-steps:
  3954. 1. Begin a transaction with scope `GROUP_SYNC` and the following
  3955. precondition:
  3956. 1. If the group does not exist or the group is marked as _left_, log
  3957. a warning that a group sync race occurred, discard the message
  3958. and abort these steps.
  3959. 2. Let `group` be a snapshot of the current group state.
  3960. 3. If `group.profile-picture` is not defined, log a warning that a
  3961. group sync race occurred.
  3962. 4. Reflect a `GroupSync.Update` with `group` set to contain
  3963. `profile_picture` set to be removed.
  3964. 5. Commit the transaction and await acknowledgement.
  3965. 5. Remove the profile picture of the group.
  3966. contact-request-profile-picture:
  3967. _group: Contact and Group Control
  3968. _doc: |-
  3969. Request a contact's profile picture.
  3970. Note that this message does not result in the profile picture being sent
  3971. immediately in reply to this message. Instead, it will be sent the next
  3972. time that contact sends a message to the user (if one is set, and if the
  3973. user is eligible for receiving the profile picture).
  3974. **Properties**:
  3975. - Kind: 1:1
  3976. - Flags: None
  3977. - User profile distribution: No
  3978. - Exempt from blocking: No
  3979. - Implicit _direct_ contact creation: No
  3980. - Protect against replay: Yes
  3981. - Unarchive: No
  3982. - Bump _last update_: No
  3983. - Reflect:
  3984. - Incoming: Yes
  3985. - Outgoing: No
  3986. - _Sent_ update: No
  3987. - Delivery receipts: No
  3988. - Reactions: No
  3989. - When rejected: N/A (ignored)
  3990. - Edit applies to: N/A
  3991. - Deletable by: N/A
  3992. - Include in history: No
  3993. - Send to Threema Gateway ID group creator: N/A
  3994. When reflected from another device as an incoming message:
  3995. 1. Run the _Common Request Profile Picture Receive Steps_.
  3996. When receiving this message:
  3997. 1. Run the _Common Request Profile Picture Receive Steps_.
  3998. The following steps are defined as the _Common Request Profile Picture
  3999. Receive Steps_:
  4000. 1. Purge the most recently distributed profile picture cache for the
  4001. sender.
  4002. group-setup:
  4003. _group: Contact and Group Control
  4004. _doc: |-
  4005. Announces the group setup to all participants. The group creator is
  4006. always a member of the group and must not be included in the member
  4007. list.
  4008. This is sent by the creator to create a new group, as well as update and
  4009. disband an existing group. The group creator sends this message to all
  4010. current (including those to be removed) and newly added group members.
  4011. The group creator may also send this to a single receiver in special
  4012. cases.
  4013. Since the group creator is not allowed to leave the group, the only way
  4014. for it to stop being a member is by sending a `group-setup` with an
  4015. empty members list and thereby disbanding the group.
  4016. **Properties**:
  4017. - Kind: Group
  4018. - Flags: None
  4019. - User profile distribution: Yes
  4020. - Exempt from blocking: See dedicated steps
  4021. - Implicit _direct_ contact creation: Yes
  4022. - Protect against replay: Yes
  4023. - Unarchive: No¹
  4024. - Bump _last update_: No²
  4025. - Reflect:
  4026. - Incoming: Yes
  4027. - Outgoing: Yes
  4028. - _Sent_ update: No
  4029. - Delivery receipts: N/A
  4030. - Reactions: No
  4031. - When rejected: N/A³
  4032. - Edit applies to: N/A (can just send another `group-setup`)
  4033. - Deletable by: N/A (can just send another `group-setup`)
  4034. - Include in history: Yes
  4035. - Send to Threema Gateway ID group creator: N/A
  4036. ¹: A newly created group's conversation visibility is implicitly _normal_
  4037. and therefore not _archived_. For the sake of simplicity and
  4038. sender/receiver symmetry, further updates to the group should not alter
  4039. the conversation visibility.
  4040. ²: A newly created group is implicitly created with _last update_ set to
  4041. the current timestamp. For the sake of simplicity and sender/receiver
  4042. symmetry, no further updates to the group should bump _last update_.
  4043. ³: For the group creator it will be handled as if `group-sync-request` was
  4044. received, re-sending the group state, implicitly triggered by FS `Reject`
  4045. receive steps.
  4046. The following steps are the dedicated blocking exemption steps for this
  4047. message as a group message (wrapped by
  4048. [`group-creator-container`](ref:e2e.group-creator-container)):
  4049. 1. Look up the group.
  4050. 2. If the group could be found, return that the message passed the
  4051. blocking check.
  4052. 3. Run the _Identity Blocked Steps_ for the creator. If the result
  4053. indicates that the creator is not blocked, return that the message
  4054. passed the blocking check. Otherwise return that the message needs to
  4055. be discarded.
  4056. When receiving this message as a group message (wrapped by
  4057. [`group-creator-container`](ref:e2e.group-creator-container)):
  4058. 1. Let `members` be the given member list. Remove all duplicate entries
  4059. from `members`. Remove the sender (creator) from `members` if present.
  4060. 2. Look up the group.
  4061. 3. If the group could be found:
  4062. 1. Let `group` be a snapshot of the current group state.
  4063. 2. If the group is marked as _left_ and `members` is empty (i.e. no
  4064. change), discard the message and abort these steps.
  4065. 3. If the group is not marked as _left_:
  4066. 1. Let `current-members` be a copy of `group.members`.
  4067. 2. Add the user to `current-members`.
  4068. 3. If `current-members` equals `members` (i.e. no change), discard
  4069. the message and abort these steps.
  4070. 4. If `members` does not include the user:
  4071. 1. If the group could not be found, discard the message and abort these
  4072. steps.
  4073. 2. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  4074. precondition:
  4075. 1. If the group does not exist or the group is marked as _left_,
  4076. discard the message and abort these steps.
  4077. 3. (MD) Reflect a `GroupSync.Update` with `group` set to contain the
  4078. `user_state` set to `KICKED`.
  4079. 4. (MD) Commit the transaction and await acknowledgement.
  4080. 5. If the user is currently participating in a group call of this
  4081. group, trigger leaving the call.
  4082. 6. Mark the group as _left_.
  4083. 7. Persist the previous member setup so that the group can be cloned.
  4084. 8. Run the _Rejected Messages Refresh Steps_ for the group.
  4085. 5. If `members` includes the user.
  4086. 1. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  4087. precondition:
  4088. 1. If the sender (creator) contact does not exist, log an error,
  4089. discard the message and abort these steps.
  4090. 2. Run the _Valid Contacts Lookup Steps_ for `members` and
  4091. overwrite `members` with the result.
  4092. 3. For each `contact-or-init` of `members`:
  4093. 1. If `contact-or-init` indicates that the _contact is the user_,
  4094. remove the entry from `members` and abort these sub-steps.
  4095. 2. If `contact-or-init` indicates that the _contact is invalid_,
  4096. remove the entry from `members`, log a warning and abort these
  4097. sub-steps.
  4098. 4. (MD) Let `pending-reflect-acks` be an empty list.
  4099. 5. For each `contact-or-init` of `members`:
  4100. 1. If `contact-or-init` is an existing contact, abort these
  4101. sub-steps.
  4102. 2. (MD) Reflect a `ContactSync.Create` with `contact` set from
  4103. `contact-or-init` and the following additional properties:
  4104. - `created_at` set to now,
  4105. - `acquaintance_level` set to `GROUP`,
  4106. - all policies and categories set to their defaults.
  4107. 3. (MD) Add the pending reflect acknowledgement to
  4108. `pending-reflect-acks`.
  4109. 6. (MD) Await all `pending-reflect-acks`.
  4110. 7. Let `added-members` be a copy of `members`.
  4111. 8. Let `group` be a snapshot of the current group state or undefined
  4112. if the group does not exist.
  4113. 9. If `group` is not defined:
  4114. 1. Let `removed-members` be an empty list.
  4115. 2. (MD) Reflect a `GroupSync.Create` with `group` set to contain:
  4116. - `group_identity`,
  4117. - `created_at`,
  4118. - `name` empty,
  4119. - `user_state` set to `MEMBER`,
  4120. - `profile_picture` empty,
  4121. - `member_identities` from `members`,
  4122. - all policies and categories set to their defaults.
  4123. 10. If `group` is defined:
  4124. 1. Remove all members from `added-members` that are in
  4125. `group.members`.
  4126. 2. Let `removed-members` be a copy of `group.members`.
  4127. 3. Remove all members from `removed-members` that are in `members`.
  4128. 4. (MD) Reflect a `GroupSync.Update` with `member_state_changes`
  4129. constructed from `added-members` and `removed-members` and
  4130. `group` set to contain the following additional properties:
  4131. - `user_state` set to `MEMBER`,
  4132. - `member_identities` from `members`.
  4133. 11. (MD) Commit the transaction and await acknowledgement.
  4134. 12. If the user is currently participating in a group call of this
  4135. group, remove all `removed-members` participants from the group
  4136. call (handle them as if they left the call) and unblock all pending
  4137. group call flows for `added-members`.
  4138. 13. Persist newly added contacts from `members`.
  4139. 14. Persist the newly created group or the member changes to the group.
  4140. If the group was previously marked as _left_, remove the _left_
  4141. mark.
  4142. 15. TODO(SE-510): Schedule fetching gateway-defined profile picture
  4143. here for each newly added contact from `members`, if necessary.
  4144. 16. If `added-members` or `removed-members` is not empty, run the
  4145. _Rejected Messages Refresh Steps_ for the group.
  4146. fields:
  4147. - _doc: |-
  4148. A set of Threema IDs defining group membership. The creator's
  4149. Threema ID is always inferred and must not be included in this set.
  4150. name: members
  4151. type: *identities
  4152. group-name:
  4153. _group: Contact and Group Control
  4154. _doc: |-
  4155. Name (or rename) a group. Sent to all group members when the group is
  4156. being created for the first time or the group is being renamed. May also
  4157. be sent to a single receiver as a response to a
  4158. [`group-sync-request`](ref:e2e.group-sync-request) message.
  4159. **Properties**:
  4160. - Kind: Group
  4161. - Flags: None
  4162. - User profile distribution: No
  4163. - Exempt from blocking: Yes
  4164. - Implicit _direct_ contact creation: No
  4165. - Protect against replay: Yes
  4166. - Unarchive: No
  4167. - Bump _last update_: No
  4168. - Reflect:
  4169. - Incoming: Yes
  4170. - Outgoing: Yes
  4171. - _Sent_ update: No
  4172. - Delivery receipts: N/A
  4173. - Reactions: No
  4174. - When rejected: N/A¹
  4175. - Edit applies to: N/A (can just send another `group-name`)
  4176. - Deletable by: N/A (can just send an empty name)
  4177. - Include in history: Yes
  4178. - Send to Threema Gateway ID group creator: N/A
  4179. ¹: For the group creator it will be handled as if `group-sync-request` was
  4180. received, re-sending the group name, implicitly triggered by FS `Reject`
  4181. receive steps.
  4182. When receiving this message as a group message (wrapped by
  4183. [`group-creator-container`](ref:e2e.group-creator-container)):
  4184. 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the
  4185. message has been discarded, abort these steps.
  4186. 2. Let `group` be a snapshot of the current group state.
  4187. 3. If `group.name` equals `name` (i.e. no change), discard the message and
  4188. abort these steps.
  4189. 4. (MD) Run the following sub-steps:
  4190. 1. Begin a transaction with scope `GROUP_SYNC` and the following
  4191. precondition:
  4192. 1. If the group does not exist or the group is marked as _left_, log
  4193. a warning that a group sync race occurred, discard the message
  4194. and abort these steps.
  4195. 2. Let `group` be a snapshot of the current group state.
  4196. 3. If `group.name` equals `name`, log a warning that a group sync race
  4197. occurred.
  4198. 4. Reflect a `GroupSync.Update` with `group` set to contain
  4199. `name` set to `name`.
  4200. 5. Commit the transaction and await acknowledgement.
  4201. 5. Update the group's name with `name`.
  4202. fields:
  4203. - _doc: |-
  4204. UTF-8 encoded string containing the group's name.
  4205. name: name
  4206. type: b*
  4207. group-leave:
  4208. _group: Contact and Group Control
  4209. _doc: |-
  4210. Sent by a group member...
  4211. * that is leaving the group. The message is sent to all other group
  4212. members and the creator.
  4213. * in direct reply to a group message for a group that it has marked as
  4214. left.
  4215. Note: The group creator is not allowed to leave the group.
  4216. **Properties**:
  4217. - Kind: Group
  4218. - Flags: None
  4219. - User profile distribution: No
  4220. - Exempt from blocking: Yes
  4221. - Implicit _direct_ contact creation: No
  4222. - Protect against replay: Yes
  4223. - Unarchive: No
  4224. - Bump _last update_: No
  4225. - Reflect:
  4226. - Incoming: Yes
  4227. - Outgoing: Yes
  4228. - _Sent_ update: No
  4229. - Delivery receipts: N/A
  4230. - Reactions: No
  4231. - When rejected: N/A¹
  4232. - Edit applies to: N/A
  4233. - Deletable by: N/A
  4234. - Include in history: Yes
  4235. - Send to Threema Gateway ID group creator: Yes
  4236. ¹: Re-send of `group-leave` implicitly triggered by FS `Reject` receive
  4237. steps due to _Common Group Receive Steps_ invocation.
  4238. When receiving this message as a group message (wrapped by
  4239. [`group-member-container`](ref:e2e.group-member-container)):
  4240. 1. If the sender is the creator of the group, log a warning, discard the
  4241. message and abort these steps.
  4242. 2. Look up the group.
  4243. 3. If the group could not be found or is marked as _left_:
  4244. 1. If the user is the creator of the group (as alleged by the
  4245. message), discard the message and abort these steps.
  4246. 2. Run the _Identity Blocked Steps_ for the creator of the group. If
  4247. the result indicates that the creator is blocked, discard the
  4248. message and abort these steps.
  4249. 3. Run the _Group Sync Request Steps_ for the group, discard the
  4250. message and abort these steps.
  4251. 4. Let `group` be a snapshot of the current group state.
  4252. 5. If `group.members` does not include the sender, discard the message and
  4253. abort these steps.
  4254. 6. (MD) Run the following sub-steps:
  4255. 1. Begin a transaction with scope `GROUP_SYNC` and the following
  4256. precondition:
  4257. 1. If the group does not exist or the group is marked as _left_, log
  4258. a warning that a group sync race occurred, discard the message
  4259. and abort these steps.
  4260. 2. Let `group` be a snapshot of the current group state.
  4261. 3. If `group.members` does not include the sender, log a warning that a
  4262. group sync race occurred.
  4263. 4. Let `updated-members` be a copy of `group.members`.
  4264. 5. Remove the sender from `updated-members`.
  4265. 6. Reflect a `GroupSync.Update` with `member_state_changes`
  4266. set to the single entry of the sender leaving and `group` set to
  4267. contain `member_identities` set from `updated-members`.
  4268. 7. Commit the transaction and await acknowledgement.
  4269. 7. If the user is currently participating in a group call of this group,
  4270. remove the sender from the group call (handle it as if the sender left
  4271. the call).
  4272. 8. Remove the sender from the group.
  4273. 9. Run the _Rejected Messages Refresh Steps_ for the group.
  4274. group-sync-request:
  4275. _group: Contact and Group Control
  4276. _doc: |-
  4277. Sent by a group member (or a device assuming to be part of the group) to
  4278. the group creator.
  4279. **Properties**:
  4280. - Kind: Group
  4281. - Flags: None
  4282. - User profile distribution: No
  4283. - Exempt from blocking: Yes
  4284. - Implicit _direct_ contact creation: No
  4285. - Protect against replay: Yes
  4286. - Unarchive: No
  4287. - Bump _last update_: No
  4288. - Reflect:
  4289. - Incoming: Yes
  4290. - Outgoing: Yes
  4291. - _Sent_ update: No
  4292. - Delivery receipts: N/A
  4293. - Reactions: No
  4294. - When rejected: N/A¹
  4295. - Edit applies to: N/A
  4296. - Deletable by: N/A
  4297. - Include in history: Yes
  4298. - Send to Threema Gateway ID group creator: Yes
  4299. ¹: Implicitly ignored by FS `Reject` receive steps.
  4300. The following steps are defined as the _Group Sync Request Steps_:
  4301. 1. If the user is the creator of the group, log an error and abort these
  4302. steps.
  4303. 2. If the group is marked as _recently resynced_ for the user, log a
  4304. notice and abort these steps.¹
  4305. 3. Run the _Bundled Messages Send Steps_ with the following properties:
  4306. - `id` set to a random message ID,
  4307. - `created-at` set to the current timestamp,
  4308. - `receivers` set to the creator of the group,
  4309. - to construct this message (wrapped by
  4310. [`group-member-container`](ref:e2e.group-member-container))
  4311. 4. Mark the group as _recently resynced_ for the user for 1h.
  4312. When receiving this message as a group message (wrapped by
  4313. [`group-member-container`](ref:e2e.group-member-container)):
  4314. 1. Look up the group. If the group could not be found, discard the message
  4315. and abort these steps.
  4316. 2. If the user is not the creator of the group, discard the message and
  4317. abort these steps.
  4318. 3. If the group is marked as _recently resynced_ for the sender, log a
  4319. notice, discard the message and abort these steps.¹
  4320. 4. (MD) Begin a transaction with scope `GROUP_SYNC` and the following
  4321. precondition:
  4322. 1. If the group does not exist, log a warning that a group sync race
  4323. occurred, discard the message and abort these steps.
  4324. 5. If the group is marked as _left_ or the sender is not a member of the
  4325. group, run the _Bundled Messages Send Steps_ with the following
  4326. properties:
  4327. - `id` set to a random message ID,
  4328. - `created-at` set to the current timestamp,
  4329. - `receivers` set to the sender,
  4330. - to construct a [`group-setup`](ref:e2e.group-setup) (wrapped by
  4331. [`group-creator-container`](ref:e2e.group-creator-container)) with an
  4332. empty members set.
  4333. 6. If the group is not marked as _left_ and the sender is a member of the
  4334. group, run the _Active Group State Resync Steps_ with four random message
  4335. IDs and `target-members` set to the sender.
  4336. 7. (MD) Commit the transaction and await acknowledgement.
  4337. ¹: This is a precaution since a `group-sync-request` is automatically
  4338. triggered and creates an automatic response. This can easily lead to
  4339. message loops. Limiting `group-sync-request`s to once an hour per group
  4340. per sender/receiver breaks a potential infinite loop.
  4341. web-session-resume:
  4342. _group: Push Control
  4343. _doc: |-
  4344. A control message from Threema Web, requesting a session to be resumed.
  4345. **Properties (1:1)**:
  4346. - Kind: 1:1
  4347. - Flags:
  4348. - `0x20`: Short-lived server queuing.
  4349. - User profile distribution: N/A (not sent by apps)
  4350. - Exempt from blocking: Yes
  4351. - Implicit _direct_ contact creation: N/A (blocking is circumvented)
  4352. - Protect against replay: Yes
  4353. - Unarchive: No
  4354. - Bump _last update_: No
  4355. - Reflect:
  4356. - Incoming: No
  4357. - Outgoing: No
  4358. - _Sent_ update: No
  4359. - Delivery receipts: N/A
  4360. - Reactions: N/A
  4361. - When rejected: N/A (not sent by clients)
  4362. - Edit applies to: N/A
  4363. - Deletable by: N/A
  4364. - Include in history: No
  4365. - Send to Threema Gateway ID group creator: N/A
  4366. When receiving this message:
  4367. 1. If the sender is not `*3MAPUSH`, discard the message and abort these
  4368. steps.
  4369. 2. Lookup the web client session associated to `wcs` and attempt to resume
  4370. it.
  4371. fields:
  4372. - _doc: |-
  4373. UTF-8, JSON-encoded object with the following fields:
  4374. - Webclient session (`'wcs'`): SHA256 hash (hex encoded) of the
  4375. public permanent key of the session initiator, string.
  4376. - Affiliation ID (`'wca'`): An optional identifier for affiliating
  4377. consecutive pushes, `string` or `null`.
  4378. - Affiliation ID (`'wct'`): Unix epoch timestamp of the request in
  4379. seconds, `i64`.
  4380. - Protocol version (`'wcv'`): Version of the Threema Web protocol,
  4381. `u16`.
  4382. All fields must be part of the JSON object, even if their values are
  4383. nullable.
  4384. name: push-payload
  4385. type: b*
  4386. # Parsed struct namespaces (mapped into separate files)
  4387. namespaces:
  4388. index: *index
  4389. handshake: *handshake
  4390. payload: *payload
  4391. e2e: *e2e