csp.struct.yml 216 KB

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