Page Not Found
We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
diff --git a/.gitignore b/.gitignore index 7380d5f5..85a001c9 100644 --- a/.gitignore +++ b/.gitignore @@ -25,5 +25,5 @@ yarn-error.log* .pnp.loader.mjs yarn.lock -build-staging/ +#build-staging/ staging/ diff --git a/build-staging/404.html b/build-staging/404.html new file mode 100644 index 00000000..2e788748 --- /dev/null +++ b/build-staging/404.html @@ -0,0 +1,24 @@ + + +
+ + +We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
["'])(?.*?)\1/,h=/\{(? [\d,-]+)\}/,y={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}};function b(e,t){const n=e.map((e=>{const{start:n,end:o}=y[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${o})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function v(e,t){let n=e.replace(/\n$/,"");const{language:o,magicComments:a,metastring:r}=t;if(r&&h.test(r)){const e=r.match(h).groups.range;if(0===a.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${r}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=a[0].className,o=f()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(o),code:n}}if(void 0===o)return{lineClassNames:{},code:n};const c=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return b(["js","jsBlock"],t);case"jsx":case"tsx":return b(["js","jsBlock","jsx"],t);case"html":return b(["js","jsBlock","html"],t);case"python":case"py":case"bash":return b(["bash"],t);case"markdown":case"md":return b(["html","jsx","bash"],t);default:return b(Object.keys(y),t)}}(o,a),l=n.split("\n"),i=Object.fromEntries(a.map((e=>[e.className,{start:0,range:""}]))),s=Object.fromEntries(a.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),u=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),m=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let p=0;p void 0!==e));s[t]?i[s[t]].range+=`${p},`:u[t]?i[u[t]].start=p:m[t]&&(i[m[t]].range+=`${i[m[t]].start}-${p-1},`),l.splice(p,1)}n=l.join("\n");const d={};return Object.entries(i).forEach((e=>{let[t,{range:n}]=e;f()(n).forEach((e=>{d[e]??=[],d[e].push(t)}))})),{lineClassNames:d,code:n}}const E={codeBlockContainer:"codeBlockContainer_Ckt0"};function k(e){let{as:t,...n}=e;const a=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[o,a]=e;const r=t[o];r&&"string"==typeof a&&(n[r]=a)})),n}(m());return o.createElement(t,(0,r.Z)({},n,{style:a,className:(0,i.Z)(n.className,E.codeBlockContainer,d.k.common.codeBlock)}))}const N={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function C(e){let{children:t,className:n}=e;return o.createElement(k,{as:"pre",tabIndex:0,className:(0,i.Z)(N.codeBlockStandalone,"thin-scrollbar",n)},o.createElement("code",{className:N.codeBlockLines},t))}var w=n(902);const B={attributes:!0,characterData:!0,childList:!0,subtree:!0};function Z(e,t){const[n,a]=(0,o.useState)(),r=(0,o.useCallback)((()=>{a(e.current?.closest("[role=tabpanel][hidden]"))}),[e,a]);(0,o.useEffect)((()=>{r()}),[r]),function(e,t,n){void 0===n&&(n=B);const a=(0,w.zX)(t),r=(0,w.Ql)(n);(0,o.useEffect)((()=>{const t=new MutationObserver(a);return e&&t.observe(e,r),()=>t.disconnect()}),[e,a,r])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),r())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}const T={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]};var L={Prism:n(7410).Z,theme:T};function j(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function _(){return _=Object.assign||function(e){for(var t=1;t 0&&e[n-1]===t?e:e.concat(t)};function P(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&-1===t.indexOf(o)&&(n[o]=e[o]);return n}var z=function(e){function t(){for(var t=this,n=[],o=arguments.length;o--;)n[o]=arguments[o];e.apply(this,n),j(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?function(e,t){var n=e.plain,o=Object.create(null),a=e.styles.reduce((function(e,n){var o=n.languages,a=n.style;return o&&!o.includes(t)||n.types.forEach((function(t){var n=_({},e[t],a);e[t]=n})),e}),o);return a.root=n,a.plain=_({},n,{backgroundColor:null}),a}(e.theme,e.language):void 0;return t.themeDict=n})),j(this,"getLineProps",(function(e){var n=e.key,o=e.className,a=e.style,r=_({},P(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),c=t.getThemeDict(t.props);return void 0!==c&&(r.style=c.plain),void 0!==a&&(r.style=void 0!==r.style?_({},r.style,a):a),void 0!==n&&(r.key=n),o&&(r.className+=" "+o),r})),j(this,"getStyleForToken",(function(e){var n=e.types,o=e.empty,a=n.length,r=t.getThemeDict(t.props);if(void 0!==r){if(1===a&&"plain"===n[0])return o?{display:"inline-block"}:void 0;if(1===a&&!o)return r[n[0]];var c=o?{display:"inline-block"}:{},l=n.map((function(e){return r[e]}));return Object.assign.apply(Object,[c].concat(l))}})),j(this,"getTokenProps",(function(e){var n=e.key,o=e.className,a=e.style,r=e.token,c=_({},P(e,["key","className","style","token"]),{className:"token "+r.types.join(" "),children:r.content,style:t.getStyleForToken(r),key:void 0});return void 0!==a&&(c.style=void 0!==c.style?_({},c.style,a):a),void 0!==n&&(c.key=n),o&&(c.className+=" "+o),c})),j(this,"tokenize",(function(e,t,n,o){var a={code:t,grammar:n,language:o,tokens:[]};e.hooks.run("before-tokenize",a);var r=a.tokens=e.tokenize(a.code,a.grammar,a.language);return e.hooks.run("after-tokenize",a),r}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,o=e.code,a=e.children,r=this.getThemeDict(this.props),c=t.languages[n];return a({tokens:function(e){for(var t=[[]],n=[e],o=[0],a=[e.length],r=0,c=0,l=[],i=[l];c>-1;){for(;(r=o[c]++)0?u:["plain"],s=m):(u=S(u,m.type),m.alias&&(u=S(u,m.alias)),s=m.content),"string"==typeof s){var d=s.split(x),p=d.length;l.push({types:u,content:d[0]});for(var f=1;f o.createElement("span",(0,r.Z)({key:t},l({token:e,key:t})))));return o.createElement("span",s,a?o.createElement(o.Fragment,null,o.createElement("span",{className:I.codeLineNumber}),o.createElement("span",{className:I.codeLineContent},u)):u,o.createElement("br",null))}var M=n(5999);function H(e){return o.createElement("svg",(0,r.Z)({viewBox:"0 0 24 24"},e),o.createElement("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"}))}function D(e){return o.createElement("svg",(0,r.Z)({viewBox:"0 0 24 24"},e),o.createElement("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))}const V={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function R(e){let{code:t,className:n}=e;const[a,r]=(0,o.useState)(!1),c=(0,o.useRef)(void 0),l=(0,o.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const o=document.createElement("textarea"),a=document.activeElement;o.value=e,o.setAttribute("readonly",""),o.style.contain="strict",o.style.position="absolute",o.style.left="-9999px",o.style.fontSize="12pt";const r=document.getSelection(),c=r.rangeCount>0&&r.getRangeAt(0);n.append(o),o.select(),o.selectionStart=0,o.selectionEnd=e.length;let l=!1;try{l=document.execCommand("copy")}catch{}o.remove(),c&&(r.removeAllRanges(),r.addRange(c)),a&&a.focus()}(t),r(!0),c.current=window.setTimeout((()=>{r(!1)}),1e3)}),[t]);return(0,o.useEffect)((()=>()=>window.clearTimeout(c.current)),[]),o.createElement("button",{type:"button","aria-label":a?(0,M.I)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,M.I)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,M.I)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,i.Z)("clean-btn",n,V.copyButton,a&&V.copyButtonCopied),onClick:l},o.createElement("span",{className:V.copyButtonIcons,"aria-hidden":"true"},o.createElement(H,{className:V.copyButtonIcon}),o.createElement(D,{className:V.copyButtonSuccessIcon})))}function $(e){return o.createElement("svg",(0,r.Z)({viewBox:"0 0 24 24"},e),o.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"}))}const F={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function q(e){let{className:t,onClick:n,isEnabled:a}=e;const r=(0,M.I)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return o.createElement("button",{type:"button",onClick:n,className:(0,i.Z)("clean-btn",t,a&&F.wordWrapButtonEnabled),"aria-label":r,title:r},o.createElement($,{className:F.wordWrapButtonIcon,"aria-hidden":"true"}))}function G(e){let{children:t,className:n="",metastring:a,title:c,showLineNumbers:l,language:s}=e;const{prism:{defaultLanguage:d,magicComments:p}}=(0,u.L)(),f=s??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??d,h=m(),y=function(){const[e,t]=(0,o.useState)(!1),[n,a]=(0,o.useState)(!1),r=(0,o.useRef)(null),c=(0,o.useCallback)((()=>{const n=r.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[r,e]),l=(0,o.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=r.current,n=e>t||r.current.querySelector("code").hasAttribute("style");a(n)}),[r]);return Z(r,l),(0,o.useEffect)((()=>{l()}),[e,l]),(0,o.useEffect)((()=>(window.addEventListener("resize",l,{passive:!0}),()=>{window.removeEventListener("resize",l)})),[l]),{codeBlockRef:r,isEnabled:e,isCodeScrollable:n,toggle:c}}(),b=function(e){return e?.match(g)?.groups.title??""}(a)||c,{lineClassNames:E,code:C}=v(t,{metastring:a,language:f,magicComments:p}),w=l??function(e){return Boolean(e?.includes("showLineNumbers"))}(a);return o.createElement(k,{as:"div",className:(0,i.Z)(n,f&&!n.includes(`language-${f}`)&&`language-${f}`)},b&&o.createElement("div",{className:N.codeBlockTitle},b),o.createElement("div",{className:N.codeBlockContent},o.createElement(A,(0,r.Z)({},L,{theme:h,code:C,language:f??"text"}),(e=>{let{className:t,tokens:n,getLineProps:a,getTokenProps:r}=e;return o.createElement("pre",{tabIndex:0,ref:y.codeBlockRef,className:(0,i.Z)(t,N.codeBlock,"thin-scrollbar")},o.createElement("code",{className:(0,i.Z)(N.codeBlockLines,w&&N.codeBlockLinesWithNumbering)},n.map(((e,t)=>o.createElement(W,{key:t,line:e,getLineProps:a,getTokenProps:r,classNames:E[t],showLineNumbers:w})))))})),o.createElement("div",{className:N.buttonGroup},(y.isEnabled||y.isCodeScrollable)&&o.createElement(q,{className:N.codeButton,onClick:()=>y.toggle(),isEnabled:y.isEnabled}),o.createElement(R,{className:N.codeButton,code:C}))))}function U(e){let{children:t,...n}=e;const a=(0,l.Z)(),c=function(e){return o.Children.toArray(e).some((e=>(0,o.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),i="string"==typeof c?G:C;return o.createElement(i,(0,r.Z)({key:String(a)},n),c)}var Q=n(9960);var X=n(6043);const Y={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function J(e){return!!e&&("SUMMARY"===e.tagName||J(e.parentElement))}function K(e,t){return!!e&&(e===t||K(e.parentElement,t))}function ee(e){let{summary:t,children:n,...a}=e;const c=(0,l.Z)(),s=(0,o.useRef)(null),{collapsed:u,setCollapsed:m}=(0,X.u)({initialState:!a.open}),[d,p]=(0,o.useState)(a.open),f=o.isValidElement(t)?t:o.createElement("summary",null,t??"Details");return o.createElement("details",(0,r.Z)({},a,{ref:s,open:d,"data-collapsed":u,className:(0,i.Z)(Y.details,c&&Y.isBrowser,a.className),onMouseDown:e=>{J(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;J(t)&&K(t,s.current)&&(e.preventDefault(),u?(m(!1),p(!0)):m(!0))}}),f,o.createElement(X.z,{lazy:!1,collapsed:u,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{m(e),p(!e)}},o.createElement("div",{className:Y.collapsibleContent},n)))}const te={details:"details_b_Ee"},ne="alert alert--info";function oe(e){let{...t}=e;return o.createElement(ee,(0,r.Z)({},t,{className:(0,i.Z)(ne,te.details,t.className)}))}var ae=n(2503);function re(e){return o.createElement(ae.Z,e)}const ce={containsTaskList:"containsTaskList_mC6p"};const le={img:"img_ev3q"};const ie="admonition_LlT9",se="admonitionHeading_tbUL",ue="admonitionIcon_kALy",me="admonitionContent_S0QG";const de={note:{infimaClassName:"secondary",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:o.createElement(M.Z,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:o.createElement(M.Z,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:o.createElement(M.Z,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:o.createElement(M.Z,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 16 16"},o.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:o.createElement(M.Z,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},pe={secondary:"note",important:"info",success:"tip",warning:"danger"};function fe(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=o.Children.toArray(e),n=t.find((e=>o.isValidElement(e)&&"mdxAdmonitionTitle"===e.props?.mdxType)),a=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return{mdxAdmonitionTitle:n,rest:a}}(e.children);return{...e,title:e.title??t,children:n}}const ge={head:function(e){const t=o.Children.map(e.children,(e=>o.isValidElement(e)?function(e){if(e.props?.mdxType&&e.props.originalType){const{mdxType:t,originalType:n,...a}=e.props;return o.createElement(e.props.originalType,a)}return e}(e):e));return o.createElement(c.Z,e,t)},code:function(e){const t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return o.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")||(0,o.isValidElement)(e)&&t.includes(e.props?.mdxType)))?o.createElement("code",e):o.createElement(U,e)},a:function(e){return o.createElement(Q.Z,e)},pre:function(e){return o.createElement(U,(0,o.isValidElement)(e.children)&&"code"===e.children.props?.originalType?e.children.props:{...e})},details:function(e){const t=o.Children.toArray(e.children),n=t.find((e=>o.isValidElement(e)&&"summary"===e.props?.mdxType)),a=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return o.createElement(oe,(0,r.Z)({},e,{summary:n}),a)},ul:function(e){return o.createElement("ul",(0,r.Z)({},e,{className:(t=e.className,(0,i.Z)(t,t?.includes("contains-task-list")&&ce.containsTaskList))}));var t},img:function(e){return o.createElement("img",(0,r.Z)({loading:"lazy"},e,{className:(t=e.className,(0,i.Z)(t,le.img))}));var t},h1:e=>o.createElement(re,(0,r.Z)({as:"h1"},e)),h2:e=>o.createElement(re,(0,r.Z)({as:"h2"},e)),h3:e=>o.createElement(re,(0,r.Z)({as:"h3"},e)),h4:e=>o.createElement(re,(0,r.Z)({as:"h4"},e)),h5:e=>o.createElement(re,(0,r.Z)({as:"h5"},e)),h6:e=>o.createElement(re,(0,r.Z)({as:"h6"},e)),admonition:function(e){const{children:t,type:n,title:a,icon:r}=fe(e),c=function(e){const t=pe[e]??e,n=de[t];return n||(console.warn(`No admonition config found for admonition type "${t}". Using Info as fallback.`),de.info)}(n),l=a??c.label,{iconComponent:s}=c,u=r??o.createElement(s,null);return o.createElement("div",{className:(0,i.Z)(d.k.common.admonition,d.k.common.admonitionType(e.type),"alert",`alert--${c.infimaClassName}`,ie)},o.createElement("div",{className:se},o.createElement("span",{className:ue},u),l),o.createElement("div",{className:me},t))},mermaid:n(1875).Z};function he(e){let{children:t}=e;return o.createElement(a.Zo,{components:ge},t)}},2244:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c});var o=n(7294),a=n(6010),r=n(9960);function c(e){const{permalink:t,title:n,subLabel:c,isNext:l}=e;return o.createElement(r.Z,{className:(0,a.Z)("pagination-nav__link",l?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},c&&o.createElement("div",{className:"pagination-nav__sublabel"},c),o.createElement("div",{className:"pagination-nav__label"},n))}},3008:(e,t,n)=>{"use strict";n.d(t,{Z:()=>l});var o=n(7294),a=n(6010),r=n(9960);const c={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function l(e){let{permalink:t,label:n,count:l}=e;return o.createElement(r.Z,{href:t,className:(0,a.Z)(c.tag,l?c.tagWithCount:c.tagRegular)},n,l&&o.createElement("span",null,l))}},1526:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var o=n(7294),a=n(6010),r=n(5999),c=n(3008);const l={tags:"tags_jXut",tag:"tag_QGVx"};function i(e){let{tags:t}=e;return o.createElement(o.Fragment,null,o.createElement("b",null,o.createElement(r.Z,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),o.createElement("ul",{className:(0,a.Z)(l.tags,"padding--none","margin-left--sm")},t.map((e=>{let{label:t,permalink:n}=e;return o.createElement("li",{key:n,className:l.tag},o.createElement(c.Z,{label:t,permalink:n}))}))))}},7594:(e,t)=>{function n(e){let t,n=[];for(let o of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(o))n.push(parseInt(o,10));else if(t=o.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,o,a,r]=t;if(o&&r){o=parseInt(o),r=parseInt(r);const e=o
{a.exports=JSON.parse('{"label":"nightly","permalink":"/blog/tags/nightly","allTagsPath":"/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/986bf1b5.1e9911cc.js b/build-staging/assets/js/986bf1b5.1e9911cc.js new file mode 100644 index 00000000..408076cb --- /dev/null +++ b/build-staging/assets/js/986bf1b5.1e9911cc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[3625],{8327:e=>{e.exports=JSON.parse('{"title":"Profiles","slug":"/category/profiles","permalink":"/docs/category/profiles","navigation":{"previous":{"title":"Supported Platforms","permalink":"/docs/getting-started/supported_platforms"},"next":{"title":"An Introduction to Cwtch Profiles","permalink":"/docs/profiles/introduction"}}}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/98da7451.9df2feb9.js b/build-staging/assets/js/98da7451.9df2feb9.js new file mode 100644 index 00000000..5637cb9a --- /dev/null +++ b/build-staging/assets/js/98da7451.9df2feb9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[8141],{8777:e=>{e.exports=JSON.parse('{"title":"Settings","slug":"/category/settings","permalink":"/docs/category/settings","navigation":{"previous":{"title":"How to Unlock a server","permalink":"/docs/servers/unlock-server"},"next":{"title":"An Introduction to Cwtch App Settings","permalink":"/docs/settings/introduction"}}}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/992a3bb7.e91a6bcf.js b/build-staging/assets/js/992a3bb7.e91a6bcf.js new file mode 100644 index 00000000..d0aa1b78 --- /dev/null +++ b/build-staging/assets/js/992a3bb7.e91a6bcf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1415],{8229:e=>{e.exports=JSON.parse('{"permalink":"/blog/tags/documentation","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/9b12a270.bb5deec9.js b/build-staging/assets/js/9b12a270.bb5deec9.js new file mode 100644 index 00000000..b782fde3 --- /dev/null +++ b/build-staging/assets/js/9b12a270.bb5deec9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[9249],{3905:(e,t,i)=>{i.d(t,{Zo:()=>d,kt:()=>g});var r=i(7294);function n(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function a(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,r)}return i}function o(e){for(var t=1;t =0||(n[i]=e[i]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r =0||Object.prototype.propertyIsEnumerable.call(e,i)&&(n[i]=e[i])}return n}var s=r.createContext({}),l=function(e){var t=r.useContext(s),i=t;return e&&(i="function"==typeof e?e(t):o(o({},t),e)),i},d=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var i=e.components,n=e.mdxType,a=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),p=l(i),h=n,g=p["".concat(s,".").concat(h)]||p[h]||u[h]||a;return i?r.createElement(g,o(o({ref:t},d),{},{components:i})):r.createElement(g,o({ref:t},d))}));function g(e,t){var i=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=i.length,o=new Array(a);o[0]=h;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:n,o[1]=c;for(var l=2;l{i.r(t),i.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var r=i(7462),n=(i(7294),i(3905));const a={title:"Making Cwtch Android Bindings Reproducible",description:"In this devlog we revisit reproducible builds and make Cwtch Android bindings reproducible",slug:"cwtch-android-reproducibility",tags:["cwtch","cwtch-stable","reproducible-builds","bindings","repliqate"],image:"/img/devlog6_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},o=void 0,c={permalink:"/blog/cwtch-android-reproducibility",source:"@site/blog/2023-02-10-android-reproducibility.md",title:"Making Cwtch Android Bindings Reproducible",description:"In this devlog we revisit reproducible builds and make Cwtch Android bindings reproducible",date:"2023-02-10T00:00:00.000Z",formattedDate:"February 10, 2023",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"cwtch-stable",permalink:"/blog/tags/cwtch-stable"},{label:"reproducible-builds",permalink:"/blog/tags/reproducible-builds"},{label:"bindings",permalink:"/blog/tags/bindings"},{label:"repliqate",permalink:"/blog/tags/repliqate"}],readingTime:2.92,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Making Cwtch Android Bindings Reproducible",description:"In this devlog we revisit reproducible builds and make Cwtch Android bindings reproducible",slug:"cwtch-android-reproducibility",tags:["cwtch","cwtch-stable","reproducible-builds","bindings","repliqate"],image:"/img/devlog6_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},prevItem:{title:"Notes on Cwtch UI Testing (II)",permalink:"/blog/cwtch-testing-ii"},nextItem:{title:"Notes on Cwtch UI Testing",permalink:"/blog/cwtch-testing-i"}},s={authorsImageUrls:[void 0]},l=[{value:"Changes Necessary for Reproducible Android Bindings",id:"changes-necessary-for-reproducible-android-bindings",level:2},{value:"Repliqate Scripts",id:"repliqate-scripts",level:2},{value:"Help us go further!",id:"help-us-go-further",level:2}],d={toc:l},p="wrapper";function u(e){let{components:t,...a}=e;return(0,n.kt)(p,(0,r.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"In this development log, we continue our previous work on ",(0,n.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/blog/cwtch-bindings-reproducible"},"reproducible Cwtch bindings"),", uncovering the final few sources of variation between our ",(0,n.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/openprivacy/repliqate"},"Repliqate")," scripts and our docker/drone builds, leading to fully reproducible builds for Cwtch Android bindings!"),(0,n.kt)("p",null,(0,n.kt)("img",{src:i(4756).Z,width:"1005",height:"481"})),(0,n.kt)("h2",{id:"changes-necessary-for-reproducible-android-bindings"},"Changes Necessary for Reproducible Android Bindings"),(0,n.kt)("p",null,"After a thorough investigation of the build artifacts produced by Repliqate and Drone we uncovered three additional sources of variation:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Insufficient path stripping introduced by Android NDK tools")," - it turns out that Android builds using NDK versions below 22 are not reproducible as they produce randomized artifacts (through unstripped temporary directory paths appearing in compiled binares). NDK 22 ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/android/ndk/wiki/Changelog-r22"},"changed the binutils and default linker")," to versions that correctly strip such paths from build artifacts. As such it was necessary for us to update the NDK version we used. We chose the technically outdated NDK 22 rather than the more modern NDK 25 to minimize Android OS compatibility changes during this switch. However, per our ",(0,n.kt)("a",{parentName:"li",href:"https://docs.cwtch.im/blog/cwtch-platform-support"},"long term support plan"),", we will be moving towards adopting the latest NDK in the future."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Paths in DWARF entries")," - while we have been unable to track down exactly where these are being introduced, we did track the final difference in the produced bindings to DWARF debug lines embedded in compiled ELF binaries. These entries encoded the actual location of the NDK on the disk of the build machine, instead of the symbolic link that we believed should have been followed. By physically placing the NDK at same location in repliqate as in our Docker container we were able to get these entries to be consistent - however there is still work to do to understand exactly why they are being introduced at all.")),(0,n.kt)("figure",null,(0,n.kt)("p",null,(0,n.kt)("a",{target:"_blank",href:i(4560).Z},(0,n.kt)("img",{src:i(9842).Z,width:"1863",height:"428"}))),(0,n.kt)("figcaption",null,"Vimdiff comparing the decoded (",(0,n.kt)("code",null,"readelf --debug-dump=line"),") DWARF debug section of Drone-produced Android bindings v.s. Repliqate-produced. The difference in paths is highlighted.")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Go Compiler Acquisition")," - our Docker container was compiling the Go compiler from source, while Repliqate was downloading a pre-compiled version. During debugging we changed the Dockerfile to also download the pre-compiled version in order to eliminate the difference as a potential reproducibility issue. Our tests indicated that there ",(0,n.kt)("em",{parentName:"li"},"was")," a difference between artifacts produced by the precompiled compiler v.s. one built from source - this is likely explained by introduced environmental differences caused by the compilation of the compiler itself e.g. the contents/versions of modules in the Go package cache which we have seen as having an impact on other produced binaries.")),(0,n.kt)("h2",{id:"repliqate-scripts"},"Repliqate Scripts"),(0,n.kt)("p",null,"With those issues now fixed, Cwtch Android bindings are ",(0,n.kt)("strong",{parentName:"p"},"officially reproducible!")," The first version that officially met this requirement was 1.10.5, and you can find the Repliqate script under ",(0,n.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-bindings-v1.10.5/libcwtch.v1.10.5-android.script"},"cwtch-bindings-v1.10.5/libcwtch.v1.10.5-android.script")," in the ",(0,n.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/cwtch.im/repliqate-scripts/"},"Cwtch Repliqate scripts repository"),"."),(0,n.kt)("p",null,"This is another big milestone towards our ultimate goal of full reproducibility for Cwtch releases."),(0,n.kt)("h2",{id:"help-us-go-further"},"Help us go further!"),(0,n.kt)("p",null,"We couldn't do what we do without all the wonderful community support we get, from ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," to ",(0,n.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,n.kt)("p",null,"If you want to see us move faster on some of these goals and are in a position to, please ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"donate"),". If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer."),(0,n.kt)("p",null,"Donations of ",(0,n.kt)("strong",{parentName:"p"},"$5 or more")," can opt to receive stickers as a thank-you gift!"),(0,n.kt)("p",null,"For more information about donating to Open Privacy and claiming a thank you gift ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate/"},"please visit the Open Privacy Donate page"),"."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"A Photo of Cwtch Stickers",src:i(4515).Z,width:"1024",height:"768"})))}u.isMDXComponent=!0},4560:(e,t,i)=>{i.d(t,{Z:()=>r});const r=i.p+"assets/files/aar-diff-cefdff70043215f9b9244cbc0a179078.png"},9842:(e,t,i)=>{i.d(t,{Z:()=>r});const r=i.p+"assets/images/aar-diff-cefdff70043215f9b9244cbc0a179078.png"},4756:(e,t,i)=>{i.d(t,{Z:()=>r});const r=i.p+"assets/images/devlog6-047cb55e43376529b3899ac2a0792f9c.png"},4515:(e,t,i)=>{i.d(t,{Z:()=>r});const r=i.p+"assets/images/stickers-new-1e9b14bdd638b4907cce833e813a09ad.jpg"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/9bb37799.506f4b14.js b/build-staging/assets/js/9bb37799.506f4b14.js new file mode 100644 index 00000000..b42e3d83 --- /dev/null +++ b/build-staging/assets/js/9bb37799.506f4b14.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[9767],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t =0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),p=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},l=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),h=p(r),m=o,d=h["".concat(c,".").concat(m)]||h[m]||u[m]||a;return r?n.createElement(d,i(i({ref:t},l),{},{components:r})):n.createElement(d,i({ref:t},l))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[h]="string"==typeof e?e:o,i[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const a={sidebar_position:1},i="Cwtch Technical Basics",s={unversionedId:"components/intro",id:"components/intro",title:"Cwtch Technical Basics",description:"This page presents a brief technical overview of the Cwtch protocol.",source:"@site/security/components/intro.md",sourceDirName:"components",slug:"/components/intro",permalink:"/security/components/intro",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Cwtch Components",permalink:"/security/category/cwtch-components"},next:{title:"Component Ecosystem Overview",permalink:"/security/components/ecosystem-overview"}},c={},p=[{value:"A Cwtch Profile",id:"a-cwtch-profile",level:2},{value:"2-party conversions: Peer to Peer",id:"2-party-conversions-peer-to-peer",level:2},{value:"Multi-party conversations: Groups and Peer to Server Communication",id:"multi-party-conversations-groups-and-peer-to-server-communication",level:2},{value:"Servers are Peers",id:"servers-are-peers",level:3}],l={toc:p},h="wrapper";function u(e){let{components:t,...a}=e;return(0,o.kt)(h,(0,n.Z)({},l,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"cwtch-technical-basics"},"Cwtch Technical Basics"),(0,o.kt)("p",null,"This page presents a brief technical overview of the Cwtch protocol."),(0,o.kt)("h2",{id:"a-cwtch-profile"},"A Cwtch Profile"),(0,o.kt)("p",null,"Users can create one of more Cwtch Profiles. Each profile generates a random ed25519 keypair compatible with\nTor."),(0,o.kt)("p",null,"In addition to the cryptographic material, a profile also contains a list of Contacts (other Cwtch profile public keys +\nassociated data about that profile like nickname and (optionally) historical messages), a list of Groups (containing the group cryptographic material in addition to other associated data like the group nickname and historical messages)."),(0,o.kt)("h2",{id:"2-party-conversions-peer-to-peer"},"2-party conversions: Peer to Peer"),(0,o.kt)("p",null,(0,o.kt)("img",{src:r(7868).Z,width:"960",height:"540"})),(0,o.kt)("p",null,'For 2 parties to engage in a peer-to-peer conversation both must be online, but only one needs to be reachable via\ntheir onion service. For the sake of clarity we often label one party the "inbound peer" (the one who hosts the onion service) and the other party the\n"outbound peer" (the one that connects to the onion service).'),(0,o.kt)("p",null,"After connection both parties engage in an authentication protocol which:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Asserts that each party has access to the private key associated with their public identity."),(0,o.kt)("li",{parentName:"ul"},"Generates an ephemeral session key used to encrypt all further communication during the session.")),(0,o.kt)("p",null,"This exchange (documented in further detail in ",(0,o.kt)("a",{parentName:"p",href:"/security/components/tapir/authentication_protocol"},"authentication protocol"),") is ",(0,o.kt)("em",{parentName:"p"},"offline deniable"),"\ni.e. it is possible for any party to forge transcripts of this protocol exchange after the fact, and as such - after the\nfact - it is impossible to definitely prove that the exchange happened at all."),(0,o.kt)("p",null,"After, the authentication protocol the two parties may exchange messages with each other freely."),(0,o.kt)("h2",{id:"multi-party-conversations-groups-and-peer-to-server-communication"},"Multi-party conversations: Groups and Peer to Server Communication"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Note: Metadata Resistant Group Communication is still an active research area and what is documented here\nwill likely change in the future.")),(0,o.kt)("p",null,"When a person wants to start a group conversation they first randomly generate a secret ",(0,o.kt)("inlineCode",{parentName:"p"},"Group Key"),". All group communication will be encrypted using this key."),(0,o.kt)("p",null,"Along with the ",(0,o.kt)("inlineCode",{parentName:"p"},"Group Key"),", the group creator also decides on a ",(0,o.kt)("strong",{parentName:"p"},"Cwtch Server")," to use as the host of the group.\nFor more information on how Servers authenticate themselves see ",(0,o.kt)("a",{parentName:"p",href:"/security/components/cwtch/key_bundles"},"key bundles"),"."),(0,o.kt)("p",null,"A ",(0,o.kt)("inlineCode",{parentName:"p"},"Group Identifier")," is generated using the group key and the group server and these three elements are packaged up\ninto an invite that can be sent to potential group members (e.g. over existing peer-to-peer connections)."),(0,o.kt)("p",null,"To send a message to the group, a profile connects to the server hosting the group (see below), and encrypts\ntheir message using the ",(0,o.kt)("inlineCode",{parentName:"p"},"Group Key")," and generates a cryptographic signature over the ",(0,o.kt)("inlineCode",{parentName:"p"},"Group Id"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"Group Server"),"\nand the decrypted message (see: ",(0,o.kt)("a",{parentName:"p",href:"/security/components/cwtch/message_formats"},"wire formats")," for more information)."),(0,o.kt)("p",null,"To receive message from the group, a profile connected to the server hosting the group and downloads ",(0,o.kt)("em",{parentName:"p"},"all")," messages (since\ntheir previous connection). Profiles then attempt to decrypt each message using the ",(0,o.kt)("inlineCode",{parentName:"p"},"Group Key")," and if successful attempt\nto verify the signature (see ",(0,o.kt)("a",{parentName:"p",href:"/security/components/cwtch/server"},"Cwtch Servers")," ",(0,o.kt)("a",{parentName:"p",href:"/security/components/cwtch/groups"},"Cwtch Groups")," for an overview of attacks and mitigations)."),(0,o.kt)("h3",{id:"servers-are-peers"},"Servers are Peers"),(0,o.kt)("p",null,"In many respects communication with a server is identical to communication with a regular Cwtch peer,\nall the same steps above are taken however the server always acts as the inbound peer, and the outbound\npeer always uses newly generated ",(0,o.kt)("strong",{parentName:"p"},"ephemeral keypair"),' as their "longterm identity".'),(0,o.kt)("p",null,"As such peer-server conversations only differ in the ",(0,o.kt)("em",{parentName:"p"},"kinds")," of messages that are sent between the two parties,\nwith the server relaying all messages that it receives and also allowing any client to query for older messages."))}u.isMDXComponent=!0},7868:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/BASE_3-a31d3b4ac686c16d510e76ceed179a35.png"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/9c021584.82717406.js b/build-staging/assets/js/9c021584.82717406.js new file mode 100644 index 00000000..bce64bd0 --- /dev/null +++ b/build-staging/assets/js/9c021584.82717406.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[7438],{8055:e=>{e.exports=JSON.parse('{"permalink":"/blog/tags/release","page":1,"postsPerPage":10,"totalPages":1,"totalCount":2,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/9d21518d.b4fade03.js b/build-staging/assets/js/9d21518d.b4fade03.js new file mode 100644 index 00000000..9720f26f --- /dev/null +++ b/build-staging/assets/js/9d21518d.b4fade03.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[3628],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>f});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t =0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var p=n.createContext({}),c=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},l=function(e){var t=c(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=c(r),d=i,f=u["".concat(p,".").concat(d)]||u[d]||m[d]||a;return r?n.createElement(f,o(o({ref:t},l),{},{components:r})):n.createElement(f,o({ref:t},l))}));function f(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,o=new Array(a);o[0]=d;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:i,o[1]=s;for(var c=2;c{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>m,frontMatter:()=>a,metadata:()=>s,toc:()=>c});var n=r(7462),i=(r(7294),r(3905));const a={sidebar_position:4},o="Image Previews and Profile Pictures",s={unversionedId:"settings/experiments/image-previews-and-profile-pictures",id:"settings/experiments/image-previews-and-profile-pictures",title:"Image Previews and Profile Pictures",description:"This experiment requires the File Sharing experiment enabled.",source:"@site/docs/settings/experiments/image-previews-and-profile-pictures.md",sourceDirName:"settings/experiments",slug:"/settings/experiments/image-previews-and-profile-pictures",permalink:"/docs/settings/experiments/image-previews-and-profile-pictures",draft:!1,editUrl:"https://git.openprivacy.ca/cwtch.im/docs.cwtch.im/src/branch/staging/docs/settings/experiments/image-previews-and-profile-pictures.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"File Sharing",permalink:"/docs/settings/experiments/file-sharing"},next:{title:"Clickable Links Experiment",permalink:"/docs/settings/experiments/clickable-links"}},p={},c=[],l={toc:c},u="wrapper";function m(e){let{components:t,...r}=e;return(0,i.kt)(u,(0,n.Z)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"image-previews-and-profile-pictures"},"Image Previews and Profile Pictures"),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"This experiment requires the ",(0,i.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/docs/settings/experiments/file-sharing"},"File Sharing")," experiment enabled.")),(0,i.kt)("p",null,"When enabled, Cwtch will download image files automatically, display image previews in the conversation window, and enable the ",(0,i.kt)("a",{parentName:"p",href:"/docs/profiles/change-profile-image"},"Profile Pictures")," feature;"),(0,i.kt)("p",null,"On Desktop, enabling this experiment will allow access to an additional setting ",(0,i.kt)("inlineCode",{parentName:"p"},'"'),"Download Folder` which can be changed to tell Cwtch where to (automatically) download pictures."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/build-staging/assets/js/9dd8190d.f34b30a9.js b/build-staging/assets/js/9dd8190d.f34b30a9.js new file mode 100644 index 00000000..bab6532d --- /dev/null +++ b/build-staging/assets/js/9dd8190d.f34b30a9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[2688],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function r(e){for(var t=1;t =0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=i.createContext({}),s=function(e){var t=i.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=s(e.components);return i.createElement(c.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},g=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),h=s(n),g=a,m=h["".concat(c,".").concat(g)]||h[g]||d[g]||o;return n?i.createElement(m,r(r({ref:t},p),{},{components:n})):i.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,r=new Array(o);r[0]=g;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[h]="string"==typeof e?e:a,r[1]=l;for(var s=2;s {n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var i=n(7462),a=(n(7294),n(3905));const o={title:"Autogenerating Cwtch Bindings",description:"In this development log we describe a first-cut of a workflow to automatically generate Cwtch C and Java bindings from a high-level specification.",slug:"autobindings",tags:["cwtch","cwtch-stable","bindings","autobindings","libcwtch"],image:"/img/devlog8_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},r=void 0,l={permalink:"/blog/autobindings",source:"@site/blog/2023-02-24-autogenerating-cwtch-bindings.md",title:"Autogenerating Cwtch Bindings",description:"In this development log we describe a first-cut of a workflow to automatically generate Cwtch C and Java bindings from a high-level specification.",date:"2023-02-24T00:00:00.000Z",formattedDate:"February 24, 2023",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"cwtch-stable",permalink:"/blog/tags/cwtch-stable"},{label:"bindings",permalink:"/blog/tags/bindings"},{label:"autobindings",permalink:"/blog/tags/autobindings"},{label:"libcwtch",permalink:"/blog/tags/libcwtch"}],readingTime:4.545,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Autogenerating Cwtch Bindings",description:"In this development log we describe a first-cut of a workflow to automatically generate Cwtch C and Java bindings from a high-level specification.",slug:"autobindings",tags:["cwtch","cwtch-stable","bindings","autobindings","libcwtch"],image:"/img/devlog8_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},prevItem:{title:"Compile-time Optional Application Experiments (Autobindings)",permalink:"/blog/autobindings-ii"},nextItem:{title:"Notes on Cwtch UI Testing (II)",permalink:"/blog/cwtch-testing-ii"}},c={authorsImageUrls:[void 0]},s=[{value:"A Brief History of Cwtch Bindings",id:"a-brief-history-of-cwtch-bindings",level:2},{value:"Cwtch Autobindings",id:"cwtch-autobindings",level:2},{value:"Next Steps",id:"next-steps",level:2},{value:"Help us go further!",id:"help-us-go-further",level:2}],p={toc:s},h="wrapper";function d(e){let{components:t,...o}=e;return(0,a.kt)(h,(0,i.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"The C-bindings for Cwtch evolved as part of Cwtch UI development. After two years of prototyping, development, new features, and revisiting first-implementations we have reached the point where we have a good understanding of\nwhat the bindings need to do, and how they should do it. To that end we have produced a first-cut of a workflow to ",(0,a.kt)("strong",{parentName:"p"},"automatically generate")," these bindings: ",(0,a.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/cwtch.im/autobindings"},"cwtch-autobindings"),"."),(0,a.kt)("p",null,"This this development log we will introduced autobindings, the motivation behind them, and how we plan to use them on the ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/blog/path-to-cwtch-stable"},"path to Cwtch Stable"),"."),(0,a.kt)("p",null,(0,a.kt)("img",{src:n(7200).Z,width:"1005",height:"481"})),(0,a.kt)("h2",{id:"a-brief-history-of-cwtch-bindings"},"A Brief History of Cwtch Bindings"),(0,a.kt)("p",null,"Prior to the modern Flutter-based UI application, the first Cwtch UI prototype was based on Qt, with the bindings automatically generated by ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/therecipe/qt"},"therecipe/qt"),". However, after encountering numerous\ncrash-bugs on the compiled Arm version for Android, and a few weeks of prototyping different approaches, we settled on Flutter as a replacement UI framework."),(0,a.kt)("p",null,"As part of early prototyping efforts for Flutter we built out a first version of ",(0,a.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/cwtch.im/libcwtch-go"},"libCwtch-go"),", and over the two years of beta development we have evolved that prototype into a functional set of Cwtch bindings."),(0,a.kt)("p",null,"This approach has not been without side effects. There is still code from those early prototypes floating around in libCwtch-go, inconsistencies in how functions - in particular ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/blog/cwtch-stable-api-design#the-cwtch-experiment-landscape"},"experimental features")," - handle settings, ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/blog/cwtch-stable-api-design#bindings"},"duplication of logic between Cwtch and libCwtch-go"),", and ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/blog/cwtch-stable-api-design#appendix-a-special-behaviour-defined-by-libcwtch-go"},"special behaviour in libCwtch-go that better belongs in the core Cwtch library"),"."),(0,a.kt)("p",null,"As part of a broader effort to ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/blog/cwtch-stable-api-design"},"refine the Cwtch API in preparation for Cwtch Stable")," we have taken the opportunity to fix many of these problems."),(0,a.kt)("h2",{id:"cwtch-autobindings"},"Cwtch Autobindings"),(0,a.kt)("p",null,"The current ",(0,a.kt)("inlineCode",{parentName:"p"},"lib.go")," file that encapsulates the vast majority of libCwtch-go currently sits at 1500+ lines of code. However, much of that code is boilerplate calling conventions e.g. the ",(0,a.kt)("inlineCode",{parentName:"p"},"BlockContact")," API implementation is:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"//export c_BlockContact\nfunc c_BlockContact(profilePtr *C.char, profileLen C.int, conversation_id C.int) {\n BlockContact(C.GoStringN(profilePtr, profileLen), int(conversation_id))\n}\n\nfunc BlockContact(profileOnion string, conversationID int) {\n profile := application.GetPeer(profileOnion)\n if profile != nil {\n profile.BlockConversation(conversationID)\n }\n}\n")),(0,a.kt)("p",null,"All that code is doing is defining a C-compatible API, performing some basic checking of parameters, and passing the result into the core Cwtch library. The two functions themselves support the C-bindings and Java-bindings respectively."),(0,a.kt)("p",null,"In the new ",(0,a.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/cwtch.im/autobindings"},"cwtch-autobindings")," we reduce these multiple lines to ",(0,a.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/cwtch.im/autobindings/src/branch/main/spec#L19"},"a single one"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"profile BlockConversation conversation\n")),(0,a.kt)("p",null,"Defining a ",(0,a.kt)("inlineCode",{parentName:"p"},"profile"),"-level function, called ",(0,a.kt)("inlineCode",{parentName:"p"},"BlockConversation")," which takes in a single parameter of type ",(0,a.kt)("inlineCode",{parentName:"p"},"conversation"),"."),(0,a.kt)("p",null,"Using a similar boilerplate-reduction for the reset of ",(0,a.kt)("inlineCode",{parentName:"p"},"lib.go")," yields ",(0,a.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/cwtch.im/autobindings/src/branch/main/README.md#spec-file-format"},"5-basic function prototypes"),":"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Application-level functions e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"CreateProfile")),(0,a.kt)("li",{parentName:"ul"},"Profile-level functions e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"BlockConversation")),(0,a.kt)("li",{parentName:"ul"},"Profile-level functions that return data e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"GetMessage")),(0,a.kt)("li",{parentName:"ul"},"Experimental Profile-level feature functions e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"DownloadFile")),(0,a.kt)("li",{parentName:"ul"},"Experimental Profile-level feature functions that return data e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"ShareFile"))),(0,a.kt)("p",null,"Once aggregated and itemized the full set of bindings for Cwtch applications, profile interactions, and experiments can be ",(0,a.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/cwtch.im/autobindings/src/branch/main/spec"},"described in fewer than 50 lines, including comments"),". Even including the code necessary to generate the bindings from this specification file (~400 lines), and the code needed to initialize the bindings themselves (~300 lines). This cuts the amount of coded needed by 60%, and eliminates many classes of error and inconsistencies associated with maintaining bindings (e.g. regularizing function calls / checking experiment status / handling error conditions etc.)."),(0,a.kt)("h2",{id:"next-steps"},"Next Steps"),(0,a.kt)("p",null,"Cwtch autobindings work today, are API-compatible with the existing libCwtch-go implements, and can be fully integrated into an existing Cwtch application with minimal effort. However, there are a few areas which need to be addressed prior to a full rollout:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("a",{parentName:"strong",href:"https://docs.cwtch.im/blog/cwtch-stable-api-design#application-experiments"},"Application-level experiments"))," (of which there is only one: Desktop Server Hosting) are not currently supported. This functionality is only tangentially related to the rest of the Cwtch bindings, and necessarily introduces additional dependencies (e.g. on ",(0,a.kt)("inlineCode",{parentName:"li"},"cwtch-server"),"). In the coming weeks we will allow optional application experiments to be enabled at compile time, to allow us to produce smaller bindings for platforms that don't support the experiment, and to allow us to build new kinds of platform-targeted experiments that can take advantage of platform specific features."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Dart Library generation"),": since we now have a formal description of the bindings interface, we can move ahead with also autogenerating the ",(0,a.kt)("a",{parentName:"li",href:"https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/branch/trunk/lib/cwtch"},"Dart-side")," of the bindings interface, giving a boost to UI integration of new features, and allowing us to generate tailored versions of the UI interface e.g. one compiled without experiment support. We can also extend the same logic to other downstream interfaces e.g. ",(0,a.kt)("a",{parentName:"li",href:"https://git.openprivacy.ca/cwtch.im/libcwtch-rs"},"libcwtch-rs")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Documentation generation"),": another benefit of a formal description of the bindings interface, we can easily generate documentation compatible with ",(0,a.kt)("a",{parentName:"li",href:"https://cwtch.im"},"docs.cwtch.im"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Cwtch API"),": This first cut of autobindings is based on an unreleased version of the core Cwtch library that implements much of the ",(0,a.kt)("a",{parentName:"li",href:"https://docs.cwtch.im/blog/cwtch-stable-api-design"},"Cwtch Stable API redesign"),". In a short while we will be merging these features into Cwtch, in preparation for Cwtch 1.11, and beyond.")),(0,a.kt)("h2",{id:"help-us-go-further"},"Help us go further!"),(0,a.kt)("p",null,"We couldn't do what we do without all the wonderful community support we get, from ",(0,a.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," to ",(0,a.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,a.kt)("p",null,"If you want to see us move faster on some of these goals and are in a position to, please ",(0,a.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"donate"),". If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer."),(0,a.kt)("p",null,"Donations of ",(0,a.kt)("strong",{parentName:"p"},"$5 or more")," can opt to receive stickers as a thank-you gift!"),(0,a.kt)("p",null,"For more information about donating to Open Privacy and claiming a thank you gift ",(0,a.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate/"},"please visit the Open Privacy Donate page"),"."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"A Photo of Cwtch Stickers",src:n(4515).Z,width:"1024",height:"768"})))}d.isMDXComponent=!0},7200:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/devlog8-97ac031095f463e4b5172ac973677415.png"},4515:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/stickers-new-1e9b14bdd638b4907cce833e813a09ad.jpg"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/9e2a7473.1020ed04.js b/build-staging/assets/js/9e2a7473.1020ed04.js new file mode 100644 index 00000000..e4934a20 --- /dev/null +++ b/build-staging/assets/js/9e2a7473.1020ed04.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1258],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function r(e){for(var t=1;t =0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),c=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return i.createElement(s.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),h=c(n),u=a,m=h["".concat(s,".").concat(u)]||h[u]||d[u]||o;return n?i.createElement(m,r(r({ref:t},p),{},{components:n})):i.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,r=new Array(o);r[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[h]="string"==typeof e?e:a,r[1]=l;for(var c=2;c {n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var i=n(7462),a=(n(7294),n(3905));const o={title:"Cwtch Stable API Design",description:"The post outlines the technical changes we are planning on making to the core Cwtch API in preparation for Cwtch Stable ",slug:"cwtch-stable-api-design",tags:["cwtch","cwtch-stable","planning","api"],image:"/img/devlog2_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},r=void 0,l={permalink:"/blog/cwtch-stable-api-design",source:"@site/blog/2023-01-13-cwtch-stable-api-design.md",title:"Cwtch Stable API Design",description:"The post outlines the technical changes we are planning on making to the core Cwtch API in preparation for Cwtch Stable ",date:"2023-01-13T00:00:00.000Z",formattedDate:"January 13, 2023",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"cwtch-stable",permalink:"/blog/tags/cwtch-stable"},{label:"planning",permalink:"/blog/tags/planning"},{label:"api",permalink:"/blog/tags/api"}],readingTime:17.28,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Cwtch Stable API Design",description:"The post outlines the technical changes we are planning on making to the core Cwtch API in preparation for Cwtch Stable ",slug:"cwtch-stable-api-design",tags:["cwtch","cwtch-stable","planning","api"],image:"/img/devlog2_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},prevItem:{title:"Making Cwtch Bindings Reproducible",permalink:"/blog/cwtch-bindings-reproducible"},nextItem:{title:"Path to Cwtch Stable",permalink:"/blog/path-to-cwtch-stable"}},s={authorsImageUrls:[void 0]},c=[{value:"Clarifying Terminology",id:"clarifying-terminology",level:3},{value:"Tenets of the Cwtch API Design",id:"tenets-of-the-cwtch-api-design",level:3},{value:"The Cwtch Experiment Landscape",id:"the-cwtch-experiment-landscape",level:3},{value:"The Problem with Experiments",id:"the-problem-with-experiments",level:3},{value:"Restricting Powerful Cwtch APIs",id:"restricting-powerful-cwtch-apis",level:3},{value:"Pre-Registered Hooks",id:"pre-registered-hooks",level:4},{value:" ProtocolEngine
Subsystems",id:"protocolengine-subsystems",level:4},{value:"Impact on Enabling (Powerful) New Functionality",id:"impact-on-enabling-powerful-new-functionality",level:4},{value:"Application Experiments",id:"application-experiments",level:2},{value:"Bindings",id:"bindings",level:2},{value:"Timelines and Next Actions",id:"timelines-and-next-actions",level:2},{value:"Help us go further!",id:"help-us-go-further",level:2},{value:"Appendix A: Special Behaviour Defined by libcwtch-go",id:"appendix-a-special-behaviour-defined-by-libcwtch-go",level:2}],p={toc:c},h="wrapper";function d(e){let{components:t,...o}=e;return(0,a.kt)(h,(0,i.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Cwtch grew out of a prototype and has been allowed to evolve over time as we discovered better ways of implementing safe and secure metadata resistant communications. "),(0,a.kt)("p",null,"As we grew, we inserted experimental functionality where it was most accessible to place - not, necessarily, where it was ultimately best to place it - this has led to some degree of overlapping, and inconsistent, responsibilities across Cwtch software packages."),(0,a.kt)("p",null,"As we move out of Beta and ",(0,a.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/blog/path-to-cwtch-stable"},"towards Cwtch Stable")," it is time to revisit these previous decisions with both the benefit of hindsight, and years of real-world testing."),(0,a.kt)("p",null,"In this post we will outline our plans for the Cwtch API that realign responsibilities, and explicitly enable new functionality to be built in a modular, controlled, and secure way. In preparation for Cwtch Stable, and beyond."),(0,a.kt)("p",null,(0,a.kt)("img",{src:n(4867).Z,width:"1005",height:"481"})),(0,a.kt)("h3",{id:"clarifying-terminology"},"Clarifying Terminology"),(0,a.kt)("p",null,"Over the years we have evolved how we talk about the various parts of the Cwtch ecosystem. To make this document clear we have revised and clarified some terms:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Cwtch")," refers to the overall ecosystem including all the component libraries, bindings, and the flagship Cwtch application. "),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Cwtchlib")," refers to the ",(0,a.kt)("a",{parentName:"li",href:"https://git.openprivacy.ca/cwtch.im/cwtch"},"reference implementation of the Cwtch Protocol")," / Application framework, currently written in Go."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Bindings")," refers to C/Java/Kotlin/Rust bindings (primarily ",(0,a.kt)("a",{parentName:"li",href:"https://git.openprivacy.ca/cwtch.im/libcwtch-go"},"libcwtch-go"),") that act as an interface between Cwtchlib and downstream applications."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"CwtchPeer")," is where the reference Cwtch API is defined. It is responsible for managing the state of a single Cwtch Profile, persistence (e.g. storing messages), and automatically reacting to certain messages like message acknowledgements and providing public profile attributes (e.g. profile display name)."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ProtocolEngine")," is responsible for maintaining networking resources like listening threads, peer connections, ephemeral server connections. At present, ",(0,a.kt)("inlineCode",{parentName:"li"},"ProtocolEngine")," is also responsible for automatically responding to certain kinds of messages like providing file chunks for shared files.")),(0,a.kt)("h3",{id:"tenets-of-the-cwtch-api-design"},"Tenets of the Cwtch API Design"),(0,a.kt)("p",null,"Based on the tenets we have laid out for the Path to Cwtch Stable, we have adopted the following guiding principles for a new API design:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Robustness")," - new features and functionality can be implemented in Cwtch without adding new functions or dependencies to existing Cwtch interfaces."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Completeness")," - all behaviour is either defined in the official library, or explicitly deferred to applications, no special behaviour is implemented by intermediate wrappers."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Security")," \u2013 experiments should not compromise existing Cwtch functionality - and should be able to be turned on/off at any time without issue.")),(0,a.kt)("h3",{id:"the-cwtch-experiment-landscape"},"The Cwtch Experiment Landscape"),(0,a.kt)("p",null,"A summary of the experiments that are currently implements or in design, and the changes to the code that were required to support them."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Groups")," \u2013 the very first prototypes of Cwtch were designed around group messaging and, as such, multi-party chats are the most integrated experiment within Cwtch sharing interfaces with P2P chat and requiring specialized ",(0,a.kt)("inlineCode",{parentName:"li"},"ProtocolEngine")," functionality to manage ephemeral connections and antispam tokens, including the introduction of new peer events like NewMessageFromGroup. ",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Hybrid Groups")," - we have plans to upgrade the Groups experience to a more flexible \u201chybrid-groups\u201d protocol which requires additional custom hook-response that needs to be tightly controlled and isolated from other parts of the system."))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Filesharing")," \u2013 like Groups, Filesharing is a cross-cutting feature that required new APIs, new Hooks into Peer Events, and additional capability in ",(0,a.kt)("inlineCode",{parentName:"li"},"ProtocolEngine"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Profile Images")," \u2013 based on Filesharing and the core get/val functionality, there are only a few small parts of the codebase that are explicitly dedicated to profile images, and these are all event-based reactions that currently reside in the event-decoration module of licwtch-go, but could easily be moved to a standalone module if a hook-based API was available."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Server Hosting")," \u2013 the only example of an Application-level experiment in Cwch at present. This functionality requires no changes to the cwtchlib module, but is mainly implemented in the libcwtch-go bindings themselves. Ideally this functionality would be moved into a standalone package."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Message Formatting")," \u2013 notable as the the main example of a former experimental-functionality that was promoted to an optional feature, but because it is entirely UI based in implementation there are few insights that can be gained from its history"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Search / Microblogging")," \u2013 proposed features that would require database access/changes in order to implement fully and efficiently, any proposed changes to the Cwtch API should allow for the possibility of new functionality at all layers of the Cwtch stack, including storage."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Status / Profile Metadata")," \u2013 proposed features that only require specific APIs / hooks for saving requested information for the purposes of caching.")),(0,a.kt)("h3",{id:"the-problem-with-experiments"},"The Problem with Experiments"),(0,a.kt)("p",null,"We have done some work in past to limit the impact an experimental feature can have on the rest of Cwtch, mainly through providing restricted sets of public Cwtch APIs e.g. the ",(0,a.kt)("inlineCode",{parentName:"p"},"SendMessages")," interface that only allows callers to send messages."),(0,a.kt)("p",null,"We have also worked to package experimental functionality into so-called ",(0,a.kt)("strong",{parentName:"p"},"Gated Functionalities")," that are only available if a given experiment is turned on."),(0,a.kt)("p",null,"Together, these form the current basis for implementing to Cwtch features in the official libraries, but they are not without problems:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"The scope of a functionality is rather broad, and can only be passed a complete Cwtch profile or a denoted subset of functionality e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"SendMessages")," \u2013 there is no current way to scope a function to a specific conversation, or to a given zone (e.g. filesharing code is technically able to update attributes unrelated to filesharing)."),(0,a.kt)("li",{parentName:"ul"},"The implementation of experiments has mostly been delegated to bindings and, as such, the gating inside CwtchLib is limited, often relying on state to be passed into it by the bindings, or relying on the bindings explicitly disable the functionality."),(0,a.kt)("li",{parentName:"ul"},"This lack of ownership over experiments by the official CwtchLib means that libraries based on CwtchLib instead of bindings do not have access to the safeguards provided by the bindings.")),(0,a.kt)("h3",{id:"restricting-powerful-cwtch-apis"},"Restricting Powerful Cwtch APIs"),(0,a.kt)("p",null,"To carefully expand Cwtch out using additional experimental APIs we must work to limit the impact further e.g. restricting actions to a given type of conversation, or only executing actions at registered times. To do this we require three separate but related strands of work:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Assume responsibility for experiments and features in Cwtch itself so that Cwtchlib has direct access to which experiments are enabled at any given time. Doing this allows changes to settings to always flow through ",(0,a.kt)("inlineCode",{parentName:"li"},"Application")," and, (as currently happens with Anonymous Communication Network (ACN) state), provides a natural point at which to interface those changes into a Cwtch Profile."),(0,a.kt)("li",{parentName:"ul"},"Finer-grained Interfaces that allow restricting actions to preregistered conversation types e.g. a ",(0,a.kt)("inlineCode",{parentName:"li"},"RestrictedCwtchConversationInterface")," which decorates a Cwtch Profile interface such that it can only interact with a single conversation \u2013 these can then be passed into hooks and interface functions to limit their impact."),(0,a.kt)("li",{parentName:"ul"},"Registered Hooks at pre-specified points with restricted capabilities \u2013 to allow experimental functionality to register interest in certain events, and act on them at the correct time, and to allow ",(0,a.kt)("inlineCode",{parentName:"li"},"CwtchPeer")," to control which experiments get access to which events at a given time.")),(0,a.kt)("h4",{id:"pre-registered-hooks"},"Pre-Registered Hooks"),(0,a.kt)("p",null,"In order to implement certain functionality actions need to take place in-between events handled by ",(0,a.kt)("inlineCode",{parentName:"p"},"CwtchPeer"),". As a motivating example consider a new group membership protocol overlayed above the existing messages. Such a protocol may require checking against group permission settings after receiving a new message, but before inserting it into into the database (e.g. the message author needs to be confirmed against the list of current members authorized to post to the group)."),(0,a.kt)("p",null,"This is currently only possible with invasive changes to the ",(0,a.kt)("inlineCode",{parentName:"p"},"CwtchPeer")," interface, explicitly inserting a hook point and acting on it. In an ideal design we would be able to register such hooks for most likely events without additional development effort."),(0,a.kt)("p",null,"We are introducing a new set of Cwtch APIs designed for this purpose:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"OnNewPeerMessage")," - hooked prior to inserting the message into the database."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"OnPeerMessageConfirmed")," \u2013 hooked after a peer message has been inserted into the database."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"OnEncryptedGroupMessage")," \u2013 hooked after receiving an encrypted message from a group server."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"OnGroupMessageReceived")," \u2013 hooked after a successful decryption of a group message, but before inserting it into the database."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"OnContactRequestValue")," \u2013 hooked on request of a scoped (the permission level of the attribute e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"public")," or ",(0,a.kt)("inlineCode",{parentName:"li"},"conversation")," level attributes), zoned ( relating to a specific feature e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"filesharing")," or ",(0,a.kt)("inlineCode",{parentName:"li"},"chat"),"), and keyed (the name of the attribute e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"name")," or ",(0,a.kt)("inlineCode",{parentName:"li"},"manifest"),") value from a contact."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"OnContactReceiveValue")," \u2013 hooked on receipt of a requested scoped,zoned, and keyed value from a contact.")),(0,a.kt)("p",null,"Including the following APIs for managing hooked functionality:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"RegisterEvents")," - returns a set of events that the extension is interested processing."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"RegisterExperiments")," - returns a set of experiments that the extension is interested in being notified about"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"OnEvent")," - to be called by ",(0,a.kt)("inlineCode",{parentName:"li"},"CwtchPeer")," whenever an event registered with ",(0,a.kt)("inlineCode",{parentName:"li"},"RegisterEvents")," is called (assuming all experiments registered through ",(0,a.kt)("inlineCode",{parentName:"li"},"RegisterExperiments")," is active)")),(0,a.kt)("h4",{id:"protocolengine-subsystems"},(0,a.kt)("inlineCode",{parentName:"h4"},"ProtocolEngine")," Subsystems"),(0,a.kt)("p",null,"As mentioned in our experiment summary, some functionality needs to be implemented directly in the ",(0,a.kt)("inlineCode",{parentName:"p"},"ProtocolEngine"),". The ",(0,a.kt)("inlineCode",{parentName:"p"},"ProtocolEngine")," is responsible for managing networking clients, and sending/receiving packets from those clients to/from a CwtchPeer (via the event bus)."),(0,a.kt)("p",null,"Some types of data are too costly to send over the event bus e.g. requested chunks from shared files, and as such we need to delegate the handling of such data to a ",(0,a.kt)("inlineCode",{parentName:"p"},"ProtocolEngine"),"."),(0,a.kt)("p",null,"At the moment is this done through the concept of informal \u201csubsystems\u201d, modular add-ons to ",(0,a.kt)("inlineCode",{parentName:"p"},"ProtocolEngine")," that process certain events. The current informal nature of this design means that there are not hard-and-fast rules regarding what functionality lives in a subsystem, and how subsystems interact with the wider ",(0,a.kt)("inlineCode",{parentName:"p"},"ProtocolEngine")," ecosystem. "),(0,a.kt)("p",null,"We are formalizing this subsystem into an interface, similar to the hooked functionality in ",(0,a.kt)("inlineCode",{parentName:"p"},"CwtchPeer"),":"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"RegisterEvents")," - returns a set of events that the subsystem needs to consume to operate."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"OnEvent")," \u2013 to be called by ",(0,a.kt)("inlineCode",{parentName:"li"},"ProtocolEngine")," whenever an event registered with ",(0,a.kt)("inlineCode",{parentName:"li"},"RegisterEvents")," is called (when all the experiments registered through ",(0,a.kt)("inlineCode",{parentName:"li"},"RegisterExperiments")," are active)"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"RegisterContexts")," - returns the set of contexts that the subsystem implements e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"im.cwtch.filesharing"))),(0,a.kt)("p",null,"This also requires a formalization of two ",(0,a.kt)("em",{parentName:"p"},"engine specific")," events (for use on the event bus):"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"SendCwtchMessage")," \u2013 encapsulating the existing ",(0,a.kt)("inlineCode",{parentName:"li"},"CwtchPeerMessage")," that is used internally in ",(0,a.kt)("inlineCode",{parentName:"li"},"ProtocolEngine")," for messages between subsystems."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"CwtchMessageReceived")," \u2013 encapsulating the existing ",(0,a.kt)("inlineCode",{parentName:"li"},"handlePeerMessage")," function which effectively already serves this purpose, but instead of using an Observer pattern, is implemented as an increasingly unwieldy set of if/else blocks.")),(0,a.kt)("p",null,"And the introduction of three ",(0,a.kt)("strong",{parentName:"p"},"additional")," ",(0,a.kt)("inlineCode",{parentName:"p"},"ProtocolEnine")," specific events:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"StartEngineSubsystem")," \u2013 replaces subsystem specific start event, can be driven by functionalities to (re)start protocol specific handling."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"StopEngineSubsystem")," \u2013 replaces subsystem specific stop event mechanisms, can be driven by functionalities to stop all protocol specific handling."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"SubsystemStatus")," \u2013 a generic event that can be published by subsystems with a collection of fields useful for debugging")),(0,a.kt)("p",null,"This will allow us to move the following functionality, currently part of ",(0,a.kt)("inlineCode",{parentName:"p"},"ProtocolEngine")," itself, into generic subsystems:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Attribute Lookup Handling")," - this functionality is currently part of the overloaded ",(0,a.kt)("inlineCode",{parentName:"li"},"handlePeerMessage")," function, filtered using the ",(0,a.kt)("inlineCode",{parentName:"li"},"Context")," parameter of the ",(0,a.kt)("inlineCode",{parentName:"li"},"CwtchPeerMessage"),". As such it can be entirely delegated to a subsystem. "),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Filesharing Chunk Request Handling")," \u2013 this is also part of handlePeerMessage, also filtered using the ",(0,a.kt)("inlineCode",{parentName:"li"},"Context")," parameter, and is already almost entirely implementing in a standalone subsystem (only routing is handled by ",(0,a.kt)("inlineCode",{parentName:"li"},"handlePeerMessage"),")"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Filesharing Start File Share/Stop File Share")," \u2013 this is currently part of the ",(0,a.kt)("inlineCode",{parentName:"li"},"handleEvent")," behaviour of ",(0,a.kt)("inlineCode",{parentName:"li"},"ProtocolEngine")," and can be moved into an ",(0,a.kt)("inlineCode",{parentName:"li"},"OnEvent")," handler of the file sharing subsystem (where such events are already processed).")),(0,a.kt)("p",null,"The introduction of pre-registered hooks in combination with the formalizations of ",(0,a.kt)("inlineCode",{parentName:"p"},"ProtocolEngine")," subsystems will allow the follow functionality, currently implemented in ",(0,a.kt)("inlineCode",{parentName:"p"},"CwtchPeer")," or libcwtch-go to be moved to standalone packages:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Filesharing")," makes heavy use of the getval/retval functionality, we can move all of this into a hooked-based functionality extension. ",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Filesharing also depends on the file sharing subsystem to be enabled in a ",(0,a.kt)("inlineCode",{parentName:"li"},"ProtocolEngine"),". This subsystem is responsible for processing chunk requests."))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Profile Images")," \u2013 we treat profile images as a specialization of the file sharing function, as such the experiment can operate entirely over apis provided by the filesharing experiment. (Right now this specialization lives in libcwtch-go as hooks into the relevant functions)"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Legacy Groups")," \u2013 while groups themselves are a first-class consideration for Cwtch, the actual process of constructing and receiving group messages relies heavily on processing of events, or interpreting generic conversation attributes, and as such this functionality can be moved entirely to hooked-based functionality. By doing this we also open the path towards introducing new group protocols based on the same interface."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Status/Profile Metadata")," \u2013 status depends entirely on OnPeerRequestValue / OnPeerReceiveValue and requires little Cwtch Peer interaction other than saving the result.")),(0,a.kt)("h4",{id:"impact-on-enabling-powerful-new-functionality"},"Impact on Enabling (Powerful) New Functionality"),(0,a.kt)("p",null,"None of the above restricts our ability to introduce new functionality in to Cwtch that is dependent on more invasive changes (e.g. direct database access / updates), but they do allow us to structure such changes into discrete modules:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Search")," \u2013 a fulltext search feature requires new indexes to be created in Cwtch Storage (likely using the sqlite FT5 module). As an experiment SearchFunctionality would need access to a hook after database setup in order to create and populate those indexes. This is a far more powerful feature than most as it requires direct database access."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Non Chat Conversation Contexts")," - the storage backend work we implemented last year had a long-term goal of enabling non-chat contexts like microblogging. Like search, these kinds of experiments will require deeply integrated access to the Cwtch database.")),(0,a.kt)("h2",{id:"application-experiments"},"Application Experiments"),(0,a.kt)("p",null,"One kind of experiment we haven\u2019t touched on yet is additional application functionality, at present we have one main example: Embedded Server Hosting \u2013 this allows a Cwtch desktop client to setup and manage Cwtch Servers."),(0,a.kt)("p",null,"This kind of functionality doesn\u2019t belong in Cwtchlib \u2013 as it would necessarily introduce unrelated dependencies into the core library."),(0,a.kt)("p",null,"This functionality also doesn\u2019t belong in the bindings either. They should be as minimal as possible. To that end, we will be moving this functionality out of the bindings and into dedicated repositories which can be managed via an Application Experiment interface."),(0,a.kt)("h2",{id:"bindings"},"Bindings"),(0,a.kt)("p",null,"The last problem to be solved is how to interface experiments with the bindings (libcwtch-go) and ultimately downstream applications."),(0,a.kt)("p",null,"We can split the bindings into four core areas:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Application Management")," - functionality necessary to manage the core Cwtch application e.g. StartCwtch, ReconnectCwtchForeground, Shutdown, CreateProfile etc. This category also include FreePointer which is necessary for safe memory management."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Application Experiments")," - auxiliary functionality that augments the Cwtch application with new features e.g. Server Hosting etc."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Core Profile Management")," - core non-experimental functionality that requires a profile e.g. ImportBundle, SendMessage etc. These apis take a handle in addition to the parameters needed to call the underlying function."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Experimental Profile Features")," \u2013 auxiliary functionality that augments profiles with additional features e.g. ShareFile, SetProfileImage etc. These apis also take a handle.")),(0,a.kt)("p",null,"The flip side of the bindings is the event bus handing which is responsible for maintaining a queue for the downstream application. This queue provides some filtering and enhancement of events to improve performance. This queue can be moved entirely into Application with only GetAppBusEvent defined and exposed in the bindings."),(0,a.kt)("p",null,"In an ideal future, all of these bindings could be ",(0,a.kt)("strong",{parentName:"p"},"generated automatically")," from the Cwtchlib interface definitions i.e. there should be no special functionality in the bindings themselves. The generation would need to include C bindings (untyped with automatic checks) and the Dart library calling convention (type safe)"),(0,a.kt)("p",null,"We can define three types of C/Java/Kotlin interface function templates:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ProfileMethodName(profilehandle String, args...)")," \u2013 which directly resolves the Cwtch Profile and calls the function."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ProfileExperimentalMethodName(profilehandle String, args...)")," \u2013 which checks the current application settings to see if the experiment is enabled, and then resolves the CwtchProfile and calls the function - else errors."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ApplicationExperimentalMethodName(args...)")," \u2013 which checks the current application settings to see if the experiment is enabled, and if so, calls the experimental application functionality.")),(0,a.kt)("p",null,"All we need to know from CwtchLib is what methods to export to C bindings, and what template they should use. This can be automatically derived from the context ",(0,a.kt)("inlineCode",{parentName:"p"},"ProfileInterface")," for the first, exported methods of the various ",(0,a.kt)("inlineCode",{parentName:"p"},"Functionalities")," for the second, and ",(0,a.kt)("inlineCode",{parentName:"p"},"ApplicationExperiment")," definitions for the third."),(0,a.kt)("h2",{id:"timelines-and-next-actions"},"Timelines and Next Actions"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Freeze any changes to the bindings interface")," - we have made minimal changes to the bindings in the Cwtch 1.9 and 1.10 \u2013 until we have implemented the proposed changes into cwtchlib."),(0,a.kt)("li",{parentName:"ul"},"As part of Cwtch 1.11 and 1.12 Release Cycles",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Implement the ",(0,a.kt)("inlineCode",{parentName:"li"},"ProtocolEngine")," Subsystem Design as outlined above."),(0,a.kt)("li",{parentName:"ul"},"Implement the Hooks API."),(0,a.kt)("li",{parentName:"ul"},"Move all special behaviour / extra functionalities in the libcwtch-go bindings into cwtchlib \u2013 with the exception of behaviour related to Application Experiments (i.e. Server Hosting)."),(0,a.kt)("li",{parentName:"ul"},"Move event handling from the bindings into Application."),(0,a.kt)("li",{parentName:"ul"},"Move Application Experiments defined in bindings into their own libraries (or integrate them into existing libraries like cwtch-server) \u2013 keeping the existing interface definitions."))),(0,a.kt)("li",{parentName:"ul"},"Once Automated UI Tests have been integrated into the Cwtch UI Repository:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Write a generate-cwtch-bindings tool that auto generates the libcwtch-go C/Android bindings ",(0,a.kt)("strong",{parentName:"li"},"and")," a dart calling convention library from cwtchlib and any configured application experiments libraries"),(0,a.kt)("li",{parentName:"ul"},"Port the existing UI app to use the newly generated dart Cwtch library (this must wait until we have automated UI testing as part of the build process to ensure that there are no regressions during this process)."),(0,a.kt)("li",{parentName:"ul"},"At this point the bindings are based off of the generated library and libcwtch-go is deprecated / replaced with automatically generated and versioned bindings.")))),(0,a.kt)("p",null,"As these changes are made, and these goals met we will be posting about them here! Subscribe to our ",(0,a.kt)("a",{parentName:"p",href:"/blog/rss.xml"},"RSS feed"),", ",(0,a.kt)("a",{parentName:"p",href:"/blog/atom.xml"},"Atom feed"),", or ",(0,a.kt)("a",{parentName:"p",href:"/blog/feed.json"},"JSON feed")," to stay up to date, and get the latest on, all Cwtch development."),(0,a.kt)("h2",{id:"help-us-go-further"},"Help us go further!"),(0,a.kt)("p",null,"We couldn't do what we do without all the wonderful community support we get, from ",(0,a.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," to ",(0,a.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,a.kt)("p",null,"If you want to see us move faster on some of these goals and are in a position to, please ",(0,a.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"donate"),". If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer."),(0,a.kt)("p",null,"Donations of ",(0,a.kt)("strong",{parentName:"p"},"$5 or more")," can opt to receive stickers as a thank-you gift!"),(0,a.kt)("p",null,"For more information about donating to Open Privacy and claiming a thank you gift ",(0,a.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate/"},"please visit the Open Privacy Donate page"),"."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"A Photo of Cwtch Stickers",src:n(4515).Z,width:"1024",height:"768"})),(0,a.kt)("h2",{id:"appendix-a-special-behaviour-defined-by-libcwtch-go"},"Appendix A: Special Behaviour Defined by libcwtch-go"),(0,a.kt)("p",null,"The following is an exhaustive list of functionality currently provided by libcwtch-go bindings instead of the cwtchlib:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Application Settings",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Including Enabling / Disabling Experiment"))),(0,a.kt)("li",{parentName:"ul"},"ACN Process Management - starting/stopping/restarting/configuring Tor."),(0,a.kt)("li",{parentName:"ul"},"Notification Handling - augmenting/suppressing/augmenting interesting event notifications (primarily for Android)"),(0,a.kt)("li",{parentName:"ul"},"Logging Levels - configuring appropriate logging levels (e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"INFO")," or ",(0,a.kt)("inlineCode",{parentName:"li"},"DEBUG"),")"),(0,a.kt)("li",{parentName:"ul"},"Profile Images Helper Functions - handling default profile images for contacts and groups, in addition to looking up custom profile images if the experiment is enabled."),(0,a.kt)("li",{parentName:"ul"},"UI Contact Structures - aggregating contact information for the main Cwtch UI."),(0,a.kt)("li",{parentName:"ul"},"Group Experiment Functionality",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Experiment Gating"),(0,a.kt)("li",{parentName:"ul"},"GetServerInfoList"),(0,a.kt)("li",{parentName:"ul"},"GetServerInfo"),(0,a.kt)("li",{parentName:"ul"},"UI Server Struct Definition"))),(0,a.kt)("li",{parentName:"ul"},"Server Hosting Experiment Functionality - creating/deleting/managing the server hosting experiment for desktop Cwtch clients."),(0,a.kt)("li",{parentName:"ul"},'"Unencrypted" Profile Handling - replacing a blank password with a default password where the underlying API expects a password but the profile has been designated "unencrypted".'),(0,a.kt)("li",{parentName:"ul"},"Image Previews Experiment Handling - automatically starting the downloading of certain file types (when the experiment is enabled)."),(0,a.kt)("li",{parentName:"ul"},"Cwtch UI Reconnection Handling (for Android) - restarting various Cwtch subsystems when the UI attempts to reconnect in circumstances where the Android kernel has killed the underlying process."),(0,a.kt)("li",{parentName:"ul"},"Cwtch Profile Engine Activation - starting/stopping a ",(0,a.kt)("inlineCode",{parentName:"li"},"ProtocolEngine")," when requested by the UI, or in response to changes in ACN state."),(0,a.kt)("li",{parentName:"ul"},"UI Profile Aggregation - aggregating information related to Profiles for the UI (e.g. network connection status / unread messages) into a single event."),(0,a.kt)("li",{parentName:"ul"},"File sharing restarts "),(0,a.kt)("li",{parentName:"ul"},"UI Event Augmentation - augmenting various internal Cwtch events with information that the UI needs but that isn't directly embedded within the event (e.g. converting ",(0,a.kt)("inlineCode",{parentName:"li"},"handle")," to a ",(0,a.kt)("inlineCode",{parentName:"li"},"conversation id"),"). Much of this augmentation is legacy, implemented before recent changes to internal Cwtch structs, and likely can either be removed entirely, or delegated into Cwtch itself."),(0,a.kt)("li",{parentName:"ul"},"Debug Information - special information available to Cwtch debug builds (memory use / active goroutines etc.)")))}d.isMDXComponent=!0},4867:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/devlog2-3f3a0725dfb20a2d49da23dd84274ec2.png"},4515:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/stickers-new-1e9b14bdd638b4907cce833e813a09ad.jpg"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/9e4087bc.582408aa.js b/build-staging/assets/js/9e4087bc.582408aa.js new file mode 100644 index 00000000..6b05be93 --- /dev/null +++ b/build-staging/assets/js/9e4087bc.582408aa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[3608],{3169:(e,t,a)=>{a.r(t),a.d(t,{default:()=>o});var r=a(7294),l=a(9960),n=a(5999),c=a(1944),m=a(7961);function s(e){let{year:t,posts:a}=e;return r.createElement(r.Fragment,null,r.createElement("h3",null,t),r.createElement("ul",null,a.map((e=>r.createElement("li",{key:e.metadata.date},r.createElement(l.Z,{to:e.metadata.permalink},e.metadata.formattedDate," - ",e.metadata.title))))))}function i(e){let{years:t}=e;return r.createElement("section",{className:"margin-vert--lg"},r.createElement("div",{className:"container"},r.createElement("div",{className:"row"},t.map(((e,t)=>r.createElement("div",{key:t,className:"col col--4 margin-vert--lg"},r.createElement(s,e)))))))}function o(e){let{archive:t}=e;const a=(0,n.I)({id:"theme.blog.archive.title",message:"Archive",description:"The page & hero title of the blog archive page"}),l=(0,n.I)({id:"theme.blog.archive.description",message:"Archive",description:"The page & hero description of the blog archive page"}),s=function(e){const t=e.reduceRight(((e,t)=>{const a=t.metadata.date.split("-")[0],r=e.get(a)??[];return e.set(a,[t,...r])}),new Map);return Array.from(t,(e=>{let[t,a]=e;return{year:t,posts:a}}))}(t.blogPosts);return r.createElement(r.Fragment,null,r.createElement(c.d,{title:a,description:l}),r.createElement(m.Z,null,r.createElement("header",{className:"hero hero--primary"},r.createElement("div",{className:"container"},r.createElement("h1",{className:"hero__title"},a),r.createElement("p",{className:"hero__subtitle"},l))),r.createElement("main",null,s.length>0&&r.createElement(i,{years:s}))))}}}]); \ No newline at end of file diff --git a/build-staging/assets/js/9f1c7621.9c0d80ed.js b/build-staging/assets/js/9f1c7621.9c0d80ed.js new file mode 100644 index 00000000..9241aced --- /dev/null +++ b/build-staging/assets/js/9f1c7621.9c0d80ed.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1312],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>g});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var p=n.createContext({}),l=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=l(a),h=r,g=u["".concat(p,".").concat(h)]||u[h]||d[h]||i;return a?n.createElement(g,o(o({ref:t},c),{},{components:a})):n.createElement(g,o({ref:t},c))}));function g(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var l=2;l{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var n=a(7462),r=(a(7294),a(3905));const i={title:"Notes on Cwtch UI Testing (II)",description:"In this development log we provide more updates on automated UI integration testing!",slug:"cwtch-testing-ii",tags:["cwtch","cwtch-stable","support","testing"],image:"/img/devlog7_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},o=void 0,s={permalink:"/blog/cwtch-testing-ii",source:"@site/blog/2023-02-17-cwtch-testing-ii.md",title:"Notes on Cwtch UI Testing (II)",description:"In this development log we provide more updates on automated UI integration testing!",date:"2023-02-17T00:00:00.000Z",formattedDate:"February 17, 2023",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"cwtch-stable",permalink:"/blog/tags/cwtch-stable"},{label:"support",permalink:"/blog/tags/support"},{label:"testing",permalink:"/blog/tags/testing"}],readingTime:1.75,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Notes on Cwtch UI Testing (II)",description:"In this development log we provide more updates on automated UI integration testing!",slug:"cwtch-testing-ii",tags:["cwtch","cwtch-stable","support","testing"],image:"/img/devlog7_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},prevItem:{title:"Autogenerating Cwtch Bindings",permalink:"/blog/autobindings"},nextItem:{title:"Making Cwtch Android Bindings Reproducible",permalink:"/blog/cwtch-android-reproducibility"}},p={authorsImageUrls:[void 0]},l=[{value:"Constraining Cwtch UI Fields",id:"constraining-cwtch-ui-fields",level:2},{value:"More Automated UI Tests",id:"more-automated-ui-tests",level:2},{value:"New Release of Cwtchbot",id:"new-release-of-cwtchbot",level:2},{value:"Help us go further!",id:"help-us-go-further",level:2}],c={toc:l},u="wrapper";function d(e){let{components:t,...i}=e;return(0,r.kt)(u,(0,n.Z)({},c,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"In this development log, we investigate some text-based UI bugs encountered by ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/docs/contribute/testing#running-fuzzbot"},"Fuzzbot"),", add more ",(0,r.kt)("a",{parentName:"p",href:"/blog/cwtch-testing-i"},"automated UI tests")," to the pipeline, and announce a new release of the Cwtchbot library."),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(6097).Z,width:"1005",height:"481"})),(0,r.kt)("h2",{id:"constraining-cwtch-ui-fields"},"Constraining Cwtch UI Fields"),(0,r.kt)("p",null,"Fuzzbot identified a few bugs relating to UI layout and text clipping. Certain strings would violate the bounds of their containers and overlap with other UI elements. While this\ndoesn't pose a safety issue, it is unsightly."),(0,r.kt)("figure",null,(0,r.kt)("p",null,(0,r.kt)("a",{target:"_blank",href:a(3785).Z},(0,r.kt)("img",{src:a(6561).Z,width:"410",height:"90"}))),(0,r.kt)("figcaption",null,"Screenshot demonstrating how certain strings would violate the bounds of their containers.")),(0,r.kt)("p",null,"These cases were fixed by parenting impacted elements in a ",(0,r.kt)("inlineCode",{parentName:"p"},"Container")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"clip: hardEdge")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"decoration:BoxDecoration()")," (note that both of these are required as Container widgets in Flutter cannot set clipping logic\nwithout an associated decoration)."),(0,r.kt)("figure",null,(0,r.kt)("p",null,(0,r.kt)("a",{target:"_blank",href:a(3551).Z},(0,r.kt)("img",{src:a(9812).Z,width:"427",height:"76"}))),(0,r.kt)("figcaption",null,"Now these clipped strings are tightly constrained to their container bounds.")),(0,r.kt)("p",null,"These fixes are available in the ",(0,r.kt)("a",{parentName:"p",href:"/docs/contribute/testing#cwtch-nightlies"},"latest Cwtch Nightly"),", and will be officially released in Cwtch 1.11."),(0,r.kt)("h2",{id:"more-automated-ui-tests"},"More Automated UI Tests"),(0,r.kt)("p",null,"We have added two new sets of automated UI tests to our pipeline:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"02: Global Settings")," - these tests check that certain global settings like languages, theme, unknown contacts blocking, and streamer mode work as expected. (",(0,r.kt)("a",{parentName:"li",href:"https://git.openprivacy.ca/cwtch.im/cwtch-ui/pulls/628"},"PR: 628"),")"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"04: Profile Management")," - these tests check that creating, unlocking, and deleting a profile work as expected. (",(0,r.kt)("a",{parentName:"li",href:"https://git.openprivacy.ca/cwtch.im/cwtch-ui/pulls/632"},"PR: 632"),")")),(0,r.kt)("h2",{id:"new-release-of-cwtchbot"},"New Release of Cwtchbot"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/sarah/cwtchbot"},"Cwtchbot")," has been updated to use the latest Cwtch 0.18.10 API."),(0,r.kt)("h2",{id:"help-us-go-further"},"Help us go further!"),(0,r.kt)("p",null,"We couldn't do what we do without all the wonderful community support we get, from ",(0,r.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," to ",(0,r.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,r.kt)("p",null,"If you want to see us move faster on some of these goals and are in a position to, please ",(0,r.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"donate"),". If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer."),(0,r.kt)("p",null,"Donations of ",(0,r.kt)("strong",{parentName:"p"},"$5 or more")," can opt to receive stickers as a thank-you gift!"),(0,r.kt)("p",null,"For more information about donating to Open Privacy and claiming a thank you gift ",(0,r.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate/"},"please visit the Open Privacy Donate page"),"."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"A Photo of Cwtch Stickers",src:a(4515).Z,width:"1024",height:"768"})))}d.isMDXComponent=!0},3551:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/files/dl7-after-452769c3b44432627b4533b37b3e9053.png"},3785:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/files/dl7-before-38cd04ba78b67745560d72a1872e4443.png"},6097:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/devlog7-ddd3206f988a859af98340268befb0fa.png"},9812:(e,t,a)=>{a.d(t,{Z:()=>n});const n="data:image/png;base64,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"},6561:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/dl7-before-38cd04ba78b67745560d72a1872e4443.png"},4515:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/stickers-new-1e9b14bdd638b4907cce833e813a09ad.jpg"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a02b4022.90907439.js b/build-staging/assets/js/a02b4022.90907439.js new file mode 100644 index 00000000..24ed2b43 --- /dev/null +++ b/build-staging/assets/js/a02b4022.90907439.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[3492],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>d});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t =0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},m="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),m=p(a),u=r,d=m["".concat(s,".").concat(u)]||m[u]||h[u]||i;return a?n.createElement(d,o(o({ref:t},c),{},{components:a})):n.createElement(d,o({ref:t},c))}));function d(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[m]="string"==typeof e?e:r,o[1]=l;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var n=a(7462),r=(a(7294),a(3905));const i={title:"Cwtch Beta 1.12",description:"Cwtch Beta 1.12 is now available for download",slug:"cwtch-nightly-1-12",tags:["cwtch","cwtch-stable","release"],image:"/img/devlog13_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},o=void 0,l={permalink:"/blog/cwtch-nightly-1-12",source:"@site/blog/2023-06-16-cwtch-1.12.md",title:"Cwtch Beta 1.12",description:"Cwtch Beta 1.12 is now available for download",date:"2023-06-16T00:00:00.000Z",formattedDate:"June 16, 2023",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"cwtch-stable",permalink:"/blog/tags/cwtch-stable"},{label:"release",permalink:"/blog/tags/release"}],readingTime:2.455,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Cwtch Beta 1.12",description:"Cwtch Beta 1.12 is now available for download",slug:"cwtch-nightly-1-12",tags:["cwtch","cwtch-stable","release"],image:"/img/devlog13_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},prevItem:{title:"Cwtch Stable Roadmap Update",permalink:"/blog/cwtch-stable-roadmap-update-june"},nextItem:{title:"New Cwtch Nightly (v1.11.0-74-g0406)",permalink:"/blog/cwtch-nightly-v.11-74"}},s={authorsImageUrls:[void 0]},p=[{value:"In This Release",id:"in-this-release",level:2},{value:"Reproducible Bindings",id:"reproducible-bindings",level:2},{value:"Download the New Version",id:"download-the-new-version",level:2},{value:"Help us go further!",id:"help-us-go-further",level:2}],c={toc:p},m="wrapper";function h(e){let{components:t,...i}=e;return(0,r.kt)(m,(0,n.Z)({},c,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://cwtch.im/download"},"Cwtch 1.12 is now available for download"),"!"),(0,r.kt)("p",null,"Cwtch 1.12 is the culmination of the last few months of effort by the Cwtch team, and includes many foundational changes that pave the way for ",(0,r.kt)("a",{parentName:"p",href:"/blog/path-to-cwtch-stable"},"Cwtch Stable")," including new features like ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/docs/profiles/profile-info"},"profile attributes"),", support for new platforms like ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/docs/platforms/tails"},"Tails"),", and multiple improvements to performance and stability."),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(159).Z,width:"1004",height:"480"})),(0,r.kt)("h2",{id:"in-this-release"},"In This Release"),(0,r.kt)("figure",null,(0,r.kt)("p",null,(0,r.kt)("a",{target:"_blank",href:a(8173).Z},(0,r.kt)("img",{src:a(5726).Z,width:"1388",height:"828"}))),(0,r.kt)("figcaption",null,"A screenshot of Cwtch 1.12")),(0,r.kt)("p",null,"A special thanks to the ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/docs/contribute/translate"},"amazing volunteer translators")," and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/docs/contribute/testing"},"testers")," who made this release possible."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"New Features:"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Profile Attributes")," - profiles can now be augmented with ",(0,r.kt)("a",{parentName:"li",href:"https://docs.cwtch.im/docs/profiles/profile-info"},"additional public information")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Availability Status")," - you can now notify contacts that you ",(0,r.kt)("a",{parentName:"li",href:"https://docs.cwtch.im/docs/profiles/availability-status"},"are ",(0,r.kt)("strong",{parentName:"a"},"away")," or ",(0,r.kt)("strong",{parentName:"a"},"busy"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Five New Supported Localizations"),": ",(0,r.kt)("strong",{parentName:"li"},"Japanese"),", ",(0,r.kt)("strong",{parentName:"li"},"Korean"),", ",(0,r.kt)("strong",{parentName:"li"},"Slovak"),", ",(0,r.kt)("strong",{parentName:"li"},"Swahili")," and ",(0,r.kt)("strong",{parentName:"li"},"Swedish")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Support for Tails")," - adds an ",(0,r.kt)("a",{parentName:"li",href:"https://docs.cwtch.im/docs/platforms/tails"},"OnionGrater")," configuration and a new ",(0,r.kt)("inlineCode",{parentName:"li"},"CWTCH_TAILS")," environment variable that enables special Tor behaviour."))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Bug Fixes / Improvements:"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Based on Flutter 3.10"),(0,r.kt)("li",{parentName:"ul"},"Inter is now the main UI font"),(0,r.kt)("li",{parentName:"ul"},"New Font Scaling setting"),(0,r.kt)("li",{parentName:"ul"},"New Network Management code to better manage Tor on unstable networks"),(0,r.kt)("li",{parentName:"ul"},"File Sharing Experiment Fixes",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Fix performance issues for file bubble"),(0,r.kt)("li",{parentName:"ul"},"Allow restarting of file shares that have timed out"),(0,r.kt)("li",{parentName:"ul"},"Fix NPE in FileBubble caused by deleting the underlying file"),(0,r.kt)("li",{parentName:"ul"},"Move from RetVal to UpdateConversationAttributes to minimze UI thread issues"))),(0,r.kt)("li",{parentName:"ul"},"Updates to Linux install scripts to support more distributions"),(0,r.kt)("li",{parentName:"ul"},"Add a Retry Peer connection to prioritize connection attempts for certain conversations"),(0,r.kt)("li",{parentName:"ul"},"Updates to ",(0,r.kt)("inlineCode",{parentName:"li"},"_FlDartProject")," to allow custom setting of Flutter asset paths"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Accessibility / UX:"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Full translations for ",(0,r.kt)("strong",{parentName:"li"},"Brazilian Portuguese"),", ",(0,r.kt)("strong",{parentName:"li"},"Dutch"),", ",(0,r.kt)("strong",{parentName:"li"},"French"),", ",(0,r.kt)("strong",{parentName:"li"},"German"),", ",(0,r.kt)("strong",{parentName:"li"},"Italian"),", ",(0,r.kt)("strong",{parentName:"li"},"Russian"),", ",(0,r.kt)("strong",{parentName:"li"},"Polish"),", ",(0,r.kt)("strong",{parentName:"li"},"Slovak"),", ",(0,r.kt)("strong",{parentName:"li"},"Spanish"),", ",(0,r.kt)("strong",{parentName:"li"},"Swahili"),", ",(0,r.kt)("strong",{parentName:"li"},"Swedish"),", ",(0,r.kt)("strong",{parentName:"li"},"Turkish"),", and ",(0,r.kt)("strong",{parentName:"li"},"Welsh")),(0,r.kt)("li",{parentName:"ul"},"Core translations for ",(0,r.kt)("strong",{parentName:"li"},"Danish")," (75%), ",(0,r.kt)("strong",{parentName:"li"},"Norwegian")," (76%), and ",(0,r.kt)("strong",{parentName:"li"},"Romanian")," (75%)"),(0,r.kt)("li",{parentName:"ul"},"Partial translations for ",(0,r.kt)("strong",{parentName:"li"},"Japanese")," (29%), ",(0,r.kt)("strong",{parentName:"li"},"Korean")," (23%), ",(0,r.kt)("strong",{parentName:"li"},"Luxembourgish")," (22%), ",(0,r.kt)("strong",{parentName:"li"},"Greek")," (16%), and ",(0,r.kt)("strong",{parentName:"li"},"Portuguese")," (6%)")))),(0,r.kt)("h2",{id:"reproducible-bindings"},"Reproducible Bindings"),(0,r.kt)("p",null,"Cwtch 1.12 is based on libCwtch version ",(0,r.kt)("inlineCode",{parentName:"p"},"libCwtch-autobindings-2023-06-13-10-50-v0.0.5"),". The ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/blog/cwtch-bindings-reproducible#introducing-repliqate"},"repliqate scripts")," to reproduce these bindings from source can be found at ",(0,r.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.5"},"https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.5")),(0,r.kt)("h2",{id:"download-the-new-version"},"Download the New Version"),(0,r.kt)("p",null,"You can download Cwtch from ",(0,r.kt)("a",{parentName:"p",href:"https://cwtch.im/download"},"https://cwtch.im/download"),"."),(0,r.kt)("p",null,"Subscribe to our ",(0,r.kt)("a",{parentName:"p",href:"/blog/rss.xml"},"RSS feed"),", ",(0,r.kt)("a",{parentName:"p",href:"/blog/atom.xml"},"Atom feed"),", or ",(0,r.kt)("a",{parentName:"p",href:"/blog/feed.json"},"JSON feed")," to stay up to date, and get the latest on, all aspects of Cwtch development."),(0,r.kt)("p",null,"Alternatively we also provide a ",(0,r.kt)("a",{parentName:"p",href:"https://cwtch.im/releases/index.xml"},"releases-only RSS feed"),"."),(0,r.kt)("h2",{id:"help-us-go-further"},"Help us go further!"),(0,r.kt)("p",null,"We couldn't do what we do without all the wonderful community support we get, from ",(0,r.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," to ",(0,r.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,r.kt)("p",null,"If you want to see us move faster on some of these goals and are in a position to, please ",(0,r.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"donate"),". If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer."),(0,r.kt)("p",null,"Donations of ",(0,r.kt)("strong",{parentName:"p"},"$5 or more")," can opt to receive stickers as a thank-you gift!"),(0,r.kt)("p",null,"For more information about donating to Open Privacy and claiming a thank you gift ",(0,r.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate/"},"please visit the Open Privacy Donate page"),"."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"A Photo of Cwtch Stickers",src:a(4515).Z,width:"1024",height:"768"})))}h.isMDXComponent=!0},8173:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/files/picnic1.12-a06a0594d75387abb048bc8009f595b2.png"},159:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/devlog13-54310f46f23705b91f8a0a402a249ef7.png"},5726:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/picnic1.12-a06a0594d75387abb048bc8009f595b2.png"},4515:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/stickers-new-1e9b14bdd638b4907cce833e813a09ad.jpg"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a08943ae.a0db67c9.js b/build-staging/assets/js/a08943ae.a0db67c9.js new file mode 100644 index 00000000..a0a10703 --- /dev/null +++ b/build-staging/assets/js/a08943ae.a0db67c9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1800],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>d});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function c(e){for(var t=1;t =0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},l=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),u=p(n),h=r,d=u["".concat(s,".").concat(h)]||u[h]||g[h]||o;return n?a.createElement(d,c(c({ref:t},l),{},{components:n})):a.createElement(d,c({ref:t},l))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=h;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[u]="string"==typeof e?e:r,c[1]=i;for(var p=2;p {n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>c,default:()=>g,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const o={sidebar_position:1},c="Change Language",i={unversionedId:"settings/appearance/change-language",id:"settings/appearance/change-language",title:"Change Language",description:"Thanks to the help of volunteers, the Cwtch app has been translated to many languages.",source:"@site/docs/settings/appearance/change-language.md",sourceDirName:"settings/appearance",slug:"/settings/appearance/change-language",permalink:"/docs/settings/appearance/change-language",draft:!1,editUrl:"https://git.openprivacy.ca/cwtch.im/docs.cwtch.im/src/branch/staging/docs/settings/appearance/change-language.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Appearance",permalink:"/docs/category/appearance"},next:{title:"Light/Dark and themes Breakdown",permalink:"/docs/settings/appearance/light-dark-mode"}},s={},p=[],l={toc:p},u="wrapper";function g(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"change-language"},"Change Language"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/docs/contribute/translate"},"Thanks to the help of volunteers"),", the Cwtch app has been translated to many languages. "),(0,r.kt)("p",null,"To change the language Cwtch uses:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Open Settings"),(0,r.kt)("li",{parentName:"ol"},'The top setting is "Language", you can use the drop down to select the language that you wish to use.')))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a19b8c23.380ff2ab.js b/build-staging/assets/js/a19b8c23.380ff2ab.js new file mode 100644 index 00000000..ac6e5c9d --- /dev/null +++ b/build-staging/assets/js/a19b8c23.380ff2ab.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[6435],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t =0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),p=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},l="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,u=a(e,["components","mdxType","originalType","parentName"]),l=p(r),m=o,f=l["".concat(c,".").concat(m)]||l[m]||d[m]||i;return r?n.createElement(f,s(s({ref:t},u),{},{components:r})):n.createElement(f,s({ref:t},u))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,s=new Array(i);s[0]=m;var a={};for(var c in t)hasOwnProperty.call(t,c)&&(a[c]=t[c]);a.originalType=e,a[l]="string"==typeof e?e:o,s[1]=a;for(var p=2;p{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>d,frontMatter:()=>i,metadata:()=>a,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const i={sidebar_position:1},s="Servers Introduction",a={unversionedId:"servers/introduction",id:"servers/introduction",title:"Servers Introduction",description:"This feature requires Experiments Enabled and",source:"@site/docs/servers/introduction.md",sourceDirName:"servers",slug:"/servers/introduction",permalink:"/docs/servers/introduction",draft:!1,editUrl:"https://git.openprivacy.ca/cwtch.im/docs.cwtch.im/src/branch/staging/docs/servers/introduction.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Servers",permalink:"/docs/category/servers"},next:{title:"How to create a server",permalink:"/docs/servers/create-server"}},c={},p=[],u={toc:p},l="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(l,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"servers-introduction"},"Servers Introduction"),(0,o.kt)("admonition",{title:"Experiments Required",type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"This feature requires ",(0,o.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/docs/settings/introduction#experiments"},"Experiments Enabled")," and\nthe ",(0,o.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/docs/settings/experiments/server-hosting"},"Server Hosting Experiment")," turned on.")),(0,o.kt)("p",null,"Cwtch contact to contact chat is fully peer to peer, which means if one peer is offline, you cannot chat, and there is no mechanism for multiple people to chat."),(0,o.kt)("p",null,"To support group chat (and offline delivery) we have created untrusted Cwtch servers which can host messages for a group. The messages are encrypted with the group key, and fetch via ephemeral onions, so the server has no way to know what messages for what groups it might be holding, or who is accessing it."),(0,o.kt)("p",null,"Currently running servers in the Cwtch app is only supported on the Desktop version as mobile devices' internet conection and environment is too unstable and unsuitable to running a server."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a34f2ac7.72611369.js b/build-staging/assets/js/a34f2ac7.72611369.js new file mode 100644 index 00000000..65517c6a --- /dev/null +++ b/build-staging/assets/js/a34f2ac7.72611369.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[6291],{1683:e=>{e.exports=JSON.parse('{"permalink":"/blog/tags/support","page":1,"postsPerPage":10,"totalPages":1,"totalCount":3,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a430b379.8153e8a0.js b/build-staging/assets/js/a430b379.8153e8a0.js new file mode 100644 index 00000000..0c5fa200 --- /dev/null +++ b/build-staging/assets/js/a430b379.8153e8a0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1367],{8595:e=>{e.exports=JSON.parse('{"label":"repliqate","permalink":"/blog/tags/repliqate","allTagsPath":"/blog/tags","count":2}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a65a3c47.bfeca907.js b/build-staging/assets/js/a65a3c47.bfeca907.js new file mode 100644 index 00000000..97db4493 --- /dev/null +++ b/build-staging/assets/js/a65a3c47.bfeca907.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[7591],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>m});var o=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,o)}return a}function i(e){for(var t=1;t =0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o =0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var c=o.createContext({}),p=function(e){var t=o.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},s=function(e){var t=p(e.components);return o.createElement(c.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var a=e.components,n=e.mdxType,r=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),h=p(a),u=n,m=h["".concat(c,".").concat(u)]||h[u]||d[u]||r;return a?o.createElement(m,i(i({ref:t},s),{},{components:a})):o.createElement(m,i({ref:t},s))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=a.length,i=new Array(r);i[0]=u;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[h]="string"==typeof e?e:n,i[1]=l;for(var p=2;p {a.r(t),a.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var o=a(7462),n=(a(7294),a(3905));const r={title:"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.",description:"In this development log we take a look at the new Cwtch developer docs!",slug:"cwtch-developer-documentation",tags:["cwtch","cwtch-stable","developer-documentation"],image:"/img/devlog9_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},i=void 0,l={permalink:"/blog/cwtch-developer-documentation",source:"@site/blog/2023-04-28-developer-docs.md",title:"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.",description:"In this development log we take a look at the new Cwtch developer docs!",date:"2023-04-28T00:00:00.000Z",formattedDate:"April 28, 2023",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"cwtch-stable",permalink:"/blog/tags/cwtch-stable"},{label:"developer-documentation",permalink:"/blog/tags/developer-documentation"}],readingTime:2.595,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.",description:"In this development log we take a look at the new Cwtch developer docs!",slug:"cwtch-developer-documentation",tags:["cwtch","cwtch-stable","developer-documentation"],image:"/img/devlog9_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},prevItem:{title:"New Cwtch Nightly (v1.11.0-74-g0406)",permalink:"/blog/cwtch-nightly-v.11-74"},nextItem:{title:"Availability Status and Profile Attributes",permalink:"/blog/availability-status-profile-attributes"}},c={authorsImageUrls:[void 0]},p=[{value:"Cwtch Development Handbook",id:"cwtch-development-handbook",level:2},{value:"Release and Packaging Process",id:"release-and-packaging-process",level:3},{value:"Cwtch Application Development and Cwtchbot v0.1.0!",id:"cwtch-application-development-and-cwtchbot-v010",level:3},{value:"New Nightly",id:"new-nightly",level:3},{value:"Help us go further!",id:"help-us-go-further",level:2}],s={toc:p},h="wrapper";function d(e){let{components:t,...r}=e;return(0,n.kt)(h,(0,o.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"One of the larger remaining goals outlined in our ",(0,n.kt)("a",{parentName:"p",href:"/blog/cwtch-stable-roadmap-update"},"Cwtch Stable roadmap update")," is comprehensive developer documentation. We have recently spent some time writing the foundation for these documents. "),(0,n.kt)("p",null,"In this devlog we will introduce some of them, and outline the next steps. We also have a new nightly Cwtch release available for testing!"),(0,n.kt)("p",null,"We are very interested in getting feedback on these documents, and we encourage anyone who is excited to build a Cwtch Bot, or even an alternative UI, to read them over and reach out to us with comments, questions, and suggestions!"),(0,n.kt)("p",null,"As a reminder, the Open Privacy Research Society have ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/discreet-log/38-march-2023/"},"also announced they are want to raise $60,000 in 2023")," to help move forward projects like Cwtch. Please help support projects like ours with a ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," or ",(0,n.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,n.kt)("p",null,(0,n.kt)("img",{src:a(3466).Z,width:"1005",height:"481"})),(0,n.kt)("h2",{id:"cwtch-development-handbook"},"Cwtch Development Handbook"),(0,n.kt)("p",null,"We have created a new documentation section, ",(0,n.kt)("a",{parentName:"p",href:"/developing/intro"},"the developers handbook"),". This new section is targeted towards to people working on Cwtch projects (e.g. the official Cwtch library or the Cwtch UI), as well as people who want to build new Cwtch applications (e.g. chat bots or custom clients)."),(0,n.kt)("h3",{id:"release-and-packaging-process"},"Release and Packaging Process"),(0,n.kt)("p",null,"The new handbook features a breakdown of ",(0,n.kt)("a",{parentName:"p",href:"/developing/release"},"Cwtch release processes")," - describing what, and how, build artifacts are created; the difference between nightly and official builds; how the official release process works; and how reproducible build scripts are created."),(0,n.kt)("h3",{id:"cwtch-application-development-and-cwtchbot-v010"},"Cwtch Application Development and Cwtchbot v0.1.0!"),(0,n.kt)("p",null,"For the first time ever we now have ",(0,n.kt)("a",{parentName:"p",href:"/developing/category/building-a-cwtch-app"},"comprehensive documentation on how to build a Cwtch Application"),". This section of the development handbook covers everything from ",(0,n.kt)("a",{parentName:"p",href:"/developing/building-a-cwtch-app/intro#choosing-a-cwtch-library"},"choosing a Cwtch library"),", to ",(0,n.kt)("a",{parentName:"p",href:"/developing/building-a-cwtch-app/building-an-echobot"},"building your first application"),"."),(0,n.kt)("p",null,"Together with this new documentation we have also ",(0,n.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/sarah/cwtchbot"},"released version 0.1 of the Cwtchbot framework"),", updating calls to use the ",(0,n.kt)("a",{parentName:"p",href:"/blog/cwtch-stable-api-design"},"new Cwtch Stable API"),"."),(0,n.kt)("h3",{id:"new-nightly"},"New Nightly"),(0,n.kt)("p",null,"There is a ",(0,n.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies"},"new Nightly build")," are available from our build server. The latest nightly we recommend testing is ",(0,n.kt)("a",{parentName:"p",href:"https://build.openprivacy.ca/files/flwtch-2023-04-26-20-57-v1.11.0-33-gb4371/"},"2023-04-26-20-57-v1.11.0-33-gb4371"),"."),(0,n.kt)("p",null,"This version has a number of fixes and updates to the file sharing and image previews/profile pictures experiment, and an update to the ",(0,n.kt)("a",{parentName:"p",href:"/docs/platforms/tails"},"in-development Tails support"),". "),(0,n.kt)("p",null,"In addition, this nightly also includes a number of performance improvements that should fix reported rendering issues on less powerful devices."),(0,n.kt)("p",null,"Please see the contribution documentation for advice on ",(0,n.kt)("a",{parentName:"p",href:"/docs/contribute/testing#submitting-feedback"},"submitting feedback")),(0,n.kt)("p",null,"Subscribe to our ",(0,n.kt)("a",{parentName:"p",href:"/blog/rss.xml"},"RSS feed"),", ",(0,n.kt)("a",{parentName:"p",href:"/blog/atom.xml"},"Atom feed"),", or ",(0,n.kt)("a",{parentName:"p",href:"/blog/feed.json"},"JSON feed")," to stay up to date, and get the latest on, all aspects of Cwtch development."),(0,n.kt)("h2",{id:"help-us-go-further"},"Help us go further!"),(0,n.kt)("p",null,"We couldn't do what we do without all the wonderful community support we get, from ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," to ",(0,n.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,n.kt)("p",null,"If you want to see us move faster on some of these goals and are in a position to, please ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"donate"),". If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer."),(0,n.kt)("p",null,"Donations of ",(0,n.kt)("strong",{parentName:"p"},"$5 or more")," can opt to receive stickers as a thank-you gift!"),(0,n.kt)("p",null,"For more information about donating to Open Privacy and claiming a thank you gift ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate/"},"please visit the Open Privacy Donate page"),"."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"A Photo of Cwtch Stickers",src:a(4515).Z,width:"1024",height:"768"})))}d.isMDXComponent=!0},3466:(e,t,a)=>{a.d(t,{Z:()=>o});const o=a.p+"assets/images/devlog9-db5594c3b12bd5d3baf3fe06894e1a6f.png"},4515:(e,t,a)=>{a.d(t,{Z:()=>o});const o=a.p+"assets/images/stickers-new-1e9b14bdd638b4907cce833e813a09ad.jpg"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a6882456.7303ae16.js b/build-staging/assets/js/a6882456.7303ae16.js new file mode 100644 index 00000000..e36056e1 --- /dev/null +++ b/build-staging/assets/js/a6882456.7303ae16.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[4415],{3905:(t,e,n)=>{n.d(e,{Zo:()=>s,kt:()=>b});var o=n(7294);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function c(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,o)}return n}function a(t){for(var e=1;e =0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(t);for(o=0;o =0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var l=o.createContext({}),p=function(t){var e=o.useContext(l),n=e;return t&&(n="function"==typeof t?t(e):a(a({},e),t)),n},s=function(t){var e=p(t.components);return o.createElement(l.Provider,{value:e},t.children)},u="mdxType",m={inlineCode:"code",wrapper:function(t){var e=t.children;return o.createElement(o.Fragment,{},e)}},d=o.forwardRef((function(t,e){var n=t.components,r=t.mdxType,c=t.originalType,l=t.parentName,s=i(t,["components","mdxType","originalType","parentName"]),u=p(n),d=r,b=u["".concat(l,".").concat(d)]||u[d]||m[d]||c;return n?o.createElement(b,a(a({ref:e},s),{},{components:n})):o.createElement(b,a({ref:e},s))}));function b(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var c=n.length,a=new Array(c);a[0]=d;var i={};for(var l in e)hasOwnProperty.call(e,l)&&(i[l]=e[l]);i.originalType=t,i[u]="string"==typeof t?t:r,a[1]=i;for(var p=2;p {n.r(e),n.d(e,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>c,metadata:()=>i,toc:()=>p});var o=n(7462),r=(n(7294),n(3905));const c={sidebar_position:8},a="Unblocking a Contact",i={unversionedId:"chat/unblock-contact",id:"chat/unblock-contact",title:"Unblocking a Contact",description:"1. Select the contact in your Conversation list. Blocked contacts are moved to the bottom of the list.",source:"@site/docs/chat/unblock-contact.md",sourceDirName:"chat",slug:"/chat/unblock-contact",permalink:"/docs/chat/unblock-contact",draft:!1,editUrl:"https://git.openprivacy.ca/cwtch.im/docs.cwtch.im/src/branch/staging/docs/chat/unblock-contact.md",tags:[],version:"current",sidebarPosition:8,frontMatter:{sidebar_position:8},sidebar:"tutorialSidebar",previous:{title:"Blocking a Contact",permalink:"/docs/chat/block-contact"},next:{title:"Removing a Conversation",permalink:"/docs/chat/delete-contact"}},l={},p=[],s={toc:p},u="wrapper";function m(t){let{components:e,...n}=t;return(0,r.kt)(u,(0,o.Z)({},s,n,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"unblocking-a-contact"},"Unblocking a Contact"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Select the contact in your Conversation list. Blocked contacts are moved to the bottom of the list."),(0,r.kt)("li",{parentName:"ol"},"Go to Conversation Settings"),(0,r.kt)("li",{parentName:"ol"},"Scroll down to Block Contact"),(0,r.kt)("li",{parentName:"ol"},"Move the switch to Unblock Contact")),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"This documentation page is a stub. You can help\nby ",(0,r.kt)("a",{parentName:"p",href:"https://git.openprivacy.ca/cwtch.im/docs.cwtch.im"},"expanding it"),".")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a6aa9e1f.4532b4f8.js b/build-staging/assets/js/a6aa9e1f.4532b4f8.js new file mode 100644 index 00000000..876527bb --- /dev/null +++ b/build-staging/assets/js/a6aa9e1f.4532b4f8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[3089],{46:(e,t,a)=>{a.r(t),a.d(t,{default:()=>u});var n=a(7294),r=a(6010),l=a(2263),i=a(1944),o=a(5281),s=a(9058),m=a(9703),c=a(197),g=a(9985);function p(e){const{metadata:t}=e,{siteConfig:{title:a}}=(0,l.Z)(),{blogDescription:r,blogTitle:o,permalink:s}=t,m="/"===s?a:o;return n.createElement(n.Fragment,null,n.createElement(i.d,{title:m,description:r}),n.createElement(c.Z,{tag:"blog_posts_list"}))}function d(e){const{metadata:t,items:a,sidebar:r}=e;return n.createElement(s.Z,{sidebar:r},n.createElement(g.Z,{items:a}),n.createElement(m.Z,{metadata:t}))}function u(e){return n.createElement(i.FG,{className:(0,r.Z)(o.k.wrapper.blogPages,o.k.page.blogListPage)},n.createElement(p,e),n.createElement(d,e))}},9703:(e,t,a)=>{a.d(t,{Z:()=>i});var n=a(7294),r=a(5999),l=a(2244);function i(e){const{metadata:t}=e,{previousPage:a,nextPage:i}=t;return n.createElement("nav",{className:"pagination-nav","aria-label":(0,r.I)({id:"theme.blog.paginator.navAriaLabel",message:"Blog list page navigation",description:"The ARIA label for the blog pagination"})},a&&n.createElement(l.Z,{permalink:a,title:n.createElement(r.Z,{id:"theme.blog.paginator.newerEntries",description:"The label used to navigate to the newer blog posts page (previous page)"},"Newer Entries")}),i&&n.createElement(l.Z,{permalink:i,title:n.createElement(r.Z,{id:"theme.blog.paginator.olderEntries",description:"The label used to navigate to the older blog posts page (next page)"},"Older Entries"),isNext:!0}))}},9985:(e,t,a)=>{a.d(t,{Z:()=>i});var n=a(7294),r=a(9460),l=a(1286);function i(e){let{items:t,component:a=l.Z}=e;return n.createElement(n.Fragment,null,t.map((e=>{let{content:t}=e;return n.createElement(r.n,{key:t.metadata.permalink,content:t},n.createElement(a,null,n.createElement(t,null)))})))}}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a6fe627e.b2883d9a.js b/build-staging/assets/js/a6fe627e.b2883d9a.js new file mode 100644 index 00000000..66965eda --- /dev/null +++ b/build-staging/assets/js/a6fe627e.b2883d9a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[9239],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t =0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var a=n.createContext({}),c=function(e){var t=n.useContext(a),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=c(e.components);return n.createElement(a.Provider,{value:t},e.children)},l="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),l=c(r),d=o,f=l["".concat(a,".").concat(d)]||l[d]||m[d]||i;return r?n.createElement(f,s(s({ref:t},u),{},{components:r})):n.createElement(f,s({ref:t},u))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,s=new Array(i);s[0]=d;var p={};for(var a in t)hasOwnProperty.call(t,a)&&(p[a]=t[a]);p.originalType=e,p[l]="string"==typeof e?e:o,s[1]=p;for(var c=2;c{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>m,frontMatter:()=>i,metadata:()=>p,toc:()=>c});var n=r(7462),o=(r(7294),r(3905));const i={sidebar_position:1},s="Groups Experiment",p={unversionedId:"settings/experiments/group-experiment",id:"settings/experiments/group-experiment",title:"Groups Experiment",description:"Enables Cwtch to connect to untrusted servers and use them to host private, asynchronous, groups.",source:"@site/docs/settings/experiments/group-experiment.md",sourceDirName:"settings/experiments",slug:"/settings/experiments/group-experiment",permalink:"/docs/settings/experiments/group-experiment",draft:!1,editUrl:"https://git.openprivacy.ca/cwtch.im/docs.cwtch.im/src/branch/staging/docs/settings/experiments/group-experiment.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Experiments",permalink:"/docs/category/experiments"},next:{title:"Server Hosting",permalink:"/docs/settings/experiments/server-hosting"}},a={},c=[{value:"To Turn On",id:"to-turn-on",level:2}],u={toc:c},l="wrapper";function m(e){let{components:t,...r}=e;return(0,o.kt)(l,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"groups-experiment"},"Groups Experiment"),(0,o.kt)("p",null,"Enables Cwtch to ",(0,o.kt)("a",{parentName:"p",href:"/docs/servers/introduction"},"connect to untrusted servers")," and use them to ",(0,o.kt)("a",{parentName:"p",href:"/docs/groups/introduction"},"host private, asynchronous, groups"),"."),(0,o.kt)("h2",{id:"to-turn-on"},"To Turn On"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Go to Settings"),(0,o.kt)("li",{parentName:"ol"},"Enable Experiments"),(0,o.kt)("li",{parentName:"ol"},"Enable the Group experiment")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a7023ddc.b24ccc70.js b/build-staging/assets/js/a7023ddc.b24ccc70.js new file mode 100644 index 00000000..38952ed3 --- /dev/null +++ b/build-staging/assets/js/a7023ddc.b24ccc70.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1713],{3457:l=>{l.exports=JSON.parse('[{"label":"cwtch","permalink":"/blog/tags/cwtch","count":17},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable","count":17},{"label":"planning","permalink":"/blog/tags/planning","count":4},{"label":"release","permalink":"/blog/tags/release","count":2},{"label":"developer-documentation","permalink":"/blog/tags/developer-documentation","count":2},{"label":"nightly","permalink":"/blog/tags/nightly","count":1},{"label":"documentation","permalink":"/blog/tags/documentation","count":1},{"label":"security-handbook","permalink":"/blog/tags/security-handbook","count":1},{"label":"bindings","permalink":"/blog/tags/bindings","count":4},{"label":"autobindings","permalink":"/blog/tags/autobindings","count":2},{"label":"libcwtch","permalink":"/blog/tags/libcwtch","count":2},{"label":"support","permalink":"/blog/tags/support","count":3},{"label":"testing","permalink":"/blog/tags/testing","count":2},{"label":"reproducible-builds","permalink":"/blog/tags/reproducible-builds","count":2},{"label":"repliqate","permalink":"/blog/tags/repliqate","count":2},{"label":"api","permalink":"/blog/tags/api","count":1}]')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a79c88c2.e76d7c3e.js b/build-staging/assets/js/a79c88c2.e76d7c3e.js new file mode 100644 index 00000000..4adeed16 --- /dev/null +++ b/build-staging/assets/js/a79c88c2.e76d7c3e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[9976],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t =0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),s=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},h="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),h=s(a),u=r,m=h["".concat(c,".").concat(u)]||h[u]||g[u]||i;return a?n.createElement(m,o(o({ref:t},p),{},{components:a})):n.createElement(m,o({ref:t},p))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=u;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[h]="string"==typeof e?e:r,o[1]=l;for(var s=2;s{a.r(t),a.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=a(7462),r=(a(7294),a(3905));const i={title:"Cwtch Stable API Design",description:"The post outlines the technical changes we are planning on making to the core Cwtch API in preparation for Cwtch Stable ",slug:"cwtch-stable-api-design",tags:["cwtch","cwtch-stable","planning","api"],image:"/img/devlog2_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},o=void 0,l={permalink:"/blog/cwtch-stable-api-design",source:"@site/blog/2023-01-13-cwtch-stable-api-design.md",title:"Cwtch Stable API Design",description:"The post outlines the technical changes we are planning on making to the core Cwtch API in preparation for Cwtch Stable ",date:"2023-01-13T00:00:00.000Z",formattedDate:"January 13, 2023",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"cwtch-stable",permalink:"/blog/tags/cwtch-stable"},{label:"planning",permalink:"/blog/tags/planning"},{label:"api",permalink:"/blog/tags/api"}],readingTime:17.28,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Cwtch Stable API Design",description:"The post outlines the technical changes we are planning on making to the core Cwtch API in preparation for Cwtch Stable ",slug:"cwtch-stable-api-design",tags:["cwtch","cwtch-stable","planning","api"],image:"/img/devlog2_small.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},prevItem:{title:"Making Cwtch Bindings Reproducible",permalink:"/blog/cwtch-bindings-reproducible"},nextItem:{title:"Path to Cwtch Stable",permalink:"/blog/path-to-cwtch-stable"}},c={authorsImageUrls:[void 0]},s=[],p={toc:s},h="wrapper";function g(e){let{components:t,...i}=e;return(0,r.kt)(h,(0,n.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Cwtch grew out of a prototype and has been allowed to evolve over time as we discovered better ways of implementing safe and secure metadata resistant communications. "),(0,r.kt)("p",null,"As we grew, we inserted experimental functionality where it was most accessible to place - not, necessarily, where it was ultimately best to place it - this has led to some degree of overlapping, and inconsistent, responsibilities across Cwtch software packages."),(0,r.kt)("p",null,"As we move out of Beta and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.cwtch.im/blog/path-to-cwtch-stable"},"towards Cwtch Stable")," it is time to revisit these previous decisions with both the benefit of hindsight, and years of real-world testing."),(0,r.kt)("p",null,"In this post we will outline our plans for the Cwtch API that realign responsibilities, and explicitly enable new functionality to be built in a modular, controlled, and secure way. In preparation for Cwtch Stable, and beyond."),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(4867).Z,width:"1005",height:"481"})))}g.isMDXComponent=!0},4867:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/devlog2-3f3a0725dfb20a2d49da23dd84274ec2.png"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a8c7fdc6.649793e5.js b/build-staging/assets/js/a8c7fdc6.649793e5.js new file mode 100644 index 00000000..bfc808d8 --- /dev/null +++ b/build-staging/assets/js/a8c7fdc6.649793e5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1602],{6454:e=>{e.exports=JSON.parse('{"pluginId":"docs-security","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Cwtch Security Handbook","href":"/security/intro","docId":"intro"},{"type":"link","label":"Risk Model","href":"/security/risk","docId":"risk"},{"type":"category","label":"Cwtch Components","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Cwtch Technical Basics","href":"/security/components/intro","docId":"components/intro"},{"type":"link","label":"Component Ecosystem Overview","href":"/security/components/ecosystem-overview","docId":"components/ecosystem-overview"},{"type":"category","label":"Connectivity & Tor","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Connectivity","href":"/security/components/connectivity/intro","docId":"components/connectivity/intro"}],"href":"/security/category/connectivity--tor"},{"type":"category","label":"Tapir","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Packet Format","href":"/security/components/tapir/packet_format","docId":"components/tapir/packet_format"},{"type":"link","label":"Authentication Protocol","href":"/security/components/tapir/authentication_protocol","docId":"components/tapir/authentication_protocol"}],"href":"/security/category/tapir"},{"type":"category","label":"Cwtch","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Message Formats","href":"/security/components/cwtch/message_formats","docId":"components/cwtch/message_formats"},{"type":"link","label":"Key Bundles","href":"/security/components/cwtch/key_bundles","docId":"components/cwtch/key_bundles"},{"type":"link","label":"Groups","href":"/security/components/cwtch/groups","docId":"components/cwtch/groups"},{"type":"link","label":"Cwtch Server","href":"/security/components/cwtch/server","docId":"components/cwtch/server"}],"href":"/security/category/cwtch"},{"type":"category","label":"Cwtch UI","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Android Service","href":"/security/components/ui/android","docId":"components/ui/android"},{"type":"link","label":"Image Previews","href":"/security/components/ui/image_previews","docId":"components/ui/image_previews"},{"type":"link","label":"Input","href":"/security/components/ui/input","docId":"components/ui/input"},{"type":"link","label":"Message Overlays","href":"/security/components/ui/overlays","docId":"components/ui/overlays"}],"href":"/security/category/cwtch-ui"}],"href":"/security/category/cwtch-components"},{"type":"link","label":"Deployment","href":"/security/deployment","docId":"deployment"},{"type":"link","label":"Development","href":"/security/development","docId":"development"},{"type":"link","label":"References","href":"/security/references","docId":"references"}]},"docs":{"components/connectivity/intro":{"id":"components/connectivity/intro","title":"Connectivity","description":"Cwtch makes use of Tor Onion Services (v3) for all inter-node communication.","sidebar":"tutorialSidebar"},"components/cwtch/groups":{"id":"components/cwtch/groups","title":"Groups","description":"For the most part the Cwtch risk model for groups is split into two distinct","sidebar":"tutorialSidebar"},"components/cwtch/key_bundles":{"id":"components/cwtch/key_bundles","title":"Key Bundles","description":"Cwtch servers identify themselves through signed key bundles. These key bundles contain a list of keys necessary","sidebar":"tutorialSidebar"},"components/cwtch/message_formats":{"id":"components/cwtch/message_formats","title":"Message Formats","description":"Peer to Peer Messages","sidebar":"tutorialSidebar"},"components/cwtch/server":{"id":"components/cwtch/server","title":"Cwtch Server","description":"The goal of the Cwtch protocol is to enable group communication through","sidebar":"tutorialSidebar"},"components/ecosystem-overview":{"id":"components/ecosystem-overview","title":"Component Ecosystem Overview","description":"Cwtch is made up of several smaller component libraries. This chapter will provide a brief overview of","sidebar":"tutorialSidebar"},"components/intro":{"id":"components/intro","title":"Cwtch Technical Basics","description":"This page presents a brief technical overview of the Cwtch protocol.","sidebar":"tutorialSidebar"},"components/tapir/authentication_protocol":{"id":"components/tapir/authentication_protocol","title":"Authentication Protocol","description":"Each peer, given an open connection $C$:","sidebar":"tutorialSidebar"},"components/tapir/packet_format":{"id":"components/tapir/packet_format","title":"Packet Format","description":"All tapir packets are fixed length (8192 bytes) with the first 2 bytes indicated the actual length of the message,","sidebar":"tutorialSidebar"},"components/ui/android":{"id":"components/ui/android","title":"Android Service","description":"Adapted from Integrating FFI processes with Android services","sidebar":"tutorialSidebar"},"components/ui/image_previews":{"id":"components/ui/image_previews","title":"Image Previews","description":"Built on the back of filesharing in Cwtch 1.3, image previews are keyed by the suggested filename\u2019s extension (and no, we\u2019re not interested in using MIME types or magic numbers) and advertised size. If enabled, the preview system will automatically download shared images to a configured downloads folder and display them as part of the message itself. (Due to limitations on Android, they\u2019ll go to the app\u2019s private storage cache, and give you the option to save them elsewhere later instead.) The file size limit is TBD but will obviously be much lower than the overall filesharing size limit, which is currently 10 gigabytes.","sidebar":"tutorialSidebar"},"components/ui/input":{"id":"components/ui/input","title":"Input","description":"Risk: Interception of Cwtch content or metadata through an IME on Mobile Devices","sidebar":"tutorialSidebar"},"components/ui/overlays":{"id":"components/ui/overlays","title":"Message Overlays","description":"Adapted from Notes on the Cwtch Chat API","sidebar":"tutorialSidebar"},"deployment":{"id":"deployment","title":"Deployment","description":"Risk: Binaries are replaced on the website with malicious ones","sidebar":"tutorialSidebar"},"development":{"id":"development","title":"Development","description":"The main process to counter malicious actors in development of Cwtch is the","sidebar":"tutorialSidebar"},"intro":{"id":"intro","title":"Cwtch Security Handbook","description":"Welcome to the Cwtch Secure Development Handbook! The purpose of this","sidebar":"tutorialSidebar"},"references":{"id":"references","title":"References","description":"* Atwater, Erinn, and Sarah Jamie Lewis. \\"Token Based Services-Differences from Privacy Pass.\\"","sidebar":"tutorialSidebar"},"risk":{"id":"risk","title":"Risk Model","description":"Communications metadata is known to be exploited by various adversaries to","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a9159543.799d02e8.js b/build-staging/assets/js/a9159543.799d02e8.js new file mode 100644 index 00000000..a1a97156 --- /dev/null +++ b/build-staging/assets/js/a9159543.799d02e8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[5941],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>g});var n=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t =0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},c=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,o=e.originalType,p=e.parentName,c=a(e,["components","mdxType","originalType","parentName"]),u=l(r),f=i,g=u["".concat(p,".").concat(f)]||u[f]||m[f]||o;return r?n.createElement(g,s(s({ref:t},c),{},{components:r})):n.createElement(g,s({ref:t},c))}));function g(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=r.length,s=new Array(o);s[0]=f;var a={};for(var p in t)hasOwnProperty.call(t,p)&&(a[p]=t[p]);a.originalType=e,a[u]="string"==typeof e?e:i,s[1]=a;for(var l=2;l {r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>m,frontMatter:()=>o,metadata:()=>a,toc:()=>l});var n=r(7462),i=(r(7294),r(3905));const o={sidebar_position:2},s="Server Hosting",a={unversionedId:"settings/experiments/server-hosting",id:"settings/experiments/server-hosting",title:"Server Hosting",description:"Server hosting is currently an experimental feature in Cwtch, it is not enabled by default.",source:"@site/docs/settings/experiments/server-hosting.md",sourceDirName:"settings/experiments",slug:"/settings/experiments/server-hosting",permalink:"/docs/settings/experiments/server-hosting",draft:!1,editUrl:"https://git.openprivacy.ca/cwtch.im/docs.cwtch.im/src/branch/staging/docs/settings/experiments/server-hosting.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Groups Experiment",permalink:"/docs/settings/experiments/group-experiment"},next:{title:"File Sharing",permalink:"/docs/settings/experiments/file-sharing"}},p={},l=[],c={toc:l},u="wrapper";function m(e){let{components:t,...r}=e;return(0,i.kt)(u,(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"server-hosting"},"Server Hosting"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Server hosting is currently an experimental feature in Cwtch, it is not enabled by default.")),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Go to Settings"),(0,i.kt)("li",{parentName:"ol"},"Enable Experiments"),(0,i.kt)("li",{parentName:"ol"},"Enable the Server Hosting experiment"),(0,i.kt)("li",{parentName:"ol"},"You will probably also want to enable the Group experiment if you want to participate on a group hosted on your server")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/build-staging/assets/js/a9d2d00e.8d3943df.js b/build-staging/assets/js/a9d2d00e.8d3943df.js new file mode 100644 index 00000000..6b35b886 --- /dev/null +++ b/build-staging/assets/js/a9d2d00e.8d3943df.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[6126],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t =0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(r),h=o,d=u["".concat(l,".").concat(h)]||u[h]||m[h]||i;return r?n.createElement(d,a(a({ref:t},p),{},{components:r})):n.createElement(d,a({ref:t},p))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:o,a[1]=s;for(var c=2;c{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var n=r(7462),o=(r(7294),r(3905));const i={sidebar_position:4},a="Groups",s={unversionedId:"components/cwtch/groups",id:"components/cwtch/groups",title:"Groups",description:"For the most part the Cwtch risk model for groups is split into two distinct",source:"@site/security/components/cwtch/groups.md",sourceDirName:"components/cwtch",slug:"/components/cwtch/groups",permalink:"/security/components/cwtch/groups",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Key Bundles",permalink:"/security/components/cwtch/key_bundles"},next:{title:"Cwtch Server",permalink:"/security/components/cwtch/server"}},l={},c=[{value:"Risk Overview: Key Derivation",id:"risk-overview-key-derivation",level:2},{value:"Risk: Malicious Peer Leaks Group Key and/or Conversation",id:"risk-malicious-peer-leaks-group-key-andor-conversation",level:2},{value:"Risk: Active Attacks by Group Members",id:"risk-active-attacks-by-group-members",level:2},{value:"Mitigations:",id:"mitigations",level:3}],p={toc:c},u="wrapper";function m(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"groups"},"Groups"),(0,o.kt)("p",null,"For the most part the Cwtch risk model for groups is split into two distinct\nprofiles:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Groups made up of mutually trusted participants where peers are assumed\nhonest."),(0,o.kt)("li",{parentName:"ul"},"Groups consisting of strangers where peers are assumed to be potentially\nmalicious.")),(0,o.kt)("p",null,"Most of the mitigations described in this section relate to the latter case, but\nnaturally also impact the former. Even if assumed honest peers later turn\nmalicious there are mechanisms that can detect such malice and prevent it from\nhappening in the future."),(0,o.kt)("h2",{id:"risk-overview-key-derivation"},"Risk Overview: Key Derivation"),(0,o.kt)("p",null,"In the ideal case we would use a protocol like OTR, the limitations preventing\nus from doing so right now are:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Offline messages are not guaranteed to reach all peers, and as such any\nmetadata relating to key material might get lost. We need a key derivation\nprocess which is robust to missing messages or incomplete broadcast.\n")),(0,o.kt)("h2",{id:"risk-malicious-peer-leaks-group-key-andor-conversation"},"Risk: Malicious Peer Leaks Group Key and/or Conversation"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Status: Partially Mitigated (but impossible to mitigate fully)")),(0,o.kt)("p",null,"Whether dealing with trusted smaller groups or partially-public larger groups\nthere is ",(0,o.kt)("em",{parentName:"p"},"always")," the possibility that a malicious actor will leak group\nmessages."),(0,o.kt)("p",null,"We plan to make it easy for peers to ",(0,o.kt)("a",{parentName:"p",href:"#fork"},"fork")," groups to mitigate the\nsame key being used to encrypt lots of sensitive information and provide\nsome level of forward secrecy for past group conversations."),(0,o.kt)("h2",{id:"risk-active-attacks-by-group-members"},"Risk: Active Attacks by Group Members"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Status: Partially Mitigated")),(0,o.kt)("p",null,"Group members, who have access to the key material of the group, can conspire\nwith a server or other group members to break transcript consistency."),(0,o.kt)("p",null,"While we cannot directly prevent censorship given this kind of active\ncollusion, we have a number of mechanisms in place that should reveal the\npresence of censorship to honest members of the group. "),(0,o.kt)("h3",{id:"mitigations"},"Mitigations:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Because each message is signed by the peers public key, it should not be\npossible (within the cryptographic assumptions of the underlying cryptography)\nfor one group member to imitate another."),(0,o.kt)("li",{parentName:"ul"},"Each message contains a unique identifier derived from the contents and the\nprevious message hash - making it impossible for collaborators to include\nmessages from non-colluding members without revealing an implicit message\nchain (which if they were attempting to censor other messages would\nreveal such censorship)\n")),(0,o.kt)("p",null,"Finally: We are actively working on adding non-repudiation to Cwtch servers such\nthat they themselves are restricted in what they can censor efficiently."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/build-staging/assets/js/ac6c2a1e.de6fd122.js b/build-staging/assets/js/ac6c2a1e.de6fd122.js new file mode 100644 index 00000000..9b5e629d --- /dev/null +++ b/build-staging/assets/js/ac6c2a1e.de6fd122.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[8639],{6086:s=>{s.exports=JSON.parse('{"label":"support","permalink":"/blog/tags/support","allTagsPath":"/blog/tags","count":3}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/acb99df2.6a426454.js b/build-staging/assets/js/acb99df2.6a426454.js new file mode 100644 index 00000000..bdc589b4 --- /dev/null +++ b/build-staging/assets/js/acb99df2.6a426454.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[10],{1892:e=>{e.exports=JSON.parse('{"permalink":"/blog/tags/cwtch-stable","page":1,"postsPerPage":10,"totalPages":2,"totalCount":17,"nextPage":"/blog/tags/cwtch-stable/page/2","blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/af23c5f9.7089b1b0.js b/build-staging/assets/js/af23c5f9.7089b1b0.js new file mode 100644 index 00000000..10a5c9d9 --- /dev/null +++ b/build-staging/assets/js/af23c5f9.7089b1b0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[3218],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>d});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t =0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),h=p(a),m=i,d=h["".concat(s,".").concat(m)]||h[m]||u[m]||r;return a?n.createElement(d,o(o({ref:t},c),{},{components:a})):n.createElement(d,o({ref:t},c))}));function d(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[h]="string"==typeof e?e:i,o[1]=l;for(var p=2;p {a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var n=a(7462),i=(a(7294),a(3905));const r={title:"Cwtch Stable Roadmap Update",description:"Back in january we outlined several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we revisit those and announce some more",slug:"cwtch-stable-roadmap-update",tags:["cwtch","cwtch-stable","planning"],image:"/img/devlog1_small.jpg",hide_table_of_contents:!1,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},o=void 0,l={permalink:"/blog/cwtch-stable-roadmap-update",source:"@site/blog/2023-03-31-cwtch-stable-roadmap-update.md",title:"Cwtch Stable Roadmap Update",description:"Back in january we outlined several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we revisit those and announce some more",date:"2023-03-31T00:00:00.000Z",formattedDate:"March 31, 2023",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"cwtch-stable",permalink:"/blog/tags/cwtch-stable"},{label:"planning",permalink:"/blog/tags/planning"}],readingTime:5.61,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Cwtch Stable Roadmap Update",description:"Back in january we outlined several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we revisit those and announce some more",slug:"cwtch-stable-roadmap-update",tags:["cwtch","cwtch-stable","planning"],image:"/img/devlog1_small.jpg",hide_table_of_contents:!1,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},prevItem:{title:"Availability Status and Profile Attributes",permalink:"/blog/availability-status-profile-attributes"},nextItem:{title:"Cwtch Beta 1.11",permalink:"/blog/cwtch-nightly-1-11"}},s={authorsImageUrls:[void 0]},p=[{value:"Update on the January Roadmap",id:"update-on-the-january-roadmap",level:2},{value:"A Timeline for Cwtch Stable",id:"a-timeline-for-cwtch-stable",level:2},{value:"Get Involved",id:"get-involved",level:2},{value:"Help us go further!",id:"help-us-go-further",level:2}],c={toc:p},h="wrapper";function u(e){let{components:t,...r}=e;return(0,i.kt)(h,(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"The next large step for the Cwtch project to take is a move from public ",(0,i.kt)("strong",{parentName:"p"},"Beta")," to ",(0,i.kt)("strong",{parentName:"p"},"Stable")," \u2013 marking a point at which we consider Cwtch to be secure and usable. We have been working hard towards that goal over the last few months."),(0,i.kt)("p",null,"This post ",(0,i.kt)("a",{parentName:"p",href:"/blog/path-to-cwtch-stable"},"revisits the Cwtch Stable roadmap")," we introduced at the start of the year, and provides an overview of the next steps on our journey towards Cwtch Stable."),(0,i.kt)("p",null,(0,i.kt)("img",{src:a(9469).Z,width:"1005",height:"480"})),(0,i.kt)("h2",{id:"update-on-the-january-roadmap"},"Update on the January Roadmap"),(0,i.kt)("p",null,"Back in January we outlined several goals that we would have to hit on our way to Cwtch Stable, and the timelines for achieving them. Now that we have reached target date of the last of these goals, we can look back and see how we did:"),(0,i.kt)("p",null,"(\u2705 means complete, \ud83d\udfe1 means in-progress, \u274c not started.)"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"1st February 2023"),", the Cwtch team will have reviewed all existing Cwtch issues in line with this document, and established a timeline for including them in upcoming releases (or specifically commit to not including them in upcoming releases). \u2705"),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"1st February 2023"),", the Cwtch team will have ",(0,i.kt)("a",{parentName:"li",href:"/blog/cwtch-stable-api-design"},"finalized a feature set that defines Cwtch Stable")," and established a timeline for including these features in upcoming Cwtch Beta releases. \u2705"),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"1st February 2023"),", the Cwtch team will have expanded the Cwtch Documentation website to include a section for:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/security/intro"},"Security and Design Documents")," \u2705"),(0,i.kt)("li",{parentName:"ul"},"Infrastructure and ",(0,i.kt)("a",{parentName:"li",href:"/docs/getting-started/supported_platforms"},"Support")," \ud83d\udfe1"),(0,i.kt)("li",{parentName:"ul"},"in addition to a new development blog. \u2705"))),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"31st March 2023"),", the Cwtch team will have created:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"a ",(0,i.kt)("a",{parentName:"li",href:"/docs/contribute/documentation"},"style guide for documentation"),", and \u2705"),(0,i.kt)("li",{parentName:"ul"},"have used it to ensure that all Cwtch features have consistent documentation available, \ud83d\udfe1"),(0,i.kt)("li",{parentName:"ul"},"with at least one screenshot (where applicable). \ud83d\udfe1"))),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"31st March 2023")," the Cwtch team will have published: ",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"a Cwtch ",(0,i.kt)("a",{parentName:"li",href:"/blog/cwtch-stable-api-design"},"Interface Specification Document")," \u2705"),(0,i.kt)("li",{parentName:"ul"},"a Cwtch Release Process Document \ud83d\udfe1"),(0,i.kt)("li",{parentName:"ul"},"a Cwtch ",(0,i.kt)("a",{parentName:"li",href:"/blog/cwtch-platform-support"},"Support Plan document")," \u2705"),(0,i.kt)("li",{parentName:"ul"},"a Cwtch Packaging Document \ud83d\udfe1"),(0,i.kt)("li",{parentName:"ul"},"a document describing the ",(0,i.kt)("a",{parentName:"li",href:"/blog/cwtch-bindings-reproducible"},"Reproducible Builds Process")," \u2705"),(0,i.kt)("li",{parentName:"ul"},"These documents will be available on the newly expanded Cwtch Documentation website \ud83d\udfe1"))),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"31st March 2023")," the Cwtch team will have integrated automated UI tests into the build pipeline for the cwtch-ui repository. \u2705"),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"31st March 2023")," the Cwtch team will have integrated automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team \u274c"),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"31st March 2023")," the Cwtch team will have committed to a date, timeline, and roadmap for launching Cwtch Stable \u2705 (this post!)")),(0,i.kt)("p",null,"While we didn't hit all of our goals, we did make progress on nearly all of them, and in addition also made progress in a few other key areas:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/blog/autobindings"},"Cwtch Autobindings")," with ",(0,i.kt)("a",{parentName:"li",href:"/blog/autobindings-ii"},"compile-time optional experiments")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/blog/cwtch-nightly-1-11"},"Cwtch 1.11")," - with support for reproducible bindings, two new localizations (Slovak and Korean), in addition to a myriad of bug fixes and performance improvements."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://git.openprivacy.ca/openprivacy/repliqate"},"Repliqate")," - a tool for testing and confirming reproducible builds processes based on Qemu, and a Debian Cloud image.")),(0,i.kt)("h2",{id:"a-timeline-for-cwtch-stable"},"A Timeline for Cwtch Stable"),(0,i.kt)("p",null,"Now for the big news, we plan on releasing a candidate Cwtch Stable release during ",(0,i.kt)("strong",{parentName:"p"},"Summer 2023"),". Here is our plan for getting there:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"30th April 2023")," the Cwtch team will have written the remaining outstanding documentation from the January roadmap including:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"A Cwtch Release Process Document"),(0,i.kt)("li",{parentName:"ul"},"A Cwtch Packaging Document"),(0,i.kt)("li",{parentName:"ul"},"Completion of documentation of existing Cwtch features, including relevant screenshots."))),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"30th April 2023")," the Cwtch team will have also released developer-centric documentation including:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"A guide to building Cwtch-apps using official libraries"),(0,i.kt)("li",{parentName:"ul"},"Automatically generated API documentation for libCwtch"))),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"30th June 2023")," the Cwtch team will have released new Cwtch Beta releases (1.12+) featuring:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"An implementation of ",(0,i.kt)("a",{parentName:"li",href:"https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/129"},"Conversation Search")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/27"},"Profile statuses")," and other associated information"),(0,i.kt)("li",{parentName:"ul"},"An update to the network handling code to allow for ",(0,i.kt)("a",{parentName:"li",href:"https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/593"},"better Protocol Engine management")))),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"31st July 2023")," the Cwtch team will have completed several infrastructure upgrades including:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Extended reproducible builds to cover the Cwtch UI, or document where the blockers to achieving this exist."),(0,i.kt)("li",{parentName:"ul"},"Integration of automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team"),(0,i.kt)("li",{parentName:"ul"},"New testing environments for F-droid, Whonix, Raspberry Pi and other ",(0,i.kt)("a",{parentName:"li",href:"/docs/getting-started/supported_platforms"},"partially supported systems")))),(0,i.kt)("li",{parentName:"ul"},"By ",(0,i.kt)("strong",{parentName:"li"},"31st August 2023")," the Cwtch team will have a released Cwtch Stable Release Candidate:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"At this point we expect that the Cwtch application and existing documentation will be robust and complete enough to be labelled as stable."),(0,i.kt)("li",{parentName:"ul"},"Along with this label comes a higher standard for how we consider all aspects of Cwtch development. The work we have done up to this point reflects a much stronger development pipeline, and an ongoing commitment to security."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"This does not mark an end to Cwtch development"),", or new Cwtch features. But it does denote the point at which we consider Cwtch to be appropriate for wider use.")))),(0,i.kt)("p",null,"This is not all we have planned for the upcoming months. Subscribe to our ",(0,i.kt)("a",{parentName:"p",href:"/blog/rss.xml"},"RSS feed"),", ",(0,i.kt)("a",{parentName:"p",href:"/blog/atom.xml"},"Atom feed"),", or ",(0,i.kt)("a",{parentName:"p",href:"/blog/feed.json"},"JSON feed")," to stay up to date, and get the latest on, all aspects of Cwtch development."),(0,i.kt)("h2",{id:"get-involved"},"Get Involved"),(0,i.kt)("p",null,"We have noticed an uptick in the number of people reaching out interested in contributing to Cwtch development. In order to help people get acclimated to our development flow we have created a new section on the main documentation site called ",(0,i.kt)("a",{parentName:"p",href:"/docs/contribute/developing"},"Developing Cwtch")," - there you will find a collection of useful links and information about how to get started with Cwtch development, what libraries and tools we use, how pull requests are validated and verified, and how to choose an issue to work on."),(0,i.kt)("p",null,"We also also updated our guides on ",(0,i.kt)("a",{parentName:"p",href:"/docs/contribute/translate"},"Translating Cwtch")," and ",(0,i.kt)("a",{parentName:"p",href:"/docs/contribute/testing"},"Testing Cwtch"),"."),(0,i.kt)("p",null,"If you are interested in getting started with Cwtch development then please check it out, and feel free to reach out to ",(0,i.kt)("inlineCode",{parentName:"p"},"team@cwtch.im")," (or open an issue) with any questions. All types of contributions ",(0,i.kt)("a",{parentName:"p",href:"/docs/contribute/stickers"},"are eligible for stickers"),"."),(0,i.kt)("h2",{id:"help-us-go-further"},"Help us go further!"),(0,i.kt)("p",null,"We couldn't do what we do without all the wonderful community support we get, from ",(0,i.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," to ",(0,i.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,i.kt)("p",null,"If you want to see us move faster on some of these goals and are in a position to, please ",(0,i.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"donate"),". If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer."),(0,i.kt)("p",null,"Donations of ",(0,i.kt)("strong",{parentName:"p"},"$5 or more")," can opt to receive stickers as a thank-you gift!"),(0,i.kt)("p",null,"For more information about donating to Open Privacy and claiming a thank you gift ",(0,i.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate/"},"please visit the Open Privacy Donate page"),"."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"A Photo of Cwtch Stickers",src:a(4515).Z,width:"1024",height:"768"})))}u.isMDXComponent=!0},9469:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/devlog1-53937adbfa7a7edf40d34660f71ed0fd.png"},4515:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/stickers-new-1e9b14bdd638b4907cce833e813a09ad.jpg"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/b0404c31.48ec076b.js b/build-staging/assets/js/b0404c31.48ec076b.js new file mode 100644 index 00000000..d03b0dfe --- /dev/null +++ b/build-staging/assets/js/b0404c31.48ec076b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[7860],{3905:(e,t,a)=>{a.d(t,{Zo:()=>h,kt:()=>m});var n=a(7294);function o(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t =0||(o[a]=e[a]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,a)&&(o[a]=e[a])}return o}var s=n.createContext({}),c=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},h=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,h=l(e,["components","mdxType","originalType","parentName"]),p=c(a),u=o,m=p["".concat(s,".").concat(u)]||p[u]||d[u]||i;return a?n.createElement(m,r(r({ref:t},h),{},{components:a})):n.createElement(m,r({ref:t},h))}));function m(e,t){var a=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=a.length,r=new Array(i);r[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:o,r[1]=l;for(var c=2;c{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var n=a(7462),o=(a(7294),a(3905));const i={title:"Path to Cwtch Stable",description:"The post outlines the general principles that are guiding the development of Cwtch Stable, the obstacles that prevent a stable Cwtch release, and closes with an overview the next steps and a timeline to tackle them.",slug:"path-to-cwtch-stable",tags:["cwtch","cwtch-stable","planning"],image:"/img/devlog1_small.jpg",hide_table_of_contents:!1,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},r=void 0,l={permalink:"/blog/path-to-cwtch-stable",source:"@site/blog/2023-01-06-path-to-cwtch-stable.md",title:"Path to Cwtch Stable",description:"The post outlines the general principles that are guiding the development of Cwtch Stable, the obstacles that prevent a stable Cwtch release, and closes with an overview the next steps and a timeline to tackle them.",date:"2023-01-06T00:00:00.000Z",formattedDate:"January 6, 2023",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"cwtch-stable",permalink:"/blog/tags/cwtch-stable"},{label:"planning",permalink:"/blog/tags/planning"}],readingTime:9.995,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Path to Cwtch Stable",description:"The post outlines the general principles that are guiding the development of Cwtch Stable, the obstacles that prevent a stable Cwtch release, and closes with an overview the next steps and a timeline to tackle them.",slug:"path-to-cwtch-stable",tags:["cwtch","cwtch-stable","planning"],image:"/img/devlog1_small.jpg",hide_table_of_contents:!1,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},prevItem:{title:"Cwtch Stable API Design",permalink:"/blog/cwtch-stable-api-design"}},s={authorsImageUrls:[void 0]},c=[{value:"Tenets of Cwtch Stable",id:"tenets-of-cwtch-stable",level:3},{value:"Known Problems",id:"known-problems",level:3},{value:"Plan of Action",id:"plan-of-action",level:3},{value:"Goals and Timelines",id:"goals-and-timelines",level:3},{value:"Help us get there!",id:"help-us-get-there",level:3}],h={toc:c},p="wrapper";function d(e){let{components:t,...i}=e;return(0,o.kt)(p,(0,n.Z)({},h,i,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"As of December 2022 we have released 10 versions of Cwtch Beta since the ",(0,o.kt)("a",{parentName:"p",href:"https://openprivacy.ca/discreet-log/10-cwtch-beta-and-beyond/"},"initial launch, 18 months ago, in June 2021"),"."),(0,o.kt)("p",null,"There is a consensus among the team that the next large step for the Cwtch project to take is a move from public ",(0,o.kt)("strong",{parentName:"p"},"Beta")," to ",(0,o.kt)("strong",{parentName:"p"},"Stable")," \u2013 marking a point at which we consider Cwtch to be secure and usable."),(0,o.kt)("p",null,"This post outlines the general principles that are guiding the development of Cwtch Stable, the obstacles that prevent a stable Cwtch release, and closes with an overview of the next steps and our timeline for tackling them."),(0,o.kt)("p",null,(0,o.kt)("img",{src:a(9469).Z,width:"1005",height:"480"})),(0,o.kt)("h3",{id:"tenets-of-cwtch-stable"},"Tenets of Cwtch Stable"),(0,o.kt)("p",null,"It is important to state that Cwtch Stable ",(0,o.kt)("strong",{parentName:"p"},"does not mean an end to Cwtch development"),". Rather, it establishes a baseline at which point Cwtch is considered to be a fully supported project. The Cwtch Team have set the following tenets that guide our decision-making and priorities:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Consistent Interface")," \u2013 each new Cwtch release should be accompanied by consistent releases to all support libraries. This requires a stable and documented API so that we can be clear when upgrading a library will result in breaking change for downstream projects. We should not, as a general rule, have to make breaking changes to this API interface in order to support new experimental features."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Universal Availability and Cohesive Support")," \u2013 people who use Cwtch understand that if Cwtch is available for a platform then that means all features will work as expected, that there are no surprise limitations, and any differences are well documented. People should not have to go out of their way to install Cwtch."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Reproducible Builds")," \u2013 Cwtch builds should be trivially reproducible, including the ability to reproduce all bundled assets. Reproducibility should not rely on containerization, but all containers used in our build process should be reproducible."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Proven Security")," \u2013 we can demonstrate that Cwtch provides first class security through well documented design, testing, and audit procedures. We should be able to do this for Cwtch in addition to all functional dependencies.")),(0,o.kt)("h3",{id:"known-problems"},"Known Problems"),(0,o.kt)("p",null,"To begin, let's outline the current state of Cwtch and lay out the issues that stand in the way of Cwtch Stable."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Lack of a Stable API for future feature development")," \u2013 while the core Cwtch API has remained fairly unchanged in recent releases we understand that the addition of new features e.g. cohesive group support likely requires new API hooks that allow safe manipulation of Cwtch Profile (transactional semantics and post-event hooks). Before we can even consider a stable release we need to define what this API should look like, and implement it. (Tenet 1)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Special functionality in libCwtch-go")," \u2013 our C-API bridge (libCwtch-go) currently implements a lot of special functionality in support for both experimental features (e.g. profile images) and UI settings. This special behaviour makes it difficult to track feature responsibility. This behaviour must either be pushed back into the main Cwtch library, or defined to be the responsibility of a downstream application e.g. Cwtch UI. (Tenet 1)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"libCwtch-rs partial support")," - we currently do not officially consider ",(0,o.kt)("a",{parentName:"li",href:"https://lib.rs/crates/libcwtch"},"libCwtch-rs")," when updating libCwtch-go as part of our release schedule. Before we can consider a Cwtch Stable release we should have multiple beta releases where libCwtch-rs has full support for any and all new Cwtch features. (Tenet 1, Tenet 2)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Lack of Reproducible Pipelines")," - while the vast majority of our build pipeline is automated, containerized, and reproducible, there remain bundled assets that cannot be trivially constructed, and assets that have non-reproducible elements (e.g. build-time injected via git tags, and go binaries including build user information). (Tenet 3)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Lack of up to date, and translated, Security Documentation")," \u2013 the ",(0,o.kt)("a",{parentName:"li",href:"https://docs.openprivacy.ca/cwtch-security-handbook/"},"Cwtch security handbook")," is currently isolated from the rest of our documentation and doesn\u2019t benefit from cross-linking, or translations. (Tenet 4)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"No Automated UI Tests")," \u2013 we put a lot of work into ",(0,o.kt)("a",{parentName:"li",href:"https://openprivacy.ca/discreet-log/23-cucumber-testing/"},"building out a testing framework for the UI"),", but it currently sits mostly unused, and unexercised in our build pipelines. We should revisit that work. (Tenet 4)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Code Signing Provider")," \u2013 our previous code signing certificate provider had support issues, and we have not yet decided on a replacement. ( Tenet 4)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Second-class Android Support")," - while we have put ",(0,o.kt)("a",{parentName:"li",href:"https://openprivacy.ca/discreet-log/27-android-improvements/"},"a lot of effort behind Android support")," across the Beta timeline, it still clearly suffers from additional issues that desktop editions do not. In order to consider Cwtch stable we must resolve all major bugs impacting Android usability. (Tenet 2)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Lack of Fuzzing")," \u2013 while ",(0,o.kt)("a",{parentName:"li",href:"https://openprivacy.ca/discreet-log/07-fuzzbot/"},"Fuzzbot")," sets a standard high above most other secure communication applications, we can and should do better. Fuzzbot currently only targets user-endpoint messages, which are the most likely to result in real-world risk, but we should strive to have the same coverage for internal events at both the network level, the internal Cwtch App level, and the event bus level. (Tenet 4)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Lack of Formal Release Acceptance Process")," \u2013 currently the features and experiments that get included in each release are determined in an ad-hoc consensus. This occasionally means that some features are left unsupported on certain platforms, and bugs occasionally arise in platforms (Android in particular) due to \u201cunrelated\u201d changes. In order for Cwtch to be declared stable, a formal acceptance process must ensure that new changes do not break existing features, and that they work across all platforms. (Tenet2, Tenet 4)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Inconsistent Cwtch Information Discovery")," \u2013 our current documentation is split between docs.cwtch.im, cwtch.im and docs.openprivacy.ca, in additional to blogs on Discreet Log. This makes it difficult for people to learn about Cwtch, and also means that our own explanations often must link across multiple different sites. (Tenet 2)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Incomplete Documentation")," \u2013 docs.cwtch.im was very well received. However, it still suffers from incomplete sections, missing links, and an overall lack of screenshots. What screenshots there are lack consistency in sizing, style, and feel. (Tenet 2)")),(0,o.kt)("h3",{id:"plan-of-action"},"Plan of Action"),(0,o.kt)("p",null,"Outside of the problems that have standalone solutions (e.g. find a new code signing provider, or fix all Android issues), there are a number of higher level activities that need to be completed before we can be confident in a Cwtch Stable release:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Define, Publish, and Implement a Cwtch Interface Specification Documentation")," \u2013 this should include examples of how new (experimental) behaviour might be implemented from finer-grained composition. Must include moving all special functionality out of libCwtch-go. Should be followed up by implementing the proposed design. (Tenet 1, Tenet 4)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Define, Publish, and Implement a Cwtch Release Process")," \u2013 this document should outline the criteria for publishing a new release, the difference between major and minor versions, how features are tested, how regressions are caught before release, and who is responsible for different parts of the process. (Tenet 2)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Define, Publish, and Implement a Cwtch Support Document")," - including answers to the questions: what systems do we support, how do we decide what systems are supported, how do we handle new OS versions, and how does application support differ from library support. This should also include a list of blockers for systems we wish to support, but currently cannot e.g ios. (Tenet 2)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Define, Publish, and Implement a Cwtch Packaging Document")," - as a supplement to the Support document we need to define what packaging we support, in addition to what app stores and managers for which we provide official releases. ( Tenet 2)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Define, Publish, and Implement a Reproducible Builds Document")," \u2013 this should cover not only Cwtch binaries, but also Docker containers, and included assets (e.g. Tor binaries). Followed up by implementing the plan into our build pipeline. ( Tenet 3)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Expand the Cwtch Documentation Site")," \u2013 to include the Security Handbook, development blogs, design documentation, and support plans. This should be our only publishing platform, outside of a landing page, and downloads on cwtch.im. This expansion should include a style guide for documentation and screenshots to ensure that we maintain consistent language and visuals when talking about a feature (e.g. we should use the same profile image style, theme, profile names, message style etc.) (Tenet 1, Tenet 2, Tenet 3, Tenet 4)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Expand our Automated Testing to include UI and Fuzzing")," - integrate UI automated tests into our build pipeline. Expand our fuzzing to include the event bus, and PeerApp packets. Finally, integrate automated fuzzing into the build pipeline, so that all new features are fuzzed to the same level. (Tenet 4)"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Re-evaluate all Issues across all Cwtch related repositories")," \u2013 issues are either bugs that need to be fixed before stable (i.e. they are in service of one of the Tenets), new feature ideas that should be scheduled around stable work (i.e. they don\u2019t align with a specific Tenet), or support requests for systems that need input from the Support and Packaging Plans."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Define a Stable Feature Set")," \u2013 there are still a few features which do not exist in Cwtch Beta which would be required for a stable release, such as chat search. Following on from the Cwtch Interface Specification Document, the team should decide what features Cwtch Stable will target, and these features should be prioritized for inclusion in Cwtch 1.11, Cwtch 1.12 and any future Beta releases. (Tenet 1)")),(0,o.kt)("h3",{id:"goals-and-timelines"},"Goals and Timelines"),(0,o.kt)("p",null,"With all of that laid out, we are now ready to introduce a timeline for resolving some of these problems, and moving us towards a state where we can launch Cwtch Stable:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"By ",(0,o.kt)("strong",{parentName:"li"},"1st February 2023"),", the Cwtch team will have reviewed all existing Cwtch issues in line with this document, and established a timeline for including them in upcoming releases (or specifically commit to not including them in upcoming releases)."),(0,o.kt)("li",{parentName:"ol"},"By ",(0,o.kt)("strong",{parentName:"li"},"1st February 2023"),", the Cwtch team will have finalized a feature set that defines Cwtch Stable and established a timeline for including these features in upcoming Cwtch Beta releases."),(0,o.kt)("li",{parentName:"ol"},"By ",(0,o.kt)("strong",{parentName:"li"},"1st February 2023"),", the Cwtch team will have expanded the Cwtch Documentation website to include a section for Security, Design Documents, Infrastructure and Support, in addition to a new development blog."),(0,o.kt)("li",{parentName:"ol"},"By ",(0,o.kt)("strong",{parentName:"li"},"31st March 2023"),", the Cwtch team will have created a style guide for documentation and have used it to ensure that all Cwtch features have consistent documentation available, with at least one screenshot (where applicable)."),(0,o.kt)("li",{parentName:"ol"},"By ",(0,o.kt)("strong",{parentName:"li"},"31st March 2023")," the Cwtch team will have published a Cwtch Interface Specification Document, a Cwtch Release Process Document, a Cwtch Support Plan document, a Cwtch Packaging Document, and a document describing the Reproducible Builds Process. These documents will be available on the newly expanded Cwtch Documentation website."),(0,o.kt)("li",{parentName:"ol"},"By ",(0,o.kt)("strong",{parentName:"li"},"31st March 2023")," the Cwtch team will have integrated automated UI tests into the build pipeline for the cwtch-ui repository."),(0,o.kt)("li",{parentName:"ol"},"By ",(0,o.kt)("strong",{parentName:"li"},"31st March 2023")," the Cwtch team will have integrated automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team."),(0,o.kt)("li",{parentName:"ol"},"By ",(0,o.kt)("strong",{parentName:"li"},"31st March 2023")," the Cwtch team will have committed to a date, timeline, and roadmap for launching Cwtch Stable.")),(0,o.kt)("p",null,"As these documents are written, and these goals met we will be posting them here! Subscribe to our ",(0,o.kt)("a",{parentName:"p",href:"/blog/rss.xml"},"RSS feed"),", ",(0,o.kt)("a",{parentName:"p",href:"/blog/atom.xml"},"Atom feed"),", or ",(0,o.kt)("a",{parentName:"p",href:"/blog/feed.json"},"JSON feed")," to stay up to date, and get the latest on, Cwtch development."),(0,o.kt)("h3",{id:"help-us-get-there"},"Help us get there!"),(0,o.kt)("p",null,"We couldn't do what we do without all the wonderful community support we get, from ",(0,o.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," to ",(0,o.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,o.kt)("p",null,"If you want to see us move faster on some of these goals and are in a position, please ",(0,o.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"donate"),". If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer."),(0,o.kt)("p",null,"Donations of ",(0,o.kt)("strong",{parentName:"p"},"$5 or more")," can opt to receive stickers as a thank-you gift!"),(0,o.kt)("p",null,"For more information about donating to Open Privacy and claiming a thank you gift ",(0,o.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate/"},"please visit the Open Privacy Donate page"),"."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"A Photo of Cwtch Stickers",src:a(4515).Z,width:"1024",height:"768"})))}d.isMDXComponent=!0},9469:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/devlog1-53937adbfa7a7edf40d34660f71ed0fd.png"},4515:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/stickers-new-1e9b14bdd638b4907cce833e813a09ad.jpg"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/b125d866.72e91b4f.js b/build-staging/assets/js/b125d866.72e91b4f.js new file mode 100644 index 00000000..ce83a038 --- /dev/null +++ b/build-staging/assets/js/b125d866.72e91b4f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[8799],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>m});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t =0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r