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)
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -17,3 +17,6 @@ data/
|
|||||||
*.convdb-wal
|
*.convdb-wal
|
||||||
*.pending.ks
|
*.pending.ks
|
||||||
qpq-server.toml
|
qpq-server.toml
|
||||||
|
|
||||||
|
# Internal planning docs (not for public distribution)
|
||||||
|
docs/internal/
|
||||||
|
|||||||
40
CONTRIBUTING.md
Normal file
40
CONTRIBUTING.md
Normal file
@@ -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).
|
||||||
@@ -14,6 +14,14 @@ members = [
|
|||||||
"crates/quicproquo-p2p",
|
"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.
|
# Shared dependency versions — bump here to affect the whole workspace.
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
||||||
|
|||||||
30
LICENSE
Normal file
30
LICENSE
Normal file
@@ -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.
|
||||||
661
LICENSE-AGPL-3.0
Normal file
661
LICENSE-AGPL-3.0
Normal file
@@ -0,0 +1,661 @@
|
|||||||
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
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.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
199
LICENSE-APACHE
Normal file
199
LICENSE-APACHE
Normal file
@@ -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.
|
||||||
21
LICENSE-MIT
Normal file
21
LICENSE-MIT
Normal file
@@ -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.
|
||||||
@@ -210,11 +210,9 @@ mdbook serve docs # http://localhost:3000
|
|||||||
- [Scaling Guide](docs/operations/scaling-guide.md) — resource sizing, horizontal scaling, capacity planning
|
- [Scaling Guide](docs/operations/scaling-guide.md) — resource sizing, horizontal scaling, capacity planning
|
||||||
- [Monitoring](docs/operations/monitoring.md) — Prometheus metrics, Grafana dashboards, alert rules
|
- [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.
|
> **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.
|
||||||
|
|
||||||
If you discover a security vulnerability, please report it privately.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
29
SECURITY.md
Normal file
29
SECURITY.md
Normal file
@@ -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.
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "quicproquo-client"
|
name = "quicproquo-client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition.workspace = true
|
||||||
description = "CLI client for quicproquo."
|
description = "CLI client for quicproquo."
|
||||||
license = "MIT"
|
license = "Apache-2.0 OR MIT"
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "qpq"
|
name = "qpq"
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "quicproquo-core"
|
name = "quicproquo-core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition.workspace = true
|
||||||
description = "Crypto primitives, MLS state machine, and hybrid post-quantum KEM for quicproquo."
|
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]
|
[features]
|
||||||
default = ["native"]
|
default = ["native"]
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "quicproquo-kt"
|
name = "quicproquo-kt"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition.workspace = true
|
||||||
description = "Key Transparency: append-only SHA-256 Merkle log for (username, identity_key) bindings."
|
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]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "quicproquo-p2p"
|
name = "quicproquo-p2p"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition.workspace = true
|
||||||
description = "P2P transport layer for quicproquo using iroh."
|
description = "P2P transport layer for quicproquo using iroh."
|
||||||
license = "MIT"
|
license = "Apache-2.0 OR MIT"
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
traffic-resistance = []
|
traffic-resistance = []
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "quicproquo-plugin-api"
|
name = "quicproquo-plugin-api"
|
||||||
version = "0.1.0"
|
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."
|
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]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "quicproquo-proto"
|
name = "quicproquo-proto"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition.workspace = true
|
||||||
description = "Protocol types for quicproquo — v1 Cap'n Proto (legacy) + v2 Protobuf (prost)"
|
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"
|
build = "build.rs"
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "quicproquo-rpc"
|
name = "quicproquo-rpc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition.workspace = true
|
||||||
description = "QUIC RPC framework for quicproquo v2 — framing, dispatch, tower middleware"
|
description = "QUIC RPC framework for quicproquo v2 — framing, dispatch, tower middleware"
|
||||||
|
license = "Apache-2.0 OR MIT"
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quicproquo-proto = { path = "../quicproquo-proto" }
|
quicproquo-proto = { path = "../quicproquo-proto" }
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "quicproquo-sdk"
|
name = "quicproquo-sdk"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition.workspace = true
|
||||||
description = "Client SDK for quicproquo v2 — connect, auth, send, receive, subscribe"
|
description = "Client SDK for quicproquo v2 — connect, auth, send, receive, subscribe"
|
||||||
|
license = "Apache-2.0 OR MIT"
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quicproquo-core = { path = "../quicproquo-core" }
|
quicproquo-core = { path = "../quicproquo-core" }
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "quicproquo-server"
|
name = "quicproquo-server"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition.workspace = true
|
||||||
description = "Delivery Service and Authentication Service for quicproquo."
|
description = "Delivery Service and Authentication Service for quicproquo."
|
||||||
license = "MIT"
|
license = "AGPL-3.0-only"
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
traffic-resistance = []
|
traffic-resistance = []
|
||||||
|
|||||||
@@ -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/<crate>/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_<what>_<expected_outcome>` (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*
|
|
||||||
@@ -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<Vec<u8>, StorageError>`, `get_channel_members(&self, channel_id: &[u8]) -> Result<Option<(Vec<u8>, Vec<u8>)>, 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)
|
|
||||||
@@ -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<Option<ClientAuth>>`
|
|
||||||
**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<u8>`
|
|
||||||
**Source:** Security | **File:** `crates/quicproquo-core/src/hybrid_kem.rs:162`
|
|
||||||
Hybrid private key material lingers in memory.
|
|
||||||
**Fix:** Return `Zeroizing<Vec<u8>>`.
|
|
||||||
|
|
||||||
### 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<Vec<u8>>`.
|
|
||||||
|
|
||||||
### M8. Client `ClientAuth.access_token` not zeroized
|
|
||||||
**Source:** Security | **File:** `crates/quicproquo-client/src/lib.rs:50-55`
|
|
||||||
**Fix:** Use `Zeroizing<Vec<u8>>`.
|
|
||||||
|
|
||||||
### M9. `SessionState.password` stores plaintext password in memory
|
|
||||||
**Source:** Security | **File:** `crates/quicproquo-client/src/client/session.rs:29`
|
|
||||||
**Fix:** Use `Zeroizing<String>`, 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<String>` 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
|
|
||||||
@@ -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 <domain>` 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 <user>`, `/unblock <user>`. 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 <user>`, `/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 <path>` and `/restore <path>` 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 <user> admin|mod|member`, `/mute <user> <duration>`. 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 <username>` to verify a user's key history is consistent, `/kt monitor` to continuously watch for key changes, `/kt proof <username>` 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 <query>` returns matching messages with context, timestamps, and conversation names. `/search <query> in:<conversation>` 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 <name>`, `/profile set-status <text>`, `/profile set-avatar <path>`, `/profile <username>` 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 <conversation>`, `/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 <msg-index>` 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 <user>` 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 <name>` 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 <path>` 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 <id>` 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 | | |
|
|
||||||
@@ -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<Option<ClientAuth>>`.
|
|
||||||
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<Connection>`. 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<Self>;
|
|
||||||
pub async fn login(username: &str, password: &str) -> Result<Self>;
|
|
||||||
pub async fn dm(&mut self, username: &str) -> Result<ConversationHandle>;
|
|
||||||
pub async fn create_group(&mut self, name: &str) -> Result<ConversationHandle>;
|
|
||||||
pub async fn send(&mut self, text: &str) -> Result<MessageId>;
|
|
||||||
pub fn subscribe(&self) -> Receiver<ClientEvent>;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
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<Connection>` 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<u8>` 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 |
|
|
||||||
@@ -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<Response>`
|
|
||||||
- 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<ClientEvent>` 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
|
|
||||||
Reference in New Issue
Block a user