From a9d1f535aa4e340d78a800feea15cf4d59c951de Mon Sep 17 00:00:00 2001 From: Christian Nennemann Date: Fri, 6 Mar 2026 20:51:30 +0100 Subject: [PATCH] chore: prepare repository for public release - Add split licensing: AGPL-3.0 for server, Apache-2.0/MIT for all other crates and SDKs (Signal-style) - Add SECURITY.md with vulnerability disclosure policy - Add CONTRIBUTING.md with build, test, and code standards - Add "not audited" security disclaimer to README - Add workspace package metadata (license, repository, keywords) - Move internal planning docs to docs/internal/ (gitignored) --- .gitignore | 3 + CONTRIBUTING.md | 40 ++ Cargo.toml | 8 + LICENSE | 30 ++ LICENSE-AGPL-3.0 | 661 ++++++++++++++++++++++++ LICENSE-APACHE | 199 +++++++ LICENSE-MIT | 21 + README.md | 6 +- SECURITY.md | 29 ++ crates/quicproquo-client/Cargo.toml | 5 +- crates/quicproquo-core/Cargo.toml | 5 +- crates/quicproquo-kt/Cargo.toml | 5 +- crates/quicproquo-p2p/Cargo.toml | 5 +- crates/quicproquo-plugin-api/Cargo.toml | 5 +- crates/quicproquo-proto/Cargo.toml | 4 +- crates/quicproquo-rpc/Cargo.toml | 4 +- crates/quicproquo-sdk/Cargo.toml | 4 +- crates/quicproquo-server/Cargo.toml | 5 +- docs/AGENT-TEAM.md | 483 ----------------- docs/MULTI-AGENT-WORK-PLAN.md | 106 ---- docs/REVIEW-2026-03-04.md | 317 ------------ docs/SPRINT-PLAN-NEXT.md | 175 ------- docs/V2-DESIGN-ANALYSIS.md | 380 -------------- docs/V2-MASTER-PLAN.md | 328 ------------ 24 files changed, 1020 insertions(+), 1808 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 LICENSE-AGPL-3.0 create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 SECURITY.md delete mode 100644 docs/AGENT-TEAM.md delete mode 100644 docs/MULTI-AGENT-WORK-PLAN.md delete mode 100644 docs/REVIEW-2026-03-04.md delete mode 100644 docs/SPRINT-PLAN-NEXT.md delete mode 100644 docs/V2-DESIGN-ANALYSIS.md delete mode 100644 docs/V2-MASTER-PLAN.md diff --git a/.gitignore b/.gitignore index e651bd5..33a57a4 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ data/ *.convdb-wal *.pending.ks qpq-server.toml + +# Internal planning docs (not for public distribution) +docs/internal/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3560a33 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,40 @@ +# Contributing to quicproquo + +## Prerequisites + +- **Rust toolchain** (stable) via [rustup](https://rustup.rs/) +- **protoc** is vendored via the `protobuf-src` crate -- no system installation needed +- Git with GPG signing configured + +## Building and Testing + +```sh +cargo build --workspace +cargo test --workspace +``` + +A `justfile` is also available for common tasks (`just build`, `just test`, `just proto`, etc.). + +## Code Standards + +### Commits + +- **Conventional commits**: `feat:`, `fix:`, `docs:`, `chore:`, `test:`, `refactor:` +- Commits must be **GPG-signed** +- Commit messages describe *why*, not just *what* +- No `Co-authored-by` trailers + +### Rust + +- No `.unwrap()` on crypto or I/O operations outside of tests +- Secrets must be zeroized on drop and never logged +- No stubs, `todo!()`, or `unimplemented!()` in production code +- Prefer clarity over cleverness; avoid unnecessary abstractions + +## Security Vulnerabilities + +Do not open public issues for security bugs. See [SECURITY.md](SECURITY.md) for responsible disclosure instructions. + +## Licensing + +The server crate (`quicproquo-server`) is licensed under **AGPL-3.0**. All other crates are dual-licensed under **Apache-2.0 / MIT**. By submitting a contribution, you agree to license your work under the applicable license(s). diff --git a/Cargo.toml b/Cargo.toml index da71d7e..99823cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,14 @@ members = [ "crates/quicproquo-p2p", ] +[workspace.package] +edition = "2021" +rust-version = "1.75" +repository = "https://github.com/quicproquo/quicproquo" +description = "End-to-end encrypted group messaging over QUIC" +keywords = ["encryption", "messaging", "quic", "mls", "post-quantum"] +categories = ["cryptography", "network-programming"] + # Shared dependency versions — bump here to affect the whole workspace. [workspace.dependencies] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..06b825f --- /dev/null +++ b/LICENSE @@ -0,0 +1,30 @@ +quicproquo — Split Licensing +============================ + +This project uses a split license model similar to Signal: + +Server (quicproquo-server) +-------------------------- +Licensed under the GNU Affero General Public License v3.0 only. +See LICENSE-AGPL-3.0 for the full text. + + SPDX-License-Identifier: AGPL-3.0-only + +Libraries and SDKs (all other crates) +-------------------------------------- +Licensed under either of + + * Apache License, Version 2.0 (LICENSE-APACHE) + * MIT License (LICENSE-MIT) + +at your option. + + SPDX-License-Identifier: Apache-2.0 OR MIT + +Contribution +------------ +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in this project by you, as defined in the +Apache-2.0 license, shall be dual licensed as above (for library crates) +or AGPL-3.0-only (for the server crate), without any additional terms or +conditions. diff --git a/LICENSE-AGPL-3.0 b/LICENSE-AGPL-3.0 new file mode 100644 index 0000000..be3f7b2 --- /dev/null +++ b/LICENSE-AGPL-3.0 @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..46e852f --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,199 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to the Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by the Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding any notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. Please also get an + OpenPGP-compatible signature on any file you distribute. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..a140f0f --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) quicproquo contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 77d529e..d678a02 100644 --- a/README.md +++ b/README.md @@ -210,11 +210,9 @@ mdbook serve docs # http://localhost:3000 - [Scaling Guide](docs/operations/scaling-guide.md) — resource sizing, horizontal scaling, capacity planning - [Monitoring](docs/operations/monitoring.md) — Prometheus metrics, Grafana dashboards, alert rules -## Security +## Security Status -This project has **not undergone a formal third-party audit**. See the [threat model](docs/src/cryptography/threat-model.md) for details. - -If you discover a security vulnerability, please report it privately. +> **This software has not undergone an independent security audit.** While it implements cryptographic best practices (MLS RFC 9420, OPAQUE, zeroization, constant-time comparisons), no third-party firm has reviewed the implementation. Do not rely on it for high-risk communications until an audit is completed. See [SECURITY.md](SECURITY.md) for our vulnerability disclosure policy. ## License diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..96cc1d7 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,29 @@ +# Security Policy + +## Supported Versions + +Only the current `main` branch is supported with security updates. + +## Reporting a Vulnerability + +**Do not use public GitHub issues to report security vulnerabilities.** + +Instead, email **security@quicproquo.org** with: + +- A description of the vulnerability +- Steps to reproduce or a proof of concept +- The affected component(s) and potential impact + +We will acknowledge your report within **48 hours** and work with you on a fix under a **90-day coordinated disclosure** timeline. + +## What Qualifies + +- Cryptographic implementation bugs (MLS, Noise, hybrid KEM, key derivation) +- Authentication or authorization bypass +- Key material leakage (memory, logs, network) +- Protocol-level flaws (replay, downgrade, impersonation) +- Any issue that compromises message confidentiality or integrity + +## Credit + +Reporters are credited in published security advisories unless they prefer to remain anonymous. Let us know your preference when you report. diff --git a/crates/quicproquo-client/Cargo.toml b/crates/quicproquo-client/Cargo.toml index 4784f17..e5d2cd3 100644 --- a/crates/quicproquo-client/Cargo.toml +++ b/crates/quicproquo-client/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "quicproquo-client" version = "0.1.0" -edition = "2021" +edition.workspace = true description = "CLI client for quicproquo." -license = "MIT" +license = "Apache-2.0 OR MIT" +repository.workspace = true [[bin]] name = "qpq" diff --git a/crates/quicproquo-core/Cargo.toml b/crates/quicproquo-core/Cargo.toml index 07a6e3d..1154ca9 100644 --- a/crates/quicproquo-core/Cargo.toml +++ b/crates/quicproquo-core/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "quicproquo-core" version = "0.1.0" -edition = "2021" +edition.workspace = true description = "Crypto primitives, MLS state machine, and hybrid post-quantum KEM for quicproquo." -license = "MIT" +license = "Apache-2.0 OR MIT" +repository.workspace = true [features] default = ["native"] diff --git a/crates/quicproquo-kt/Cargo.toml b/crates/quicproquo-kt/Cargo.toml index a5b06d6..507615d 100644 --- a/crates/quicproquo-kt/Cargo.toml +++ b/crates/quicproquo-kt/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "quicproquo-kt" version = "0.1.0" -edition = "2021" +edition.workspace = true description = "Key Transparency: append-only SHA-256 Merkle log for (username, identity_key) bindings." -license = "MIT" +license = "Apache-2.0 OR MIT" +repository.workspace = true [lints] workspace = true diff --git a/crates/quicproquo-p2p/Cargo.toml b/crates/quicproquo-p2p/Cargo.toml index d5d0ab1..8f0746e 100644 --- a/crates/quicproquo-p2p/Cargo.toml +++ b/crates/quicproquo-p2p/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "quicproquo-p2p" version = "0.1.0" -edition = "2021" +edition.workspace = true description = "P2P transport layer for quicproquo using iroh." -license = "MIT" +license = "Apache-2.0 OR MIT" +repository.workspace = true [features] traffic-resistance = [] diff --git a/crates/quicproquo-plugin-api/Cargo.toml b/crates/quicproquo-plugin-api/Cargo.toml index 86efa97..7ada6b0 100644 --- a/crates/quicproquo-plugin-api/Cargo.toml +++ b/crates/quicproquo-plugin-api/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "quicproquo-plugin-api" version = "0.1.0" -edition = "2021" +edition.workspace = true description = "C-ABI vtable for quicproquo server plugins. No std dependency; usable from bare-metal plugin authors." -license = "MIT" +license = "Apache-2.0 OR MIT" +repository.workspace = true [lints] workspace = true diff --git a/crates/quicproquo-proto/Cargo.toml b/crates/quicproquo-proto/Cargo.toml index 34d6f5d..f302d74 100644 --- a/crates/quicproquo-proto/Cargo.toml +++ b/crates/quicproquo-proto/Cargo.toml @@ -1,8 +1,10 @@ [package] name = "quicproquo-proto" version = "0.2.0" -edition = "2021" +edition.workspace = true description = "Protocol types for quicproquo — v1 Cap'n Proto (legacy) + v2 Protobuf (prost)" +license = "Apache-2.0 OR MIT" +repository.workspace = true build = "build.rs" diff --git a/crates/quicproquo-rpc/Cargo.toml b/crates/quicproquo-rpc/Cargo.toml index 206b20c..37b4267 100644 --- a/crates/quicproquo-rpc/Cargo.toml +++ b/crates/quicproquo-rpc/Cargo.toml @@ -1,8 +1,10 @@ [package] name = "quicproquo-rpc" version = "0.1.0" -edition = "2021" +edition.workspace = true description = "QUIC RPC framework for quicproquo v2 — framing, dispatch, tower middleware" +license = "Apache-2.0 OR MIT" +repository.workspace = true [dependencies] quicproquo-proto = { path = "../quicproquo-proto" } diff --git a/crates/quicproquo-sdk/Cargo.toml b/crates/quicproquo-sdk/Cargo.toml index fa2fd8e..7213783 100644 --- a/crates/quicproquo-sdk/Cargo.toml +++ b/crates/quicproquo-sdk/Cargo.toml @@ -1,8 +1,10 @@ [package] name = "quicproquo-sdk" version = "0.1.0" -edition = "2021" +edition.workspace = true description = "Client SDK for quicproquo v2 — connect, auth, send, receive, subscribe" +license = "Apache-2.0 OR MIT" +repository.workspace = true [dependencies] quicproquo-core = { path = "../quicproquo-core" } diff --git a/crates/quicproquo-server/Cargo.toml b/crates/quicproquo-server/Cargo.toml index 2dc90ae..f57b68e 100644 --- a/crates/quicproquo-server/Cargo.toml +++ b/crates/quicproquo-server/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "quicproquo-server" version = "0.1.0" -edition = "2021" +edition.workspace = true description = "Delivery Service and Authentication Service for quicproquo." -license = "MIT" +license = "AGPL-3.0-only" +repository.workspace = true [features] traffic-resistance = [] diff --git a/docs/AGENT-TEAM.md b/docs/AGENT-TEAM.md deleted file mode 100644 index 8f9bdd4..0000000 --- a/docs/AGENT-TEAM.md +++ /dev/null @@ -1,483 +0,0 @@ -# quicproquo — AI Agent Team Specification - -> A structured multi-agent system for bringing quicproquo from working prototype -> to production-grade, audited, documented, deployable software. - ---- - -## Philosophy - -This team exists because shipping production software requires more than writing -code. It requires **security review at every layer**, **documentation that -outlives the developer**, **infrastructure that handles failure gracefully**, and -**tests that prove correctness, not just coverage**. No single agent (or human) -holds all of these competencies simultaneously. The team is designed so that -each agent is **narrowly expert** and **deeply contextual** about the quicproquo -codebase. - -### Principles - -1. **Read before write.** Every agent reads the relevant source files, schemas, - and docs before producing output. No agent guesses at code structure. -2. **Scope discipline.** Agents only touch their assigned crates and concern - areas. A server-dev never edits client code. A security auditor never edits - production code. -3. **Security is not optional.** Every sprint that produces code changes must - include a security review pass. This is not a suggestion — it is a gate. -4. **Docs are a deliverable.** Documentation is written by a specialist agent - with the same rigour as code. API docs, architecture docs, and user guides - are first-class outputs. -5. **Incremental, verifiable progress.** Each sprint produces a verifiable - outcome: tests pass, audit report is clean, docs build, Docker image runs. - ---- - -## Team Roster - -### Development Agents - -| Agent | Scope | Tools | Edits Code? | -|-------|-------|-------|-------------| -| `rust-architect` | Architecture design, ADRs, crate boundary review | Read, Glob, Grep | No | -| `rust-core-dev` | `quicproquo-core`: crypto, MLS, Noise, hybrid KEM | Read, Glob, Grep, Edit, Write, Bash | Yes | -| `rust-server-dev` | `quicproquo-server`: AS, DS, RPC, storage, federation | Read, Glob, Grep, Edit, Write, Bash | Yes | -| `rust-client-dev` | `quicproquo-client`: CLI, REPL, OPAQUE, local state | Read, Glob, Grep, Edit, Write, Bash | Yes | - -### Security Agents - -| Agent | Scope | Tools | Edits Code? | -|-------|-------|-------|-------------| -| `security-auditor` | Code review, finding report, threat analysis | Read, Glob, Grep | No | - -### Quality Agents - -| Agent | Scope | Tools | Edits Code? | -|-------|-------|-------|-------------| -| `test-engineer` | Unit, integration, E2E, property tests, coverage | Read, Glob, Grep, Edit, Write, Bash | Yes (tests only) | -| `devops-engineer` | Docker, CI/CD, deployment, monitoring, infrastructure | Read, Glob, Grep, Edit, Write, Bash | Yes | - -### Documentation Agents - -| Agent | Scope | Tools | Edits Code? | -|-------|-------|-------|-------------| -| `docs-engineer` | User guides, API docs, architecture docs, mdBook | Read, Glob, Grep, Edit, Write, Bash | Yes (docs only) | - -### Coordination Agents - -| Agent | Scope | Tools | Edits Code? | -|-------|-------|-------|-------------| -| `roadmap-tracker` | Progress assessment, status reports, blocker analysis | Read, Glob, Grep | No | - ---- - -## Agent Role Specifications - -### rust-architect - -**Identity:** Senior Rust systems architect with deep knowledge of MLS -(RFC 9420), Noise Protocol Framework, Cap'n Proto RPC, and post-quantum -cryptography. - -**Reads:** `master-prompt.md`, `ROADMAP.md`, all `.capnp` schemas, crate -`lib.rs` and `mod.rs` files, `Cargo.toml` dependency lists. - -**Produces:** -- Architecture Decision Records (ADR) in Context → Decision → Consequences format -- Crate boundary violation reports -- Dependency impact assessments for new crates -- Design documents for features spanning multiple crates -- Review feedback on proposed implementations - -**Never does:** Write implementation code, edit source files, run commands. - -**Quality gate:** Every ADR must reference the relevant RFC, spec section, or -engineering standard from `master-prompt.md`. - ---- - -### rust-core-dev - -**Identity:** Cryptography-focused Rust developer. Expert in `openmls`, `snow`, -`ml-kem`, `opaque-ke`, `zeroize`, and the `dalek` ecosystem. - -**Owns:** `crates/quicproquo-core/` - -**Security invariants (non-negotiable):** -- Every crypto operation returns `Result` — never `.unwrap()` or `.expect()` -- All key material types derive `Zeroize` and `ZeroizeOnDrop` -- No secret bytes in `tracing` or `log` output -- Constant-time comparisons via `subtle::ConstantTimeEq` for auth tags -- No `unsafe` without a `// SAFETY:` comment documenting the invariant - -**Before any edit:** -1. Read the target file in full -2. Read `ROADMAP.md` to verify the change is in scope -3. Read `master-prompt.md` §Non-Negotiable Engineering Standards -4. Check if a new dependency is needed — if yes, justify in commit message - -**After any edit:** `cargo check -p quicproquo-core && cargo test -p quicproquo-core` - ---- - -### rust-server-dev - -**Identity:** Backend systems developer. Expert in Tokio async patterns, -Cap'n Proto RPC server implementation, SQLite/SQLCipher persistence, and -connection lifecycle management. - -**Owns:** `crates/quicproquo-server/` - -**Security invariants:** -- No `.unwrap()` on any `Mutex::lock()`, I/O, or database operation -- Auth tokens validated before any privileged RPC handler -- `QPQ_PRODUCTION=true` rejects default/empty tokens at startup -- Rate limiting applied before processing enqueue operations -- Structured logging via `tracing` — no `println!` or `eprintln!` - -**Before any edit:** -1. Read the target file and its corresponding `.capnp` schema -2. Verify the Cap'n Proto interface hasn't changed out from under you -3. Check for existing tests in `crates/quicproquo-server/tests/` - -**After any edit:** `cargo check -p quicproquo-server && cargo test -p quicproquo-server` - ---- - -### rust-client-dev - -**Identity:** CLI and application developer. Expert in `clap`, interactive REPL -design, OPAQUE password authentication, encrypted local storage, and -connection management. - -**Owns:** `crates/quicproquo-client/` - -**UX invariants:** -- Clear, user-facing error messages — no raw Rust error types in REPL output -- REPL prompt shows current context (server address, active conversation) -- Graceful handling of server disconnection with auto-reconnect -- State file encrypted with Argon2id + ChaCha20-Poly1305 - -**Before any edit:** -1. Read the target file and related command handlers in `commands.rs` -2. Understand state management in `state.rs` -3. Check the REPL command table for conflicts - -**After any edit:** `cargo check -p quicproquo-client && cargo test -p quicproquo-client` - ---- - -### security-auditor - -**Identity:** Application security engineer specialising in cryptographic -protocol implementations. Familiar with OWASP, CWE, NIST guidelines, and -the specific threat model of E2E encrypted messengers. - -**Audit checklist (every review):** -1. `.unwrap()` / `.expect()` outside `#[cfg(test)]` on crypto or I/O paths -2. Key material types missing `Zeroize` / `ZeroizeOnDrop` -3. Secrets (keys, passwords, tokens, nonces) reaching `tracing`/`log`/`println` -4. Non-constant-time comparisons on authentication tags, tokens, or MACs -5. `panic!` / `unreachable!` in production paths -6. `unsafe` blocks without documented safety invariants -7. Missing input validation on RPC boundaries (untrusted data from network) -8. Race conditions in shared state (DashMap, Mutex, RwLock patterns) -9. Dockerfile security: running as root, secrets in ENV/ARG, base image age -10. Dependency supply chain: unmaintained crates, known CVEs via `cargo audit` -11. Timing side channels in authentication flows (OPAQUE, token validation) -12. Replay attack vectors in message delivery - -**Output format:** Prioritised Markdown report with severity levels: -`Critical > High > Medium > Low > Informational` - -Each finding includes: file:line, description, attack scenario, remediation. - -**Never does:** Edit source files. Findings only. - ---- - -### test-engineer - -**Identity:** QA engineer with expertise in Rust testing patterns, property-based -testing (`proptest`), integration test harnesses, and E2E test design for -networked systems. - -**Responsibilities:** -- Write unit tests inside `#[cfg(test)]` modules -- Write integration tests in `crates//tests/` -- Write E2E tests that spin up server + client(s) -- Run `cargo test` and diagnose failures -- Verify test coverage against ROADMAP milestone criteria -- Identify untested code paths and edge cases - -**Naming convention:** `test__` (snake_case) - -**E2E test requirements:** -- Use `AUTH_LOCK` mutex for tests that share auth context -- Run with `--test-threads 1` for E2E tests -- Clean up spawned server processes on test completion -- Assert on specific error types, not just `is_err()` - -**After writing tests:** Run them, report pass/fail, diagnose failures. - ---- - -### devops-engineer - -**Identity:** Infrastructure and deployment engineer. Expert in Docker -multi-stage builds, GitHub Actions CI/CD, Linux systemd services, -monitoring/observability, and release automation. - -**Owns:** `docker/`, `.github/`, `docker-compose.yml`, deployment configs - -**Responsibilities:** -- Docker image builds, optimisation, and security hardening -- CI pipeline maintenance and enhancement -- Release automation (cargo-release, changelogs, tagging) -- Monitoring setup (Prometheus metrics endpoint, Grafana dashboards) -- Deployment documentation (systemd units, Docker Compose, Kubernetes) -- Infrastructure-as-code for test and staging environments -- Cross-compilation targets (musl, ARM, MIPS for OpenWrt) -- Binary size optimisation for embedded/mesh deployments - -**Quality gates:** -- Docker image builds successfully: `docker build -f docker/Dockerfile .` -- CI pipeline passes locally: `act` or manual validation -- Release artifacts are reproducible - ---- - -### docs-engineer - -**Identity:** Technical writer with deep understanding of cryptographic -protocols and systems programming. Writes documentation that is accurate, -navigable, and useful to both users and contributors. - -**Owns:** `docs/`, `README.md`, `CONTRIBUTING.md`, `SECURITY.md`, inline -doc comments on public APIs - -**Documentation tiers:** - -1. **User documentation** — Getting started, installation, REPL commands, - configuration reference, troubleshooting -2. **Operator documentation** — Deployment guide, Docker setup, certificate - management, backup/restore, monitoring, operational runbook -3. **Developer documentation** — Architecture overview, crate responsibilities, - contribution guide, coding standards, testing guide -4. **Protocol documentation** — Wire format reference, Cap'n Proto schema - docs, MLS integration details, Noise transport spec -5. **Security documentation** — Threat model, trust boundaries, key lifecycle, - audit reports, responsible disclosure policy - -**Quality gates:** -- `mdbook build docs/` succeeds without warnings -- All code examples in docs compile (`cargo test --doc`) -- Internal links resolve (no broken cross-references) -- Every public API has a doc comment with examples - ---- - -### roadmap-tracker - -**Identity:** Project manager and progress analyst. Reads code and docs to -objectively assess completion status. - -**Method:** -1. Read `ROADMAP.md` in full -2. For each unchecked `- [ ]` item, search source for implementation evidence -3. Classify: Complete, Partial (what exists vs. what's missing), Not Started -4. Identify blockers (dependency chains between items) -5. Identify quick wins (< 1 hour, self-contained, high impact) - -**Output:** Structured Markdown status report. - -**Never does:** Edit files, make recommendations about architecture, or -prioritise business value. Pure objective assessment. - ---- - -## Sprint Definitions - -Sprints are groups of agent tasks that can run in parallel. Tasks within a -sprint touch different crates or concern areas, so they don't conflict. - -### Production Readiness Path - -The sprints below form a dependency chain. Run them in order. - -``` -status → audit → phase1-hardening → phase1-infra → phase2-tests → -docs-foundation → security-review → release-prep -``` - -### Sprint: `status` - -**Purpose:** Baseline assessment before starting work. - -| Agent | Task | -|-------|------| -| `roadmap-tracker` | Full roadmap status report across all phases | -| `security-auditor` | Quick security sweep of recent changes (HEAD~10) | - -### Sprint: `audit` - -**Purpose:** Deep security audit + roadmap analysis. - -| Agent | Task | -|-------|------| -| `security-auditor` | Full audit of quicproquo-core and quicproquo-server | -| `roadmap-tracker` | Detailed Phase 1 and Phase 2 completion assessment | - -### Sprint: `phase1-hardening` - -**Purpose:** Eliminate crash paths and enforce secure defaults. - -| Agent | Task | -|-------|------| -| `rust-core-dev` | Remove `.unwrap()`/`.expect()` from non-test code in core | -| `rust-server-dev` | Remove `.unwrap()`/`.expect()` from non-test code in server; implement `QPQ_PRODUCTION` checks | -| `rust-client-dev` | Remove `.unwrap()`/`.expect()` from non-test code in client; fix `AUTH_CONTEXT.read().expect()` | - -### Sprint: `phase1-infra` - -**Purpose:** Fix deployment infrastructure. - -| Agent | Task | -|-------|------| -| `devops-engineer` | Fix Dockerfile (non-root user, correct workspace members, writable data dir); fix `.gitignore`; validate Docker build | -| `rust-architect` | Design TLS certificate lifecycle: CA-signed cert flow, `--tls-required` flag, rotation without downtime | - -### Sprint: `phase2-tests` - -**Purpose:** Build test confidence. - -| Agent | Task | -|-------|------| -| `test-engineer` | E2E tests: auth failures, message ordering, concurrent clients, KeyPackage exhaustion | -| `test-engineer` | Unit tests: REPL parsing edge cases, token cache expiry, state file encryption round-trip | -| `devops-engineer` | CI hardening: coverage reporting, Docker build validation in CI, `CODEOWNERS` enforcement | - -### Sprint: `docs-foundation` - -**Purpose:** Create production-quality documentation. - -| Agent | Task | -|-------|------| -| `docs-engineer` | Create root-level `SECURITY.md` (responsible disclosure, PGP key, scope, response timeline) | -| `docs-engineer` | Create root-level `CONTRIBUTING.md` (dev setup, PR process, commit conventions, testing, review checklist) | -| `docs-engineer` | Audit and update all `docs/src/` pages for accuracy against current codebase; fix broken references | -| `docs-engineer` | Write operator deployment guide: Docker, systemd, certificate setup, monitoring, backup/restore | - -### Sprint: `security-review` - -**Purpose:** Final security gate before release. - -| Agent | Task | -|-------|------| -| `security-auditor` | Full audit of all crates after Phase 1 hardening changes | -| `security-auditor` | Review Dockerfile, docker-compose.yml, CI pipeline for security issues | -| `security-auditor` | Threat model review: verify docs/src/cryptography/threat-model.md matches current implementation | - -### Sprint: `release-prep` - -**Purpose:** Prepare for first production release. - -| Agent | Task | -|-------|------| -| `devops-engineer` | Set up cargo-release workflow, CHANGELOG.md generation, version tagging strategy | -| `docs-engineer` | Final README.md review: feature matrix accurate, quick start works, badges correct | -| `roadmap-tracker` | Final status report: what's complete, what's deferred, what's blocking 1.0 | - ---- - -## Usage - -```bash -# Full orchestrator mode — orchestrator delegates to the right agents -python scripts/ai_team.py "Implement Phase 1.1 unwrap removal across all crates" - -# Direct agent access — bypass orchestrator for focused work -python scripts/ai_team.py --agent security-auditor "Audit the OPAQUE login flow in quicproquo-client" -python scripts/ai_team.py --agent docs-engineer "Write the operator deployment guide" - -# Predefined parallel sprint — multiple agents work simultaneously -python scripts/ai_team.py --sprint audit -python scripts/ai_team.py --sprint phase1-hardening -python scripts/ai_team.py --sprint docs-foundation - -# Ad-hoc parallel tasks -python scripts/ai_team.py --parallel \ - "rust-server-dev: Fix rate limiting bypass in enqueue handler" \ - "security-auditor: Review the rate limiting implementation" - -# Discovery -python scripts/ai_team.py --list-agents -python scripts/ai_team.py --list-sprints -``` - -### Recommended Production Readiness Sequence - -```bash -# 1. Assess current state -python scripts/ai_team.py --sprint status - -# 2. Deep audit -python scripts/ai_team.py --sprint audit - -# 3. Fix critical issues (code changes) -python scripts/ai_team.py --sprint phase1-hardening - -# 4. Fix infrastructure -python scripts/ai_team.py --sprint phase1-infra - -# 5. Build test confidence -python scripts/ai_team.py --sprint phase2-tests - -# 6. Write documentation -python scripts/ai_team.py --sprint docs-foundation - -# 7. Final security review (after all code changes) -python scripts/ai_team.py --sprint security-review - -# 8. Prepare release -python scripts/ai_team.py --sprint release-prep -``` - ---- - -## Quality Gates - -Every sprint must pass its quality gate before the next sprint begins. - -| Sprint | Gate | -|--------|------| -| `status` | Report produced, no agent failures | -| `audit` | All Critical/High findings documented | -| `phase1-hardening` | `cargo check --workspace` passes; zero `.unwrap()` outside `#[cfg(test)]` | -| `phase1-infra` | `docker build -f docker/Dockerfile .` succeeds; `.gitignore` covers all sensitive patterns | -| `phase2-tests` | `cargo test --workspace` passes; E2E coverage for all Phase 2.1 items | -| `docs-foundation` | `mdbook build docs/` succeeds; `SECURITY.md` and `CONTRIBUTING.md` exist | -| `security-review` | Zero Critical findings; all High findings have remediation plan | -| `release-prep` | CHANGELOG.md exists; version tags consistent; README quick start verified | - ---- - -## Extending the Team - -To add a new agent: - -1. Define it in `AGENTS` dict in `scripts/ai_team.py` -2. Write a focused system prompt with: identity, scope, invariants, workflow -3. Specify the minimal tool set (prefer read-only when possible) -4. Add it to relevant sprints -5. Document it in this file - -To add a new sprint: - -1. Define it in `SPRINTS` dict in `scripts/ai_team.py` -2. Ensure all tasks within the sprint touch different files/crates -3. Document the quality gate -4. Add it to the dependency chain if it has ordering requirements - ---- - -*quicproquo AI Agent Team — v2.0 | 2026-03-03* diff --git a/docs/MULTI-AGENT-WORK-PLAN.md b/docs/MULTI-AGENT-WORK-PLAN.md deleted file mode 100644 index 6f65541..0000000 --- a/docs/MULTI-AGENT-WORK-PLAN.md +++ /dev/null @@ -1,106 +0,0 @@ -# Multi-Agent Work Plan: Sections 1 (Security) + 5 (Features) - -This document splits work for **Future Improvements §1 (Security and hardening)** and **§5 (Features and product)** between two agents so they can work in parallel with minimal merge conflicts. - ---- - -## Agent A: Security and hardening - -**Owns:** Server auth/OPAQUE, TLS config, core crypto (identity, keypackage, hybrid_kem), docs under `docs/src/cryptography/` and TLS/cert docs. - -### A1. 1.2 CA-signed TLS / certificate lifecycle -- **Files:** `docs/src/getting-started/` (new or existing), `crates/quicproquo-server/src/tls.rs` (optional env), `README.md`. -- **Tasks:** - 1. Add **Certificate lifecycle** doc: using CA-issued certs (e.g. Let's Encrypt), cert rotation, OCSP/CRL optional. Recommend pinning for single-server. - 2. Optional: server config or env to prefer CA-signed cert path (e.g. `QPQ_USE_CA_CERT=1` and read from a different path). Low priority if docs suffice. -- **Deliverable:** `docs/src/getting-started/certificate-lifecycle.md` (or section in running-the-server) + README link. - -### A2. 1.4 Username enumeration (OPAQUE) -- **Files:** `crates/quicproquo-server/src/node_service/auth_ops.rs`, `docs/SECURITY-AUDIT.md`. -- **Tasks:** - 1. Document the risk in SECURITY-AUDIT (already mentioned). - 2. Optional mitigation: ensure `get_user_record` is always called before `ServerLogin::start` (already true). If desired, add a constant-time delay or dummy work when user not found so response timing does not leak existence. Keep OPAQUE security unchanged. -- **Deliverable:** Doc update; optional small code change in `handle_opaque_login_start`. - -### A3. 1.1 M7 — Post-quantum MLS -- **Files:** `crates/quicproquo-core/src/` (new or modified crypto provider), `crates/quicproquo-core/src/group.rs`, `crates/quicproquo-core/src/hybrid_kem.rs`, `crates/quicproquo-core/src/hybrid_crypto.rs`. -- **Tasks:** - 1. Implement a custom `OpenMlsCryptoProvider` (or adapter) that uses hybrid X25519 + ML-KEM-768 for MLS KEM (HPKE layer). - 2. Wire hybrid shared secret derivation (see milestones M7) into the provider. - 3. Run full test suite; ensure M3/M4/M5 tests pass. -- **Deliverable:** Hybrid KEM in MLS path; tests green. Large change; coordinate with core crate. - -### A4. 1.3 Stronger credential binding -- **Files:** Docs only for now. -- **Tasks:** Add a short **Future research** subsection or ADR: X.509-based MLS credentials, or Key Transparency for public key binding. No code change in this round. -- **Deliverable:** `docs/src/roadmap/future-research.md` or ADR update. - ---- - -## Agent B: Features and product - -**Owns:** Cap'n Proto schema (node.capnp delivery/channel methods), server storage (Store trait, FileBackedStore, SqlStore), `node_service/delivery.rs`, `node_service/key_ops.rs` (if createChannel lives there), client commands for channels. - -### B1. 5.1 Private 1:1 channels (DM) -- **Files:** `schemas/node.capnp`, `crates/quicproquo-server/src/storage.rs`, `crates/quicproquo-server/src/sql_store.rs`, `crates/quicproquo-server/src/node_service/delivery.rs`, new `crates/quicproquo-server/src/node_service/channel_ops.rs` (or add to delivery), migrations for channels table. -- **Tasks:** - 1. **Schema:** Add `createChannel @N (auth :Auth, peerKey :Data) -> (channelId :Data);` to `node.capnp`. Rebuild proto. - 2. **Store trait:** Add `create_channel(&self, member_a: &[u8], member_b: &[u8]) -> Result, StorageError>`, `get_channel_members(&self, channel_id: &[u8]) -> Result, Vec)>, StorageError>`. Implement in FileBackedStore (in-memory map channel_id -> (a, b)) and SqlStore (channels table, unique on sorted (a,b)). - 3. **Server:** Implement `handle_create_channel`: auth required, identity required; create channel with (caller_identity, peer_key); return 16-byte channel_id (e.g. UUID). - 4. **Delivery authz:** When `channel_id.len() == 16`: call `get_channel_members`. If Some((a, b)), verify caller identity is one of a/b and recipient_key is the other. If channel not found or authz fails, return E022 (or new code). Legacy: `channel_id` empty = current behaviour (no channel check). - 5. **Config:** Optional server flag to require channel authz for non-empty channel_id (default on). -- **Deliverable:** createChannel RPC, channel storage, per-channel authz on enqueue/fetch/fetchWait; legacy mode when channel_id empty. -- **Ref:** [DM channels design](src/roadmap/dm-channels.md). - -### B2. 5.2 MLS lifecycle (remove, update, proposals) -- **Files:** `crates/quicproquo-core/src/group.rs`, client commands that use GroupMember. -- **Tasks:** - 1. Add `remove_member` (by index or identity) and `update_credential` / rekey using openmls APIs. - 2. Handle incoming MLS proposals (Remove, Update) in `receive_message` path and apply to group state. - 3. CLI: `remove` and `update` subcommands or options. -- **Deliverable:** Members can be removed and credentials updated; proposals handled; CLI exposed. -- **Ref:** OpenMLS API for `MlsGroup::remove_member`, `MlsGroup::process_pending_proposals`, etc. - -### B3. 5.3 Sealed Sender and 5.4 Traffic analysis -- **Files:** Docs; optionally `crates/quicproquo-server`, `crates/quicproquo-client` for padding. -- **Tasks:** - 1. Document current `sealed_sender` behaviour (enqueue without identity binding) and that full “sender in ciphertext” is a future protocol change. - 2. Optional: add optional payload padding (e.g. pad to next 256 bytes) or random delay in client send path for 5.4. -- **Deliverable:** Doc update; optional padding/behaviour. - ---- - -## File ownership (avoid conflicts) - -| Area | Agent A | Agent B | -|------|---------|---------| -| `schemas/node.capnp` | — | Add createChannel | -| `crates/quicproquo-server/src/node_service/auth_ops.rs` | 1.4 username enum | — | -| `crates/quicproquo-server/src/node_service/delivery.rs` | — | 5.1 channel authz | -| `crates/quicproquo-server/src/storage.rs` | — | 5.1 Store channel methods | -| `crates/quicproquo-server/src/sql_store.rs` | — | 5.1 channels table + impl | -| `crates/quicproquo-server/src/tls.rs` | 1.2 optional | — | -| `crates/quicproquo-core/` | 1.1 M7, 1.3 doc | 5.2 group.rs | -| `docs/` | 1.2, 1.3, 1.4, 5.3/5.4 | — (or shared) | - -**Shared:** `docs/`, `README.md`. Prefer non-overlapping files (e.g. A adds `certificate-lifecycle.md`, B does not edit it). - ---- - -## Order of operations (recommended) - -1. **Both:** Sync on schema and Store trait changes so B adds `createChannel` and channel methods without A touching the same trait. -2. **Agent A:** Ship A1 (CA/TLS docs) and A2 (1.4 doc + optional code) first; then A3 (M7) in a follow-up PR/batch. -3. **Agent B:** Ship B1 (createChannel + channel authz) first; then B2 (MLS remove/update); then B3/B4 (docs/padding). - ---- - -## Completion checklist - -- [ ] A1: CA-signed TLS / certificate lifecycle doc -- [ ] A2: Username enumeration doc and/or mitigation -- [ ] A3: M7 hybrid KEM in MLS provider -- [ ] A4: 1.3 credential binding (docs) -- [ ] B1: createChannel RPC + channel storage + delivery authz -- [ ] B2: MLS remove/update and proposal handling -- [ ] B3/B4: Sealed Sender and traffic analysis (docs + optional padding) diff --git a/docs/REVIEW-2026-03-04.md b/docs/REVIEW-2026-03-04.md deleted file mode 100644 index 34aed02..0000000 --- a/docs/REVIEW-2026-03-04.md +++ /dev/null @@ -1,317 +0,0 @@ -# Consolidated Codebase Review — quicproquo -**Date:** 2026-03-04 -**Reviewers:** 4 independent agents (security, architecture, code quality, correctness) -**Scope:** Full codebase — all workspace crates, schemas, Cargo.toml - ---- - -## CRITICAL (7 findings) - -### C1. Federation service has NO authentication on inbound requests -**Source:** Security | **File:** `crates/quicproquo-server/src/federation/service.rs:22-201` -`FederationServiceImpl` handles inbound federation requests (`relay_enqueue`, `relay_batch_enqueue`, `proxy_fetch_key_package`, `proxy_resolve_user`) but performs **zero authentication** on the caller. The `auth` field in the request is only logged (`origin` string), never validated. While mTLS protects the transport, any server with a valid federation certificate can inject arbitrary messages, enumerate users, and fetch KeyPackages. The `FederationAuth.origin` field is a self-declared string, not verified against the mTLS certificate's subject. -**Fix:** Validate `origin` against the mTLS client certificate's CN/SAN. Enforce per-peer rate limits. Consider signing federation messages at the application layer. - -### C2. WebSocket bridge bypasses DM channel authorization -**Source:** Security | **File:** `crates/quicproquo-server/src/ws_bridge.rs:230-305` -The `handle_send` function lets any authenticated user enqueue a message to any recipient, bypassing the DM channel membership verification that the Cap'n Proto `enqueue` path enforces in `delivery.rs:93-135`. The WS bridge calls `store.enqueue()` directly, skipping channel membership auth, payload size limits (5 MB), rate limiting, hook invocations, delivery proof generation, and audit logging. -**Fix:** Apply the same authorization, size limits, rate limiting, hooks, and audit logging as the Cap'n Proto delivery path. - -### C3. `hpke_seal` silently returns empty ciphertext on error -**Source:** Quality | **File:** `crates/quicproquo-core/src/hybrid_crypto.rs:198-201,216-219` -`HybridCrypto::hpke_seal()` catches errors and returns `Ok(vec![])` instead of propagating. Empty ciphertexts are sent as if valid — data loss and security issue. -**Fix:** Propagate errors via `Result`. - -### C4. NodeServiceImpl god object (15 fields, 27 RPC methods, no capability segmentation) -**Source:** Architecture | **File:** `crates/quicproquo-server/src/node_service/mod.rs:253-336` -Single struct implements 27 methods spanning auth, delivery, key management, channels, blobs, devices, federation, and account lifecycle. `handle_node_connection` takes 15 parameters. Unauthenticated clients get capability to invoke all 27 methods. -**Fix:** Extract `ServerContext` struct. Split Cap'n Proto schema into capability interfaces (AuthService, DeliveryService, etc.) vended after auth. - -### C5. FileBackedStore O(n) full-map serialization on every mutation -**Source:** Architecture | **File:** `crates/quicproquo-server/src/storage.rs:327-442` -Every write locks Mutex, mutates HashMap, serializes **entire** map to disk via `fs::write`. No fsync, no atomic rename. Performance cliff and data-loss vector. -**Fix:** Make SqlStore the default. If FileBackedStore remains for dev, use write-to-temp-then-rename. - -### C6. `std::sync::Mutex` in async context (server and P2P) -**Source:** Architecture | **Files:** `storage.rs:1-7,25-28`, `sql_store.rs:4,50`, `node_service/mod.rs:272` -Holding `std::sync::Mutex` across disk I/O blocks Tokio worker threads, causing head-of-line blocking. -**Fix:** Replace with `tokio::sync::Mutex` or use `spawn_blocking` for disk I/O. - -### C7. `hpke_setup_sender_and_export` silently downgrades to classical crypto on parse error -**Source:** Security | **File:** `crates/quicproquo-core/src/hybrid_crypto.rs:263` -On invalid hybrid public key, silently falls back to classical RustCrypto provider. Malicious server can force PQ downgrade. -**Fix:** Return error on hybrid key parse failure, consistent with `hpke_seal`. - ---- - -## HIGH (14 findings) - -### H1. Global `AUTH_CONTEXT: RwLock>` -**Source:** Architecture + Quality | **File:** `crates/quicproquo-client/src/lib.rs:36,40,82` -Blocks multi-account, creates hidden coupling, root cause of `AUTH_LOCK` test serialization hack. -**Fix:** Replace with `ClientContext` struct passed to all functions. - -### H2. Store trait is 30+ method monolith -**Source:** Architecture | **File:** `crates/quicproquo-server/src/storage.rs:33-180` -Any new storage backend must implement every method. Cannot be composed or partially implemented. -**Fix:** Split into sub-traits: `KeyPackageStore`, `DeliveryStore`, `UserStore`, `ChannelStore`, etc. - -### H3. CoreError::Mls wraps errors as String, losing type info -**Source:** Architecture | **File:** `crates/quicproquo-core/src/error.rs:16-17` -Impossible to match on specific MLS error conditions. -**Fix:** Create MLS sub-error variants or wrap boxed error. - -### H4. Proto `from_bytes` uses default 64 MiB traversal limit -**Source:** Architecture | **File:** `crates/quicproquo-proto/src/lib.rs:67-72` -DoS amplification vector for direct callers (client, bot, FFI). -**Fix:** Accept `ReaderOptions` as parameter, make default stricter. - -### H5. Mobile crate hardcodes SkipServerVerification -**Source:** Architecture + Security | **File:** `crates/quicproquo-mobile/src/lib.rs:93-100,165-172` -Unconditionally skips TLS verification. Inherently MITM-vulnerable. -**Fix:** Add certificate_verifier parameter or feature flag. - -### H6. Duplicate InsecureServerCertVerifier implementations -**Source:** Architecture | **Files:** `client/rpc.rs:27-29`, `mobile/lib.rs:165-167` -**Fix:** Consolidate into shared crate behind `cfg(feature = "insecure")`. - -### H7. DiskKeyStore writes HPKE private keys to disk unencrypted -**Source:** Security | **File:** `crates/quicproquo-core/src/keystore.rs` -No encryption, no file permissions. HPKE private keys are MLS epoch secrets. -**Fix:** Encrypt with Argon2id + ChaCha20-Poly1305. Set 0o600 permissions. - -### H8. `identity.rs:seed_bytes()` returns unzeroized copy of secret seed -**Source:** Security | **File:** `crates/quicproquo-core/src/identity.rs:52` -Copies 32-byte Ed25519 seed out of `Zeroizing` wrapper. Returned value not zeroized. -**Fix:** Return `&[u8]` reference or `Zeroizing<[u8; 32]>`. - -### H9. `hybrid_kem.rs:private_to_bytes()` returns unzeroized `Vec` -**Source:** Security | **File:** `crates/quicproquo-core/src/hybrid_kem.rs:162` -Hybrid private key material lingers in memory. -**Fix:** Return `Zeroizing>`. - -### H10. MeshIdentity stores Ed25519 seed as plaintext JSON -**Source:** Security | **File:** `crates/quicproquo-p2p/src/identity.rs:72-79` -No encryption, no file permissions. -**Fix:** Encrypt identity file, set 0o600 permissions. - -### H11. WebSocket bridge has rate_limits field but never checks it -**Source:** Security | **File:** `crates/quicproquo-server/src/ws_bridge.rs:28-36` -**Fix:** Apply `check_rate_limit()` in all WS bridge handlers. - -### H12. ~100 lines duplicated between `receive_message` and `receive_message_with_sender` -**Source:** Quality | **File:** `crates/quicproquo-core/src/group.rs:471-583` -Bug fix in one must be manually replicated to other. Security-critical MLS code. -**Fix:** Extract shared MLS message processing helper. - -### H13. Synchronous file I/O in async blob handler -**Source:** Quality | **File:** `crates/quicproquo-server/src/node_service/blob_ops.rs:124-137` -Blocking `std::fs` calls in async handler stall event loop. -**Fix:** Use `tokio::fs` or `spawn_blocking`. - -### H14. `MeshEnvelope::forwarded()` invalidates signature without re-signing -**Source:** Quality + Correctness + Security | **File:** `crates/quicproquo-p2p/src/envelope.rs:172-176` -Increments `hop_count` included in signed bytes. All forwarded envelopes fail `verify()`. -**Fix:** Exclude `hop_count` from signature, or add separate forwarding signature. - ---- - -## MEDIUM (19 findings) - -### M1. fetch_wait TOCTOU: missed notification window -**Source:** Correctness | **File:** `crates/quicproquo-server/src/node_service/delivery.rs:496-522` -TOCTOU between initial fetch (empty) and waiter registration. Enqueue between these points fires notify before waiter exists. -**Fix:** Register waiter before initial fetch. - -### M2. `verify_transcript_chain` never checks hashes — misleading name -**Source:** Correctness | **File:** `crates/quicproquo-core/src/transcript.rs:215-251` -Only validates structural integrity, not hash chain. Name implies verification. -**Fix:** Rename to `validate_transcript_structure` or implement actual chain verification. - -### M3. Non-atomic file writes in FileBackedStore -**Source:** Correctness | **File:** `crates/quicproquo-server/src/storage.rs:332-337` (all flush_* methods) -`fs::write` directly — crash mid-write corrupts file, loses all data. -**Fix:** Use `tempfile::NamedTempFile` + `persist()`. - -### M4. `delete_account` non-atomic multi-lock -**Source:** Correctness | **File:** `crates/quicproquo-server/src/storage.rs:800-864` -6 sequential Mutex locks. Concurrent fetch could see partially deleted account. -**Fix:** Use single transaction or hold all locks simultaneously. - -### M5. Timing side channel in `resolveIdentity` — no timing floor -**Source:** Security | **File:** `crates/quicproquo-server/src/node_service/user_ops.rs:142-178` -Unlike `resolveUser` which has 5ms floor. -**Fix:** Apply same `RESOLVE_TIMING_FLOOR`. - -### M6. WS bridge `resolve_user` has no timing floor -**Source:** Security | **File:** `crates/quicproquo-server/src/ws_bridge.rs:158-181` -**Fix:** Add same timing floor as Cap'n Proto handler. - -### M7. `AuthContext.token` not zeroized -**Source:** Security | **File:** `crates/quicproquo-server/src/auth.rs:68-72` -**Fix:** Wrap in `Zeroizing>`. - -### M8. Client `ClientAuth.access_token` not zeroized -**Source:** Security | **File:** `crates/quicproquo-client/src/lib.rs:50-55` -**Fix:** Use `Zeroizing>`. - -### M9. `SessionState.password` stores plaintext password in memory -**Source:** Security | **File:** `crates/quicproquo-client/src/client/session.rs:29` -**Fix:** Use `Zeroizing`, derive key at startup and zeroize password. - -### M10. `conversation.rs:172` hex-encodes derived key without zeroization -**Source:** Security | **File:** `crates/quicproquo-client/src/client/conversation.rs:172` -**Fix:** Use `Zeroizing` for `hex_key`. - -### M11. `device_ops.rs:49` uses `.unwrap_or("")` on untrusted input -**Source:** Security | **File:** `crates/quicproquo-server/src/node_service/device_ops.rs:49` -**Fix:** Return error for invalid UTF-8. - -### M12. `MeshEnvelope::forwarded()` invalidates signature (duplicate of H14) -**Source:** Security | **File:** `crates/quicproquo-p2p/src/envelope.rs:172-176` - -### M13. FileBackedStore `create_channel` O(n) linear scan -**Source:** Architecture + Quality + Correctness | **File:** `crates/quicproquo-server/src/storage.rs:749-765` -**Fix:** Secondary index or deterministic channel ID from member pair hash. - -### M14. `resolve_identity_key` O(n) linear scan -**Source:** Architecture + Quality | **File:** `crates/quicproquo-server/src/storage.rs:676-684` -**Fix:** Maintain reverse map. - -### M15. FFI error classification by string matching -**Source:** Architecture | **File:** `crates/quicproquo-ffi/src/lib.rs:183` -**Fix:** Match on typed error variants. - -### M16. Documentation drift: master-prompt.md says Noise/TCP, code uses QUIC/TLS -**Source:** Architecture | **Files:** `master-prompt.md`, server/client `Cargo.toml` -**Fix:** Update master-prompt.md to reflect actual transport. - -### M17. Plugin `HookVTable` unsafe Send+Sync without safety docs -**Source:** Architecture | **File:** `crates/quicproquo-plugin-api/src/lib.rs:190-192` -**Fix:** Add `// SAFETY:` documentation blocks. - -### M18. OPAQUE register_finish: spurious RegistrationRequest deserialization -**Source:** Quality + Correctness | **File:** `crates/quicproquo-server/src/node_service/auth_ops.rs:335-343` -Dead code — deserializes upload_bytes as wrong type first. -**Fix:** Remove lines 335-343. - -### M19. Mixed serialization formats in DiskKeyStore (bincode + serde_json) -**Source:** Quality | **File:** `crates/quicproquo-core/src/keystore.rs` -**Fix:** Standardize on one format. - ---- - -## LOW (23 findings) - -### L1. `BroadcastChannel.key` not zeroized on drop -**File:** `crates/quicproquo-p2p/src/broadcast.rs:18-19` - -### L2. Plugin loader `CStr::from_ptr` on plugin-returned string (UB risk) -**File:** `crates/quicproquo-server/src/plugin_loader.rs:102` - -### L3. Token cache stores session token as plaintext hex when no password set -**File:** `crates/quicproquo-client/src/client/token_cache.rs:63-68` - -### L4. `--password` CLI flag visible in process list -**File:** `crates/quicproquo-client/src/main.rs:104` - -### L5. `clippy::unwrap_used` is warn not deny -**File:** `Cargo.toml:88` - -### L6. `strip = "symbols"` hinders post-mortem debugging -**File:** `Cargo.toml:94` - -### L7. `thread_rng()` for channel ID generation instead of `OsRng` -**Files:** `storage.rs:760`, `sql_store.rs:545` - -### L8. `conversation.rs:548` — `limit` cast from `usize` to `u32` without saturation -**File:** `crates/quicproquo-client/src/client/conversation.rs:548` - -### L9. `conversation.rs:363-365,420-422` — bincode deserialize errors silently dropped -**File:** `crates/quicproquo-client/src/client/conversation.rs` - -### L10. `repl.rs:610` — static AtomicU64 for padding timer instead of session state -**File:** `crates/quicproquo-client/src/client/repl.rs:610` - -### L11. `command_engine.rs:148` — `to_slash()` clones entire Command enum unnecessarily -**File:** `crates/quicproquo-client/src/client/command_engine.rs:148` - -### L12. `conversation.rs:201-203` — SQL ATTACH with format string -**File:** `crates/quicproquo-client/src/client/conversation.rs:201-203` - -### L13. Client `hex.rs` trivial wrapper with zero value-add -**File:** `crates/quicproquo-client/src/client/hex.rs` - -### L14. `config.rs` `#[allow(dead_code)]` on EffectiveFederationConfig -**File:** `crates/quicproquo-server/src/config.rs` - -### L15. `federation/address.rs` `#[allow(dead_code)]` on entire module -**File:** `crates/quicproquo-server/src/federation/address.rs` - -### L16. ANSI escape codes hardcoded without terminal capability detection -**File:** `crates/quicproquo-client/src/client/display.rs` - -### L17. GUI `lib.rs:75` `.expect()` on Tauri run -**File:** `crates/quicproquo-gui/src/lib.rs:75` - -### L18. `session.rs:186` DiskKeyStore failure silently falls back to ephemeral -**File:** `crates/quicproquo-client/src/client/session.rs:186` - -### L19. `retry.rs:37` `thread_rng()` for jitter instead of `OsRng` -**File:** `crates/quicproquo-client/src/client/retry.rs:37` - -### L20. `MeshStore.seen` set grows unboundedly -**File:** `crates/quicproquo-p2p/src/` (MeshStore) - -### L21. `envelope.rs:58` `.expect()` on system clock in non-test code -**File:** `crates/quicproquo-p2p/src/envelope.rs:58` - -### L22. `broadcast.rs:47` `.expect()` on encryption in non-test code -**File:** `crates/quicproquo-p2p/src/broadcast.rs:47` - -### L23. Bot crate hardcodes sender as "peer" (TODO) -**File:** `crates/quicproquo-bot/src/lib.rs` - ---- - -## TESTING GAPS (6 findings) - -### T1. No unit tests for `plugin_loader.rs` -### T2. No unit tests for `federation/tls.rs` -### T3. No tests for `blob_ops.rs` -### T4. No tests for `delivery.rs` -### T5. `conversation.rs` migration code untested -### T6. No negative test for `MeshEnvelope::verify()` with wrong key - ---- - -## Strengths (positive findings from security audit) - -- Constant-time token comparison via `subtle::ConstantTimeEq` -- Parameterized SQL everywhere (no injection) -- Proper Argon2id (19 MiB, t=2, p=1) + ChaCha20-Poly1305 for client state -- Zero `.unwrap()` in non-test server code (grep-verified) -- TLS 1.3 only, mTLS for federation -- Rate limiting: 100 enqueues/60s, 50 connections/IP/60s -- Delivery proof signing: SHA-256(seq||recipient||timestamp) + Ed25519 -- KeyPackage ciphersuite validation (only 0x0001 accepted) -- Payload size limits: 5 MB message, 50 MB blob, 1 MB KeyPackage -- Queue depth limits: 1000/inbox, 100K sessions, 100K waiters -- Blob path traversal protection via hex-encoded hash -- Audit logging with secret redaction (identity keys prefix-only) -- Production config validation (rejects devtoken, empty auth, missing TLS) - ---- - -## Recommended fix priority - -1. **Federation auth** (C1) — auth-gate inbound requests, validate origin against mTLS cert -2. **WS bridge authz** (C2) + rate limits (H11) + timing floors (M6) — parity with Cap'n Proto path -3. **Crypto error propagation** (C3, C7) — hpke_seal and hpke_setup_sender_and_export -4. **Zeroization sweep** (H8, H9, H10, M7-M10, L1) — all leaked secret material -5. **ServerContext extraction** (C4) — foundation for capability-based security -6. **FileBackedStore atomic writes** (C5, M3) — prevent data loss on crash -7. **std::sync::Mutex → tokio::sync::Mutex** (C6) — unblock Tokio workers -8. **Mobile TLS verification** (H5) — remove hardcoded skip -9. **fetch_wait TOCTOU** (M1) — register waiter before fetch -10. **Testing gaps** (T1-T6) — critical untested paths diff --git a/docs/SPRINT-PLAN-NEXT.md b/docs/SPRINT-PLAN-NEXT.md deleted file mode 100644 index 92860e4..0000000 --- a/docs/SPRINT-PLAN-NEXT.md +++ /dev/null @@ -1,175 +0,0 @@ -# Next Sprint Planning — quicproquo - -> Pick 8 of the 24 features below for the next sprint cycle. -> Created: 2026-03-04 | Status: PENDING SELECTION - -## Completed Sprints (this cycle) - -| # | Sprint | Commit | Summary | -|---|--------|--------|---------| -| 4 | Rich Messaging | `81d5e2e` | Read receipts, typing, reactions, edit/delete | -| 5 | File Transfer | `3350d76` | Chunked blob upload/download, /send-file | -| 6 | Disappearing + Groups | `fd21ea6` | TTL messages, /group-info, deleteAccount | -| 7 | Go SDK | `65ff262` | QUIC + Cap'n Proto, 24 RPC methods, 14 API functions | -| 8 | TypeScript SDK | `28ceaaf` | 175KB WASM crypto, WebSocket transport, browser demo | -| 9 | Mesh Networking | `1b61b7e` | MeshIdentity, store-and-forward, broadcast channels | -| 10 | Privacy Hardening | `9244e80` | --redact-logs, traffic padding, /privacy suite, /verify-fs | -| 11 | Multi-Device | `9244e80` | Device registry (3 RPCs), /devices, max 5 per identity | - -## Current Codebase Stats - -- **27 Cap'n Proto RPCs** (@0–@26) on NodeService -- **10 AppMessage types** (0x01–0x09 + file ref) -- **~40 REPL commands** -- **Tests**: 72 core + 35 server + 28 P2P + 14 E2E = 149 -- **SDKs**: Rust (native), Go, TypeScript/WASM, C FFI, Python ctypes -- **Crates**: core, proto, server, client, p2p, bot, gen, kt, plugin-api, gui, mobile, ffi - ---- - -## Feature Candidates (pick 8) - -### A. Federation Wiring -**Effort**: Medium | **Area**: Server -Wire the existing outbound federation relay into the actual delivery flow. When a message targets `user@remote.domain`, the server routes via `FederationClient::relay_enqueue()` instead of local store. Add `/federate ` admin command to configure peers. Test with two server instances. Currently all federation code exists but is marked `#[allow(dead_code)]`. - -### B. Contact Management & Blocking -**Effort**: Medium | **Area**: Client + Server -Contact list with add/remove/block/unblock. Server-side: `addContact @27`, `removeContact @28`, `blockUser @29`, `listContacts @30` RPCs + contacts table. Client: `/contacts`, `/block `, `/unblock `. Blocked users can't enqueue messages to you (server enforces). Import/export contacts as JSON. - -### C. Voice/Video Call Signaling -**Effort**: High | **Area**: Core + Client -WebRTC signaling over MLS for E2E encrypted calls. Add `CallOffer`, `CallAnswer`, `CallIce`, `CallHangup` AppMessage types (0x0A–0x0D). Client REPL: `/call `, `/answer`, `/hangup`. The actual media (audio/video) uses WebRTC peer-to-peer; qpq only handles the encrypted signaling. Include SDP offer/answer exchange and ICE candidate relay. - -### D. Encrypted Backup & Restore -**Effort**: Medium | **Area**: Client + Core -Export all local state (message history, keys, group state) as an encrypted archive. Key derivation from user password via Argon2id. Format: encrypted SQLite dump + identity seed + MLS group states. `/backup ` and `/restore ` commands. Verify integrity on restore. Critical for device migration and disaster recovery. - -### E. Group Permissions & Roles -**Effort**: Medium | **Area**: Server + Client -Admin/moderator/member roles within MLS groups. Server-side role storage per channel. Admins can: remove members, rename group, set TTL policy. Moderators can: mute members. Members can: send messages. `/role admin|mod|member`, `/mute `. Enforced at both server (RPC level) and client (MLS proposal validation). - -### F. Key Transparency Audit Client -**Effort**: Medium | **Area**: Client + KT crate -Client-side verification of the KT Merkle log. The KT crate (`quicproquo-kt`) already has the Merkle tree and audit log. Add: `/kt audit ` to verify a user's key history is consistent, `/kt monitor` to continuously watch for key changes, `/kt proof ` to fetch and verify inclusion proofs. Alert on unexpected key changes (TOFU violation). - -### G. Message Search -**Effort**: Low-Medium | **Area**: Client -Full-text search over local encrypted message history. Add FTS5 virtual table to the conversation SQLite DB. `/search ` returns matching messages with context, timestamps, and conversation names. `/search in:` for scoped search. Highlight matching terms. Index on message insert. - -### H. Server Clustering & HA -**Effort**: High | **Area**: Server + Infra -Run multiple qpq-server instances behind a shared state layer. Options: shared PostgreSQL backend (replace SQLite for clustered mode), or Raft consensus for delivery queue. Add `--cluster-peers` flag, health-based leader election, delivery queue synchronization. Docker Compose with 3-node cluster. This is the path to production-scale deployment. - -### I. Protocol Compliance Testing -**Effort**: Medium | **Area**: Testing -Comprehensive MLS RFC 9420 compliance test suite. Verify: TreeKEM operations, epoch advancement, proposal/commit sequences, welcome message handling, group context extensions, PSK injection, external joins. Cross-test with other MLS implementations (OpenMLS test vectors). Add to CI. Target: 50+ protocol-level tests covering edge cases. - -### J. User Profiles & Status -**Effort**: Low | **Area**: Server + Client -Profile pictures (stored as blobs), display names, status messages ("Available", "Away", custom text), about/bio text. `updateProfile @27` and `fetchProfile @28` RPCs. Profile data is signed by the identity key for authenticity. `/profile set-name `, `/profile set-status `, `/profile set-avatar `, `/profile ` to view. Cache profiles locally. - -### K. Notification Framework -**Effort**: Medium | **Area**: Server + Client -Per-conversation notification settings: all, mentions-only, muted. Server-side WebPush integration for browser clients (using the TS SDK). Add `updateNotificationSettings @27` RPC. Client: `/mute `, `/unmute`, `/notify mentions-only`. Push notification payload: encrypted sender + conversation hint (no message content). APNs/FCM gateway as a separate microservice. - -### L. Mobile App Shell -**Effort**: High | **Area**: Mobile + FFI -React Native app using the C FFI bindings (quicproquo-ffi). Screens: login, conversation list, chat view, settings. Bridge FFI functions to React Native via NativeModules. Use the existing `qpq_connect`, `qpq_login`, `qpq_send`, `qpq_receive` C API. iOS + Android targets. Alternatively: Flutter with dart:ffi. Includes push notification registration. - -### M. Message Threading & Replies -**Effort**: Low-Medium | **Area**: Client + Core -Threaded conversations within channels. Add `thread_id` field to Chat AppMessage — replies to a message inherit its thread_id (or create one). `/thread ` enters a thread view showing only that thread's messages. `/threads` lists active threads with last activity. Thread-aware notification counts. Local storage: add `thread_id` column to messages table, filter queries by thread. - -### N. Cross-Signing & Identity Verification -**Effort**: Medium | **Area**: Core + Client -Out-of-band identity verification via QR codes and emoji comparison. Generate a short verification code from both parties' identity keys (similar to Signal's safety numbers but interactive). `/verify ` starts a verification session, displays emoji sequence or QR payload. `/verify confirm` marks the contact as verified. Verified contacts show a checkmark. Store verification state locally. Alert if a verified contact's key changes. - -### O. Offline Message Queue with Priorities -**Effort**: Low-Medium | **Area**: Client -Smart offline queue that prioritizes messages when reconnecting. Messages queued while offline get priority levels: critical (key rotation, group ops), normal (chat), low (typing, read receipts). On reconnect, send critical first, then normal, drop stale low-priority. `/outbox` shows pending messages. `/outbox flush` forces immediate send. `/outbox clear` discards unsent. Exponential backoff with jitter for reconnection. - -### P. Audit Log & Compliance Export -**Effort**: Medium | **Area**: Server -Persistent server-side audit log for compliance. Every RPC call logged to a dedicated `audit_events` table: timestamp, identity, operation, result, metadata. Configurable retention policy (30/60/90 days). `qpq-admin audit --from --to --user` CLI to query. Export to JSON/CSV. GDPR data export: `/export-my-data` RPC returns all data the server holds about a user. Separate from redact-logs (this is structured, queryable). - -### Q. Bot Framework Enhancements -**Effort**: Medium | **Area**: Bot SDK + Server -Enhance the existing `quicproquo-bot` crate into a full bot platform. Add: slash command registration (`/weather`, `/poll`, etc.), interactive message components (buttons/selects as structured AppMessage extensions), bot permissions (scoped access tokens), webhook delivery (HTTP POST on events). `BotBuilder` pattern: `Bot::new().command("ping", handle_ping).on_message(handle_msg).run()`. Example bots: echo, reminder, RSS feed. - -### R. Tor/I2P Transport -**Effort**: High | **Area**: Server + Client + P2P -Anonymous transport layer for privacy-critical deployments. Server: listen on Tor hidden service (.onion) via `arti` or `tor` crate, configurable via `--tor-hidden-service`. Client: connect through SOCKS5 proxy to .onion address, `--tor-proxy socks5://127.0.0.1:9050`. P2P mesh: route through Tor for metadata-resistant peer communication. Optional I2P support via SAM bridge. All existing QUIC+TLS works over the tunnel. - -### S. Plugin Marketplace & Hot-Reload -**Effort**: Medium | **Area**: Server + Plugin API -Extend the existing plugin system into a discoverable marketplace. Plugin manifest format (TOML) with name, version, permissions, hooks. `qpq-server --plugin-dir ./plugins/` auto-loads `.so`/`.dylib` files. Hot-reload: watch plugin directory, reload on change without server restart. Plugin isolation: each plugin runs in its own thread with limited Store access. Add `qpq-gen plugin ` scaffolding. Example: spam filter plugin, message archiver. - -### T. Stress Testing & Benchmarking Suite -**Effort**: Medium | **Area**: Testing + Infra -Production-grade load testing tool. Simulate N concurrent clients: register, login, create channels, send/receive at configurable rate. Measure: messages/sec throughput, p50/p95/p99 latency, memory usage, connection limits. `cargo bench` integration for micro-benchmarks (already have some). New `qpq-loadtest` binary: `qpq-loadtest --clients 100 --rate 50/s --duration 60s --server localhost:5001`. Generate HTML report with charts. Identify bottlenecks before production. - -### U. Disappearing Media & View-Once -**Effort**: Low | **Area**: Client + Core -View-once messages that auto-delete after first viewing. Add `ViewOnce` flag to FileRef AppMessage — recipient can view the file/image once, then it's deleted locally. Server-side: auto-delete blob after first download. `/send-once ` command. Display "[view-once media]" placeholder until opened. Prevent screenshots (best-effort: clear clipboard, disable screen recording notification). Extends existing file transfer infrastructure. - -### V. Emoji Status & Presence -**Effort**: Low | **Area**: Server + Client -Lightweight presence system. Users set an emoji + short text status ("🏖️ On vacation", "🔴 Do not disturb", "🟢 Available"). Ephemeral — not stored permanently, expires after configurable duration. `publishPresence` RPC (piggyback on existing `publishEndpoint`). Client poll or push-based presence updates. `/status 🎯 Focusing` to set, `/status` to view, `/who` shows online contacts with their status. No tracking — presence is opt-in and ephemeral. - -### W. Markdown & Rich Text Messages -**Effort**: Low | **Area**: Core + Client -Rich text formatting in messages. Support a subset of Markdown in chat: **bold**, *italic*, `code`, ```code blocks```, ~~strikethrough~~, > quotes, [links](url). Parse on display (client-side only — wire format stays plain text with Markdown syntax). TUI renderer: ANSI escape codes for bold/italic/color. Browser demo: render as HTML. Add `/format on|off` toggle. No changes to MLS or wire protocol — purely presentational. - -### X. Invitation Links & QR Codes -**Effort**: Low-Medium | **Area**: Server + Client -Shareable invitation links for joining the server or a group. `createInvite` RPC generates a time-limited, usage-limited token. Format: `qpq://server:port/invite/TOKEN` or QR code encoding. `/invite create [--expires 24h] [--uses 10]` generates link. `/invite list` shows active invites. `/invite revoke ` cancels. New users can register via invite: `qpq-client --invite qpq://...`. Group invites: generate a link that auto-adds the joiner to a specific group after registration. - -### Y. Command Engine & Playbooks -**Effort**: Medium | **Area**: Client + Testing -Unified command abstraction layer making every REPL action available via code and YAML. Command registry maps string names to typed `Command` variants. YAML playbook format for declarative multi-step scenarios with variables, assertions, and loops. `qpq-client --run playbook.yaml` for batch execution. Programmatic Rust API: `engine.execute(Command::Send { ... })`. Enables: CI smoke tests, reproducible environments, bot scripting, onboarding demos, load test scenarios, migration scripts. Pairs with every other feature. - ---- - -## Selection Guide - -**Privacy-first** (maximum anonymity & security): -A (federation), D (backup), F (KT audit), N (cross-signing), R (Tor), U (view-once) - -**Production-ready** (deploy to real users): -A (federation), B (contacts), H (clustering), I (compliance), K (notifications), T (stress test) - -**User experience** (make it feel like a real messenger): -B (contacts), C (calls), G (search), J (profiles), V (presence), W (rich text), X (invites) - -**Mobile launch** (ship an app): -D (backup), J (profiles), K (notifications), L (mobile app), X (invites) - -**Developer ecosystem** (grow the community): -Q (bot framework), S (plugin marketplace), T (stress test), I (compliance) - -**Mesh/Freifunk** (offline-first, decentralized): -A (federation), N (cross-signing), O (offline queue), R (Tor) - ---- - -## Completed (this planning cycle) - -| Sprint | Feature | Status | -|--------|---------|--------| -| — | Y. Command Engine & Playbooks | Done — `command_engine.rs`, `playbook.rs`, `--run` CLI, 5 example playbooks | - -## Selected Features (fill in after choosing) - -> Pick 8 of A–X above, then we'll plan sprint assignments. - -| Sprint | Feature | Notes | -|--------|---------|-------| -| 12 | | | -| 13 | | | -| 14 | | | -| 15 | | | -| 16 | | | -| 17 | | | -| 18 | | | -| 19 | | | diff --git a/docs/V2-DESIGN-ANALYSIS.md b/docs/V2-DESIGN-ANALYSIS.md deleted file mode 100644 index 813915a..0000000 --- a/docs/V2-DESIGN-ANALYSIS.md +++ /dev/null @@ -1,380 +0,0 @@ -# quicproquo v2 — Design Analysis & Recommendations - -> Multi-perspective retrospective of the v1 architecture. -> Produced 2026-03-04 by four parallel analysis agents examining server, -> client/UX, crypto/security, and project structure/DX. - ---- - -## Executive Summary - -quicproquo v1 demonstrates strong fundamentals: QUIC-native transport, RFC 9420 -MLS group encryption, post-quantum hybrid KEM, OPAQUE zero-knowledge auth, and a -working multi-language SDK surface. These are the right bets and put the project -ahead of most open-source messengers on the crypto front. - -However, three architectural choices limit the path to production: - -1. **capnp-rpc is `!Send`** — forces single-threaded RPC handling, blocking - scalability. -2. **Monolithic client with global state** — business logic is tangled into the - REPL, duplicated across TUI/GUI/Web, and cannot be used as a library. -3. **Poll-based delivery** — 1-second polling wastes bandwidth and adds latency; - no server-push channel exists. - -A v2 should keep the crypto stack (MLS + hybrid PQ KEM + OPAQUE), keep QUIC, but -rearchitect the RPC layer, extract an SDK crate, and add push-based delivery. - ---- - -## Part 1 — What Works Well - -### Transport & Protocol -- **QUIC (quinn) + TLS 1.3** — correct choice. Built-in encryption, connection - migration, 0-RTT potential. No reason to change. -- **Cap'n Proto schemas as API contract** — zero-copy wire format, compact - binary, schema evolution via ordinals. The *schemas* are good; the *RPC - runtime* is the problem. - -### Cryptography -- **MLS (RFC 9420, openmls)** — only IETF-standard group E2E protocol. No - realistic alternative for groups > 2 members. Test suite is thorough (1005 - lines covering 2-party, 3-party, hybrid, removal, leave, stale epoch). -- **Hybrid PQ KEM (X25519 + ML-KEM-768)** — forward-thinking dual-algorithm - protection. Well-implemented with versioned wire format, proper zeroization, - and 12 targeted tests. Ahead of Signal (PQXDH, late 2023) and Matrix (no PQ). -- **OPAQUE (RFC 9497)** — server never sees passwords. Ristretto255 + Argon2id - is best-in-class. -- **Sealed sender, safety numbers, message padding** — all clean, simple, - correct. Safety numbers match Signal's 5200-iteration HMAC-SHA256 cost. -- **Zeroization discipline** — secrets wrapped in `Zeroizing`, Debug impls - redact keys, no `.unwrap()` in crypto paths. -- **WASM feature gating** — `core/native` cleanly separates WASM-safe crypto - from native-only modules (MLS, OPAQUE, filesystem). - -### Server Design -- **Store trait abstraction** — 30+ methods, clean backend swap (SqlStore vs - FileBackedStore). Well-factored. -- **OPAQUE auth with timing floors** — `resolveUser`/`resolveIdentity` mask - lookup timing to prevent username enumeration. -- **Delivery proofs** — Ed25519-signed receipt of server acceptance. Clients get - cryptographic evidence. -- **`wasNew` flag on createChannel** — elegantly solves the dual-MLS-group race - condition where both DM parties try to initialize. -- **Plugin hooks (C-ABI)** — `#![no_std]` vtable, zero dependencies, chained - hooks with continue/reject protocol. Clean extensibility. -- **Production config validation** — enforces encrypted storage, strong auth - tokens, pre-existing TLS certs. - -### Client & DX -- **Zero-config local dev** — `qpq --username alice --password pass` auto-starts - server, generates TLS certs, registers, and logs in. Genuinely excellent. -- **Encrypted-at-rest everything** — state file (QPCE), conversation DB - (SQLCipher), session cache. Argon2id + ChaCha20-Poly1305 throughout. -- **Playbook system** — YAML-scripted command execution with assertions. Great - for CI/integration testing. -- **Conversation store** — SQLite with deduplication, outbox for offline - queuing, activity tracking. -- **Conventional commits, GPG-signed** — consistent `feat:`/`fix:`/`docs:` - discipline. -- **Security lints enforced by build** — `clippy::unwrap_used = "deny"`, - `unsafe_code = "warn"`. - ---- - -## Part 2 — What Needs Rethinking - -### 2.1 RPC Layer: capnp-rpc is the #1 Scalability Bottleneck - -**Problem:** `capnp-rpc` uses `Rc` internally and is `!Send`. Everything runs on -a `LocalSet` with `spawn_local`. All 27 RPC methods serialize through a single -thread. No work-stealing, no multi-core utilization. - -**Impact:** With 1000+ concurrent clients, the single-threaded executor cannot -keep up. A slow `fetchWait` (30s timeout) blocks the entire connection. - -**Also:** The WebSocket bridge (`ws_bridge.rs`, 645 lines) exists solely because -Cap'n Proto cannot run in browsers. This duplicates handler logic and creates -maintenance burden. - -### 2.2 Client Architecture: Monolith with Global State - -**Problem:** `AUTH_CONTEXT` is a process-wide `RwLock>`. -Business logic (MLS processing, sealed sender, hybrid decryption, message -routing) lives inside `repl.rs`'s `poll_messages()` — a 100-line function that -mixes transport, crypto, routing, and storage. - -**Impact:** Every frontend (REPL, TUI, GUI, Web) must reimplement message -processing. The TUI already duplicates it. The GUI stub and mobile PoC would need -yet another copy. Client cannot be used as a library. - -### 2.3 Delivery Model: Poll-Based, No Push Channel - -**Problem:** Client polls every 1 second with `fetch_wait(timeout_ms=0)` — never -actually long-polls. Constant network traffic even when idle. ~1 second latency -for message delivery. - -**Also:** `fetch` is destructive (drains queue). If the client crashes between -receive and processing, messages are lost. - -### 2.4 Connection Model: Single Stream - -**Problem:** `max_concurrent_bidi_streams(1)` means the entire QUIC connection is -effectively single-stream. A blocking `fetchWait` prevents all other RPCs. - -### 2.5 Storage: Single Mutex-Guarded SQLite Connection - -**Problem:** `SqlStore` uses `Mutex`. Every database operation -acquires a global lock. Under concurrent load, all storage access serializes. - -**Also:** `FileBackedStore` flushes the entire map on every write (O(n) I/O). -Sessions are in-memory only — server restart forces all clients to re-login. - -### 2.6 Key Management Gaps - -- **DiskKeyStore** — HPKE private keys stored as plaintext bincode on disk. No - encryption at rest. -- **MLS group state** — `GroupMember` holds `MlsGroup` in memory only. Process - crash loses all group state. -- **Token zeroization** — `AuthContext.token`, `ClientAuth.access_token` are not - wrapped in `Zeroizing`. - -### 2.7 Workspace Bloat - -12 crates for a project at this maturity is excessive. Several are thin stubs -(`quicproquo-gen`, `quicproquo-bot` at 354 lines) or broken (`quicproquo-gui` -fails `cargo build --workspace`). - ---- - -## Part 3 — v2 Architecture Recommendations - -### 3.1 Replace capnp-rpc with a Send-Compatible RPC Framework - -**Recommendation:** Switch to **tonic (gRPC)** or a custom framing layer. - -| Dimension | capnp-rpc (v1) | tonic/gRPC (v2) | -|-----------|---------------|-----------------| -| Threading | `!Send`, single-threaded | `Send + Sync`, multi-threaded | -| Browser | Requires WS bridge | grpc-web native | -| Streaming | Not supported | Built-in | -| Middleware | None (copy-paste auth) | Interceptors/layers | -| Ecosystem | Niche | Massive (every language) | - -**Alternative:** Keep Cap'n Proto *schemas* for serialization (zero-copy -advantage) but replace capnp-rpc with custom framing over QUIC streams. This -preserves the wire format while gaining `Send` compatibility. - -The WS bridge would be eliminated entirely — grpc-web or WebTransport gives -browsers direct access. - -### 3.2 Extract an SDK Crate (Most Important Client Change) - -Create `quicproquo-sdk` that owns all business logic: - -``` -quicproquo-sdk/ - src/ - client.rs -- QpqClient: connect, login, send, receive - events.rs -- ClientEvent enum (push-based) - conversation.rs -- ConversationHandle, group management - crypto.rs -- MLS pipeline, sealed sender, hybrid decryption - sync.rs -- message sync, offline queue, retry -``` - -All frontends become thin shells: - -``` -CLI/REPL -> calls sdk -TUI -> calls sdk -Tauri GUI -> calls sdk (via Tauri commands) -Mobile -> calls sdk (via C FFI) -Web/WASM -> calls sdk (compiled to wasm32) -``` - -**Key API shape:** -```rust -pub struct QpqClient { /* session, rpc, crypto pipeline */ } - -impl QpqClient { - pub async fn connect(config: ClientConfig) -> Result; - pub async fn login(username: &str, password: &str) -> Result; - pub async fn dm(&mut self, username: &str) -> Result; - pub async fn create_group(&mut self, name: &str) -> Result; - pub async fn send(&mut self, text: &str) -> Result; - pub fn subscribe(&self) -> Receiver; -} -``` - -No global state. No `AUTH_CONTEXT`. Auth context is per-`QpqClient` instance. - -### 3.3 Add Push-Based Delivery - -**Recommendation:** Dedicated QUIC unidirectional stream for server-push -notifications. - -``` -Client opens bidi stream 0 -> RPC channel (request/response) -Server opens uni stream 1 -> push notifications (new message, typing, etc.) -``` - -Benefits: -- Zero-latency message delivery (no polling) -- No idle network traffic -- Typing indicators delivered in real-time -- Graceful degradation: fall back to long-poll if push stream fails - -**Also:** Make `peek` + `ack` the default delivery pattern (not destructive -`fetch`). Add idempotency keys to prevent duplicate messages on retry. - -### 3.4 Multi-Stream Connections - -Allow 4-8 concurrent bidirectional QUIC streams per connection. This enables: -- Pipelined RPCs (send while fetching) -- Concurrent blob upload + chat -- `fetchWait` on one stream without blocking others - -### 3.5 Storage Improvements - -| Change | Rationale | -|--------|-----------| -| Drop `FileBackedStore` | O(n) flush per write, no federation support | -| Connection pool for SQLite | Replace `Mutex` with r2d2/deadpool | -| Persist sessions to DB | Server restart shouldn't force re-login | -| Encrypt DiskKeyStore at rest | HPKE private keys in plaintext is a real vuln | -| Persist MLS group state | Process crash shouldn't lose group state | -| Atomic keystore writes | tempfile-then-rename pattern | - -### 3.6 Crypto Stack Refinements - -The algorithms are correct. The refinements are operational: - -| Change | Rationale | -|--------|-----------| -| Typed MLS error variants | Stop losing error info via `format!("{e:?}")` | -| Formalize hybrid PQ ciphersuite ID | Replace length-based key detection | -| Remove all InsecureServerCertVerifier | No TLS bypass on any platform | -| Add passkey/WebAuthn alt-auth | Better UX for GUI/mobile, no password to forget | -| Consider Double Ratchet for 1:1 DMs | MLS is over-engineered for 2-party; DR gives better per-message forward secrecy | -| Token/session secret zeroization | `AuthContext.token` et al. need `Zeroizing` wrappers | -| Fix serde deserialization of secrets | Intermediate non-zeroized `Vec` in `IdentityKeypair::deserialize` | - -### 3.7 Workspace Restructuring - -**Reduce from 12 to 8 crates:** - -``` -quicproquo-core -- crypto primitives (keep) -quicproquo-proto -- schema codegen (keep) -quicproquo-plugin-api -- #![no_std] C-ABI (keep) -quicproquo-kt -- key transparency (keep) -quicproquo-sdk -- NEW: business logic library -quicproquo-server -- server binary (keep) -quicproquo-client -- CLI/TUI binary, depends on sdk (keep, slimmed) -quicproquo-p2p -- mesh networking (keep, feature-flagged) -``` - -**Merge/remove:** -- `bot` -> `sdk::bot` module -- `ffi` -> `sdk` with `--features c-ffi` -- `gen` -> `scripts/` or `xtask` -- `gui` -> `apps/gui/` outside workspace (Tauri project) -- `mobile` -> `examples/` (research spike) - -**Add `[workspace.default-members]`** so `cargo build` doesn't attempt GUI. -**Add `justfile`** with `build`, `test`, `test-e2e`, `build-wasm`, `docker`. - -### 3.8 Plugin System Evolution - -| Change | Rationale | -|--------|-----------| -| Add `version: u32` to `HookVTable` | ABI stability — check version on load | -| Config passthrough | `qpq_plugin_init(vtable, config_json)` | -| Async hooks | Plugins that call external services shouldn't block Tokio | -| Evaluate WASM plugins | Sandboxed community plugins (keep C-ABI for first-party) | - -### 3.9 Federation Improvements - -| Change | Rationale | -|--------|-----------| -| DNS SRV / .well-known discovery | Static peer config doesn't scale | -| Persistent relay queue with retry | Messages to offline peers are currently lost | -| Deterministic channel ID derivation | Avoid cross-server channel conflicts | -| Keep mDNS as optional mesh feature | Not for internet-scale, but good for LAN | - -### 3.10 Test & CI Improvements - -| Change | Rationale | -|--------|-----------| -| Per-client auth context | Removes `--test-threads 1` constraint | -| Mock server for client unit tests | Fast tests without spawning real server | -| Fuzz testing (cargo-fuzz) | Hybrid KEM, sealed sender, padding, Cap'n Proto deser | -| WS bridge unit tests | 645 lines, zero tests, security-critical | -| WASM + Go SDK in CI | Currently untested in CI | -| Separate E2E from unit test CI job | Different speed, different failure modes | -| macOS CI | FFI/mobile cross-compilation validation | -| Release automation | Binary artifacts, Docker tags, WASM npm publish | - ---- - -## Part 4 — Ecosystem Positioning - -### Don't compete with Signal or Matrix directly. - -**Target: Privacy-first messaging infrastructure for developers and -organizations.** - -quicproquo's differentiators — QUIC-native transport, post-quantum crypto, MLS, -plugin system, multi-language SDKs, embeddable architecture — point toward an -infrastructure play, not a consumer app. - -Think: *"the Postgres of E2E encrypted messaging"* — a high-quality open-source -server and protocol that other projects build on. - -| Segment | Value Proposition | -|---------|-------------------| -| **Developer tool** | API-first messenger for encrypted bots and integrations | -| **Embeddable** | C FFI + WASM + Go SDK for embedding in other apps | -| **Enterprise** | On-prem, plugins for compliance/audit, OPAQUE zero-knowledge auth | -| **Research** | Post-quantum crypto, MLS reference implementation, mesh networking | - ---- - -## Part 5 — Priority Ordering - -### Phase 1: Foundation (unblocks everything else) -1. Replace capnp-rpc with Send-compatible framework -2. Extract SDK crate from client -3. Per-client auth context (no global state) - -### Phase 2: Reliability -4. Push-based delivery (QUIC uni-stream) -5. Multi-stream connections -6. Persist sessions + MLS group state -7. Encrypt DiskKeyStore at rest -8. peek+ack as default delivery - -### Phase 3: Polish -9. Workspace restructuring (12 -> 8 crates) -10. TUI as primary interactive mode (built on SDK) -11. Plugin system v2 (versioning, config, async) -12. Federation retry queue + discovery - -### Phase 4: Ecosystem -13. Full MLS in WASM (browser E2E) -14. WebTransport (eliminate WS bridge) -15. Tauri GUI (built on SDK) -16. Release automation + expanded CI - ---- - -## Appendix — Analysis Sources - -This document was produced by four parallel analysis agents: - -| Agent | Scope | Files Read | -|-------|-------|-----------| -| server-analyst | Transport, RPC, delivery, storage, federation | 27 server .rs files, 4 schemas, core transport | -| client-analyst | REPL, UX, state, multi-platform, SDK design | All client .rs, GUI, mobile, TS demo | -| security-analyst | MLS, OPAQUE, hybrid KEM, keystore, identity | All core .rs, review doc | -| dx-analyst | Workspace, build, tests, plugins, CI, ecosystem | All Cargo.toml, tests, CI, plugins, SDKs | diff --git a/docs/V2-MASTER-PLAN.md b/docs/V2-MASTER-PLAN.md deleted file mode 100644 index c477a11..0000000 --- a/docs/V2-MASTER-PLAN.md +++ /dev/null @@ -1,328 +0,0 @@ -# quicproquo v2 — Master Implementation Plan - -> Created 2026-03-04. This is the authoritative plan for the v2 rewrite. -> See also: `docs/V2-DESIGN-ANALYSIS.md` for the detailed retrospective. - -## Context - -The v1 codebase has strong crypto foundations (MLS, hybrid PQ KEM, OPAQUE) but three -architectural bottlenecks: capnp-rpc is `!Send` (single-threaded), client business logic -is trapped in a monolithic REPL with global state, and delivery is poll-based. - -This plan creates v2 on a new branch, keeping the crypto stack intact and replacing -the RPC/transport layer, extracting an SDK, and restructuring the workspace. - -**Key decisions:** -- Transport: Protobuf (prost) + custom framing over QUIC (quinn) -- Mobile: Tauri 2 (same Rust SDK backend, web UI) -- Branch strategy: `v2` branch from main, not a fresh repo -- Constraints: Rust, QUIC, GPG-signed commits, zeroize secrets, no stubs - ---- - -## Architecture Overview - -``` -┌─────────────────────────────────────────────────────┐ -│ Frontends │ -│ CLI/TUI │ Tauri GUI/Mobile │ Web (WebTransport)│ -└─────┬─────┴────────┬───────────┴──────────┬─────────┘ - │ │ │ - ▼ ▼ ▼ -┌─────────────────────────────────────────────────────┐ -│ quicproquo-sdk │ -│ QpqClient { connect, login, send, recv, subscribe } │ -│ Event system (tokio broadcast) │ -│ Crypto pipeline (MLS, sealed sender, hybrid) │ -│ Conversation store (SQLCipher) │ -└──────────────────────┬──────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────┐ -│ quicproquo-rpc │ -│ QUIC framing: [method:u16][req_id:u32][len:u32][pb] │ -│ Multi-stream (1 RPC per stream) │ -│ Server-push via uni-streams │ -│ tower middleware (auth, rate-limit) │ -└──────────────────────┬──────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────┐ -│ quicproquo-server │ -│ Domain services (auth, delivery, channel, blob) │ -│ Store trait → SqlStore (connection pool) │ -│ Plugin hooks, federation, KT │ -└─────────────────────────────────────────────────────┘ -``` - -### Wire Format - -Per QUIC bidirectional stream (request/response): -``` -Request: [method_id: u16][request_id: u32][payload_len: u32][protobuf bytes] -Response: [status: u8][request_id: u32][payload_len: u32][protobuf bytes] -``` - -Per QUIC unidirectional stream (server → client push): -``` -Push: [event_type: u16][payload_len: u32][protobuf bytes] -``` - -Each RPC opens its own QUIC bidi stream → natural multi-stream, no head-of-line blocking. - ---- - -## Workspace Structure (v2: 9 crates) - -``` -quicproquo/ -├── crates/ -│ ├── quicproquo-core/ # KEEP AS-IS — crypto primitives, MLS, hybrid KEM -│ ├── quicproquo-kt/ # KEEP AS-IS — key transparency -│ ├── quicproquo-plugin-api/ # KEEP AS-IS — #![no_std] C-ABI -│ ├── quicproquo-proto/ # REWRITE — protobuf schemas + prost codegen -│ ├── quicproquo-rpc/ # NEW — QUIC RPC framework (framing, dispatch, tower) -│ ├── quicproquo-sdk/ # NEW — client business logic library -│ ├── quicproquo-server/ # REWRITE — domain services + RPC handlers -│ ├── quicproquo-client/ # REWRITE — thin CLI/TUI shell over SDK -│ └── quicproquo-p2p/ # KEEP — iroh mesh (feature-flagged, later) -├── apps/ -│ └── gui/ # Tauri 2 desktop + mobile app (outside workspace) -├── proto/ # .proto source files -│ └── qpq/v1/ -│ ├── auth.proto # OPAQUE registration + login (4 methods) -│ ├── delivery.proto # enqueue, fetch, peek, ack, batch (6 methods) -│ ├── keys.proto # key package + hybrid key CRUD (5 methods) -│ ├── channel.proto # channel create (1 method) -│ ├── user.proto # resolve user/identity (2 methods) -│ ├── blob.proto # upload/download (2 methods) -│ ├── device.proto # register/list/revoke (3 methods) -│ ├── p2p.proto # endpoint publish/resolve + health (3 methods) -│ ├── federation.proto # relay + proxy (6 methods) -│ ├── push.proto # server-push events (NEW) -│ └── common.proto # shared types (Auth, Envelope, Error) -├── sdks/ -│ ├── go/ # Go SDK (regenerate from .proto) -│ └── typescript/ # TS SDK (WebTransport client) -├── justfile # NEW — build commands -└── Cargo.toml # workspace root -``` - -**Removed from workspace:** -- `quicproquo-bot` → `sdk::bot` module -- `quicproquo-ffi` → `sdk` with `--features c-ffi` -- `quicproquo-gen` → `scripts/` -- `quicproquo-gui` → `apps/gui/` (Tauri project, outside workspace) -- `quicproquo-mobile` → merged into `apps/gui/` (Tauri 2 mobile) - ---- - -## Crate Reuse Assessment - -| v1 Crate | capnp deps? | v2 Action | Effort | -|----------|:-----------:|-----------|--------| -| **quicproquo-core** | None | Copy as-is | Zero | -| **quicproquo-kt** | None | Copy as-is | Zero | -| **quicproquo-plugin-api** | None | Copy as-is | Zero | -| **quicproquo-p2p** | None | Copy as-is | Zero | -| **quicproquo-proto** | 100% capnp | Replace with prost codegen | Medium | -| **quicproquo-server** | 16/20 files | Extract domain logic, rewrite handlers | High | -| **quicproquo-client** | 6/10 files | Extract to SDK, thin CLI shell | High | - -### Key Files to Reuse Directly - -| Source (v1) | Destination (v2) | Notes | -|-------------|------------------|-------| -| `crates/quicproquo-core/` (entire) | same path | Zero changes | -| `crates/quicproquo-kt/` (entire) | same path | Zero changes | -| `crates/quicproquo-plugin-api/` (entire) | same path | Zero changes | -| `server/src/storage.rs` | `server/src/storage.rs` | Store trait — keep | -| `server/src/sql_store.rs` | `server/src/sql_store.rs` | Add connection pool | -| `server/src/hooks.rs` | `server/src/hooks.rs` | Plugin system — keep | -| `server/src/plugin_loader.rs` | `server/src/plugin_loader.rs` | Keep | -| `server/src/error_codes.rs` | `server/src/error_codes.rs` | Keep | -| `server/src/config.rs` | `server/src/config.rs` | Update for new transport | -| `client/src/conversation.rs` | `sdk/src/conversation.rs` | Move to SDK | -| `client/src/token_cache.rs` | `sdk/src/token_cache.rs` | Move to SDK | -| `client/src/display.rs` | `client/src/display.rs` | Keep in CLI | -| `schemas/*.capnp` | reference only | Translate to .proto | - ---- - -## Phased Implementation - -### Phase 1: Foundation -**Goal:** v2 branch with new workspace, proto schemas, RPC framework skeleton, SDK skeleton. -**Scope:** Compiles, no runtime functionality yet. - -1. **Create v2 branch** from main -2. **Restructure workspace** — update root Cargo.toml, create new crate dirs, add justfile -3. **Write .proto files** — translate all 33 RPC methods + push events from Cap'n Proto -4. **Create quicproquo-proto crate** — prost-build codegen -5. **Create quicproquo-rpc crate** — QUIC RPC framework: - - `framing.rs` — wire format encode/decode (request, response, push) - - `server.rs` — accept QUIC connections, dispatch to handlers - - `client.rs` — connect, send requests, receive responses + push events - - `middleware.rs` — tower-based auth + rate-limit layers - - `method.rs` — method registry (method_id → async handler fn) -6. **Create quicproquo-sdk crate** — public API skeleton: - - `client.rs` — `QpqClient` struct - - `events.rs` — `ClientEvent` enum - - `conversation.rs` — `ConversationHandle`, `ConversationStore` - - `config.rs` — `ClientConfig` -7. **Extract server domain types** — `server/src/domain/` module: - - `types.rs` — plain Rust request/response types - - `auth.rs` — OPAQUE logic extracted from auth_ops.rs - - `delivery.rs` — enqueue/fetch logic extracted from delivery.rs - -**Verification:** -- `cargo build --workspace` succeeds -- `cargo test -p quicproquo-core` passes (72 tests) -- Proto codegen works -- RPC framework compiles - ---- - -### Phase 2: Server Core -**Goal:** Working server with all 33 RPC handlers over QUIC. - -1. **RPC dispatch** — method registry, connection lifecycle -2. **Domain handlers** — all 33 methods as `async fn(Request) -> Result` - - Auth (4): OPAQUE register start/finish, login start/finish - - Delivery (6): enqueue, fetch, fetchWait, peek, ack, batchEnqueue - - Keys (5): upload/fetch key package, upload/fetch/batch-fetch hybrid key - - Channels (1): createChannel - - Users (2): resolveUser, resolveIdentity - - Blobs (2): uploadBlob, downloadBlob - - Devices (3): registerDevice, listDevices, revokeDevice - - P2P (3): health, publishEndpoint, resolveEndpoint - - Federation (6): relay enqueue/batch, proxy fetch/resolve, health -3. **Server-push** — notification stream via QUIC uni-stream -4. **Storage upgrades:** - - Drop `FileBackedStore` - - Connection pool (deadpool-sqlite) - - Persist sessions to SQLite - - Atomic queue depth check + enqueue -5. **Tower middleware** — auth validation, rate limiting, audit logging -6. **Multi-stream** — concurrent RPCs per connection (remove 1-stream limit) - -**Verification:** -- Server starts, accepts QUIC connections -- Health check RPC works -- OPAQUE registration + login works -- Message enqueue + fetch round-trip - ---- - -### Phase 3: SDK -**Goal:** Complete client SDK library — the heart of v2. - -1. **QpqClient** — connect, OPAQUE auth, session management (no global state) -2. **Crypto pipeline** — MLS processing, sealed sender unwrap, hybrid decrypt - (extracted from repl.rs `poll_messages()`) -3. **Conversation management** — create DM, create group, invite, remove, send, receive -4. **Event system** — `tokio::broadcast` replacing poll loop - - `MessageReceived`, `TypingIndicator`, `ConversationCreated` - - `MemberJoined`, `MemberLeft`, `ConnectionLost`, `Reconnected` -5. **Offline support** — outbox queue, retry with backoff, sync on reconnect -6. **ConversationStore** — SQLCipher local DB (migrate from client/conversation.rs) -7. **Key management** — encrypted DiskKeyStore, MLS group state persistence -8. **Token/secret zeroization** — `AuthContext.token` etc. wrapped in `Zeroizing` - -**Verification:** -- SDK integration test: connect → login → create DM → send → receive -- No global state (`AUTH_CONTEXT` eliminated) -- Event subscription works -- Offline outbox drains on reconnect - ---- - -### Phase 4: Client -**Goal:** CLI and TUI as thin shells over SDK. - -1. **CLI binary** (`qpq`) — clap subcommands calling `QpqClient` -2. **REPL** — readline with tab-completion (rustyline), categorized `/help` -3. **TUI** — ratatui, subscribes to `QpqClient::subscribe()` events -4. **Simplified commands:** - - Hide MLS/KeyPackage internals (auto-refresh) - - Message references by short ID (not index) - - Batch operations (`/create-group team alice bob`) - - Categorized help (Chat, Groups, Security, System) -5. **Auto-server-launch** — keep zero-config DX from v1 -6. **Playbook system** — keep YAML-based test scripting - -**Verification:** -- `qpq --username alice --password pass` starts REPL (same UX as v1) -- TUI mode works with live event updates -- Tab-completion for commands and usernames -- E2E test: two clients exchange messages - ---- - -### Phase 5: Desktop & Mobile -**Goal:** Tauri 2 app for all platforms. - -1. **Tauri 2 project** in `apps/gui/` -2. **Rust backend** — Tauri commands wrapping `QpqClient` -3. **Web frontend** — Svelte or vanilla HTML/JS -4. **Desktop** — Linux, macOS, Windows -5. **Mobile** — iOS, Android via Tauri 2 mobile -6. **QUIC connection migration** — automatic wifi↔cellular handoff - -**Verification:** -- Desktop app builds and runs on Linux -- Mobile app builds for Android (emulator) -- Send message from CLI → received in GUI - ---- - -### Phase 6: Polish & Ecosystem -**Goal:** Production readiness. - -1. **Federation improvements** — DNS SRV discovery, persistent relay queue with retry -2. **Plugin system v2** — version field, config passthrough, async hooks, WASM plugins -3. **WebTransport** — browser clients over HTTP/3 (same quinn endpoint) -4. **WASM MLS** — compile openmls to wasm32 for browser E2E encryption -5. **CI/CD** — release automation, WASM CI, multi-platform (Linux + macOS) -6. **Security hardening:** - - Fuzz testing (hybrid KEM, sealed sender, padding, protobuf deser) - - Remove all `InsecureServerCertVerifier` paths - - Certificate pinning - - Add passkey/WebAuthn as alternative auth -7. **Double Ratchet for 1:1 DMs** — better per-message forward secrecy than MLS for 2-party - ---- - -## RPC Method Inventory (33 total) - -| Category | Methods | Proto File | -|----------|---------|-----------| -| Auth (OPAQUE) | opaqueRegisterStart, opaqueRegisterFinish, opaqueLoginStart, opaqueLoginFinish | auth.proto | -| Delivery | enqueue, fetch, fetchWait, peek, ack, batchEnqueue | delivery.proto | -| Keys | uploadKeyPackage, fetchKeyPackage, uploadHybridKey, fetchHybridKey, fetchHybridKeys | keys.proto | -| Channel | createChannel | channel.proto | -| User | resolveUser, resolveIdentity | user.proto | -| Blob | uploadBlob, downloadBlob | blob.proto | -| Device | registerDevice, listDevices, revokeDevice | device.proto | -| P2P | health, publishEndpoint, resolveEndpoint | p2p.proto | -| Federation | relayEnqueue, relayBatchEnqueue, proxyFetchKeyPackage, proxyFetchHybridKey, proxyResolveUser, federationHealth | federation.proto | - -**New in v2:** -| Push Events | Description | Proto File | -|-------------|-------------|-----------| -| MessageNotification | New message available | push.proto | -| TypingNotification | Peer is typing | push.proto | -| ChannelUpdate | Channel created/member changed | push.proto | -| SessionExpired | Auth session expired | push.proto | - ---- - -## Engineering Standards (carried from v1) - -- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `test:`, `refactor:` -- GPG-signed commits only -- No `Co-authored-by` trailers -- No `.unwrap()` on crypto or I/O in non-test paths -- Secrets: zeroize on drop, never in logs -- No stubs / `todo!()` / `unimplemented!()` in production code -- `clippy::unwrap_used = "deny"` at workspace level