Remove LegacyCDS
This commit is contained in:
parent
13785a0936
commit
7f0a66847b
12 changed files with 28 additions and 1124 deletions
|
@ -2176,339 +2176,6 @@ Signal Desktop makes use of the following open source projects.
|
||||||
|
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|
||||||
## node-forge
|
|
||||||
|
|
||||||
You may use the Forge project under the terms of either the BSD License or the
|
|
||||||
GNU General Public License (GPL) Version 2.
|
|
||||||
|
|
||||||
The BSD License is recommended for most projects. It is simple and easy to
|
|
||||||
understand and it places almost no restrictions on what you can do with the
|
|
||||||
Forge project.
|
|
||||||
|
|
||||||
If the GPL suits your project better you are also free to use Forge under
|
|
||||||
that license.
|
|
||||||
|
|
||||||
You don't have to do anything special to choose one license or the other and
|
|
||||||
you don't have to notify anyone which license you are using. You are free to
|
|
||||||
use this project in commercial projects as long as the copyright header is
|
|
||||||
left intact.
|
|
||||||
|
|
||||||
If you are a commercial entity and use this set of libraries in your
|
|
||||||
commercial software then reasonable payment to Digital Bazaar, if you can
|
|
||||||
afford it, is not required but is expected and would be appreciated. If this
|
|
||||||
library saves you time, then it's saving you money. The cost of developing
|
|
||||||
the Forge software was on the order of several hundred hours and tens of
|
|
||||||
thousands of dollars. We are attempting to strike a balance between helping
|
|
||||||
the development community while not being taken advantage of by lucrative
|
|
||||||
commercial entities for our efforts.
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
New BSD License (3-clause)
|
|
||||||
Copyright (c) 2010, Digital Bazaar, Inc.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of Digital Bazaar, Inc. nor the
|
|
||||||
names of its contributors may be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL DIGITAL BAZAAR BE LIABLE FOR ANY
|
|
||||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
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
|
|
||||||
this service 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.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
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
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the 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 a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE 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.
|
|
||||||
|
|
||||||
## normalize-path
|
## normalize-path
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
11
app/main.ts
11
app/main.ts
|
@ -378,16 +378,9 @@ async function prepareUrl(
|
||||||
const theme = await getResolvedThemeSetting();
|
const theme = await getResolvedThemeSetting();
|
||||||
|
|
||||||
const directoryConfig = directoryConfigSchema.safeParse({
|
const directoryConfig = directoryConfigSchema.safeParse({
|
||||||
directoryType: config.get<string | undefined>('directoryType') || 'legacy',
|
|
||||||
directoryUrl: config.get<string | null>('directoryUrl') || undefined,
|
directoryUrl: config.get<string | null>('directoryUrl') || undefined,
|
||||||
directoryEnclaveId:
|
directoryMRENCLAVE:
|
||||||
config.get<string | null>('directoryEnclaveId') || undefined,
|
config.get<string | null>('directoryMRENCLAVE') || undefined,
|
||||||
directoryTrustAnchor:
|
|
||||||
config.get<string | null>('directoryTrustAnchor') || undefined,
|
|
||||||
directoryCDSIUrl:
|
|
||||||
config.get<string | null>('directoryCDSIUrl') || undefined,
|
|
||||||
directoryCDSIMRENCLAVE:
|
|
||||||
config.get<string | null>('directoryCDSIMRENCLAVE') || undefined,
|
|
||||||
});
|
});
|
||||||
if (!directoryConfig.success) {
|
if (!directoryConfig.success) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
{
|
{
|
||||||
"serverUrl": "https://chat.staging.signal.org",
|
"serverUrl": "https://chat.staging.signal.org",
|
||||||
"storageUrl": "https://storage-staging.signal.org",
|
"storageUrl": "https://storage-staging.signal.org",
|
||||||
"directoryType": "cdsi",
|
"directoryUrl": "https://cdsi.staging.signal.org",
|
||||||
"directoryUrl": null,
|
"directoryMRENCLAVE": "ef4787a56a154ac6d009138cac17155acd23cfe4329281252365dd7c252e7fbf",
|
||||||
"directoryEnclaveId": null,
|
|
||||||
"directoryTrustAnchor": null,
|
|
||||||
"directoryCDSIUrl": "https://cdsi.staging.signal.org",
|
|
||||||
"directoryCDSIMRENCLAVE": "ef4787a56a154ac6d009138cac17155acd23cfe4329281252365dd7c252e7fbf",
|
|
||||||
"cdn": {
|
"cdn": {
|
||||||
"0": "https://cdn-staging.signal.org",
|
"0": "https://cdn-staging.signal.org",
|
||||||
"2": "https://cdn2-staging.signal.org"
|
"2": "https://cdn2-staging.signal.org"
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
{
|
{
|
||||||
"serverUrl": "https://chat.signal.org",
|
"serverUrl": "https://chat.signal.org",
|
||||||
"storageUrl": "https://storage.signal.org",
|
"storageUrl": "https://storage.signal.org",
|
||||||
"directoryType": "mirrored-cdsi",
|
"directoryUrl": "https://cdsi.signal.org",
|
||||||
"directoryUrl": "https://api.directory.signal.org",
|
"directoryMRENCLAVE": "ef4787a56a154ac6d009138cac17155acd23cfe4329281252365dd7c252e7fbf",
|
||||||
"directoryEnclaveId": "74778bb0f93ae1f78c26e67152bab0bbeb693cd56d1bb9b4e9244157acc58081",
|
|
||||||
"directoryTrustAnchor": "-----BEGIN CERTIFICATE-----\nMIIFSzCCA7OgAwIBAgIJANEHdl0yo7CUMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV\nBAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwLU2FudGEgQ2xhcmExGjAYBgNV\nBAoMEUludGVsIENvcnBvcmF0aW9uMTAwLgYDVQQDDCdJbnRlbCBTR1ggQXR0ZXN0\nYXRpb24gUmVwb3J0IFNpZ25pbmcgQ0EwIBcNMTYxMTE0MTUzNzMxWhgPMjA0OTEy\nMzEyMzU5NTlaMH4xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwL\nU2FudGEgQ2xhcmExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0aW9uMTAwLgYDVQQD\nDCdJbnRlbCBTR1ggQXR0ZXN0YXRpb24gUmVwb3J0IFNpZ25pbmcgQ0EwggGiMA0G\nCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCfPGR+tXc8u1EtJzLA10Feu1Wg+p7e\nLmSRmeaCHbkQ1TF3Nwl3RmpqXkeGzNLd69QUnWovYyVSndEMyYc3sHecGgfinEeh\nrgBJSEdsSJ9FpaFdesjsxqzGRa20PYdnnfWcCTvFoulpbFR4VBuXnnVLVzkUvlXT\nL/TAnd8nIZk0zZkFJ7P5LtePvykkar7LcSQO85wtcQe0R1Raf/sQ6wYKaKmFgCGe\nNpEJUmg4ktal4qgIAxk+QHUxQE42sxViN5mqglB0QJdUot/o9a/V/mMeH8KvOAiQ\nbyinkNndn+Bgk5sSV5DFgF0DffVqmVMblt5p3jPtImzBIH0QQrXJq39AT8cRwP5H\nafuVeLHcDsRp6hol4P+ZFIhu8mmbI1u0hH3W/0C2BuYXB5PC+5izFFh/nP0lc2Lf\n6rELO9LZdnOhpL1ExFOq9H/B8tPQ84T3Sgb4nAifDabNt/zu6MmCGo5U8lwEFtGM\nRoOaX4AS+909x00lYnmtwsDVWv9vBiJCXRsCAwEAAaOByTCBxjBgBgNVHR8EWTBX\nMFWgU6BRhk9odHRwOi8vdHJ1c3RlZHNlcnZpY2VzLmludGVsLmNvbS9jb250ZW50\nL0NSTC9TR1gvQXR0ZXN0YXRpb25SZXBvcnRTaWduaW5nQ0EuY3JsMB0GA1UdDgQW\nBBR4Q3t2pn680K9+QjfrNXw7hwFRPDAfBgNVHSMEGDAWgBR4Q3t2pn680K9+Qjfr\nNXw7hwFRPDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkq\nhkiG9w0BAQsFAAOCAYEAeF8tYMXICvQqeXYQITkV2oLJsp6J4JAqJabHWxYJHGir\nIEqucRiJSSx+HjIJEUVaj8E0QjEud6Y5lNmXlcjqRXaCPOqK0eGRz6hi+ripMtPZ\nsFNaBwLQVV905SDjAzDzNIDnrcnXyB4gcDFCvwDFKKgLRjOB/WAqgscDUoGq5ZVi\nzLUzTqiQPmULAQaB9c6Oti6snEFJiCQ67JLyW/E83/frzCmO5Ru6WjU4tmsmy8Ra\nUd4APK0wZTGtfPXU7w+IBdG5Ez0kE1qzxGQaL4gINJ1zMyleDnbuS8UicjJijvqA\n152Sq049ESDz+1rRGc2NVEqh1KaGXmtXvqxXcTB+Ljy5Bw2ke0v8iGngFBPqCTVB\n3op5KBG3RjbF6RRSzwzuWfL7QErNC8WEy5yDVARzTA5+xmBc388v9Dm21HGfcC8O\nDD+gT9sSpssq0ascmvH49MOgjt1yoysLtdCtJW/9FZpoOypaHx0R+mJTLwPXVMrv\nDaVzWh5aiEx+idkSGMnX\n-----END CERTIFICATE-----\n",
|
|
||||||
"directoryCDSIUrl": "https://cdsi.signal.org",
|
|
||||||
"directoryCDSIMRENCLAVE": "ef4787a56a154ac6d009138cac17155acd23cfe4329281252365dd7c252e7fbf",
|
|
||||||
"cdn": {
|
"cdn": {
|
||||||
"0": "https://cdn.signal.org",
|
"0": "https://cdn.signal.org",
|
||||||
"2": "https://cdn2.signal.org"
|
"2": "https://cdn2.signal.org"
|
||||||
|
|
|
@ -136,7 +136,6 @@
|
||||||
"mp4box": "0.5.2",
|
"mp4box": "0.5.2",
|
||||||
"mustache": "2.3.0",
|
"mustache": "2.3.0",
|
||||||
"node-fetch": "2.6.7",
|
"node-fetch": "2.6.7",
|
||||||
"node-forge": "1.3.0",
|
|
||||||
"normalize-path": "3.0.0",
|
"normalize-path": "3.0.0",
|
||||||
"p-map": "2.1.0",
|
"p-map": "2.1.0",
|
||||||
"p-props": "4.0.0",
|
"p-props": "4.0.0",
|
||||||
|
@ -239,7 +238,6 @@
|
||||||
"@types/mustache": "4.1.2",
|
"@types/mustache": "4.1.2",
|
||||||
"@types/node": "16.11.29",
|
"@types/node": "16.11.29",
|
||||||
"@types/node-fetch": "2.5.7",
|
"@types/node-fetch": "2.5.7",
|
||||||
"@types/node-forge": "0.9.5",
|
|
||||||
"@types/normalize-path": "3.0.0",
|
"@types/normalize-path": "3.0.0",
|
||||||
"@types/pify": "3.0.2",
|
"@types/pify": "3.0.2",
|
||||||
"@types/quill": "1.3.10",
|
"@types/quill": "1.3.10",
|
||||||
|
|
69
ts/Crypto.ts
69
ts/Crypto.ts
|
@ -2,7 +2,6 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { Buffer } from 'buffer';
|
import { Buffer } from 'buffer';
|
||||||
import pProps from 'p-props';
|
|
||||||
import Long from 'long';
|
import Long from 'long';
|
||||||
import { HKDF } from '@signalapp/libsignal-client';
|
import { HKDF } from '@signalapp/libsignal-client';
|
||||||
|
|
||||||
|
@ -362,74 +361,6 @@ export function getBytes(
|
||||||
return data.subarray(start, start + n);
|
return data.subarray(start, start + n);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getMacAndData(ciphertext: Uint8Array) {
|
|
||||||
const dataLength = ciphertext.byteLength - MAC_LENGTH;
|
|
||||||
const data = getBytes(ciphertext, 0, dataLength);
|
|
||||||
const mac = getBytes(ciphertext, dataLength, MAC_LENGTH);
|
|
||||||
|
|
||||||
return { data, mac };
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function encryptCdsDiscoveryRequest(
|
|
||||||
attestations: {
|
|
||||||
[key: string]: { clientKey: Uint8Array; requestId: Uint8Array };
|
|
||||||
},
|
|
||||||
phoneNumbers: ReadonlyArray<string>
|
|
||||||
): Promise<Record<string, unknown>> {
|
|
||||||
const nonce = getRandomBytes(32);
|
|
||||||
const numbersArray = Buffer.concat(
|
|
||||||
phoneNumbers.map(number => {
|
|
||||||
// Long.fromString handles numbers with or without a leading '+'
|
|
||||||
return new Uint8Array(Long.fromString(number).toBytesBE());
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// We've written to the array, so offset === byteLength; we need to reset it. Then we'll
|
|
||||||
// have access to everything in the array when we generate an Uint8Array from it.
|
|
||||||
const queryDataPlaintext = Bytes.concatenate([nonce, numbersArray]);
|
|
||||||
|
|
||||||
const queryDataKey = getRandomBytes(32);
|
|
||||||
const commitment = sha256(queryDataPlaintext);
|
|
||||||
const iv = getRandomBytes(12);
|
|
||||||
const queryDataCiphertext = encryptAesGcm(
|
|
||||||
queryDataKey,
|
|
||||||
iv,
|
|
||||||
queryDataPlaintext
|
|
||||||
);
|
|
||||||
const { data: queryDataCiphertextData, mac: queryDataCiphertextMac } =
|
|
||||||
_getMacAndData(queryDataCiphertext);
|
|
||||||
|
|
||||||
const envelopes = await pProps(
|
|
||||||
attestations,
|
|
||||||
async ({ clientKey, requestId }) => {
|
|
||||||
const envelopeIv = getRandomBytes(12);
|
|
||||||
const ciphertext = encryptAesGcm(
|
|
||||||
clientKey,
|
|
||||||
envelopeIv,
|
|
||||||
queryDataKey,
|
|
||||||
requestId
|
|
||||||
);
|
|
||||||
const { data, mac } = _getMacAndData(ciphertext);
|
|
||||||
|
|
||||||
return {
|
|
||||||
requestId: Bytes.toBase64(requestId),
|
|
||||||
data: Bytes.toBase64(data),
|
|
||||||
iv: Bytes.toBase64(envelopeIv),
|
|
||||||
mac: Bytes.toBase64(mac),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
addressCount: phoneNumbers.length,
|
|
||||||
commitment: Bytes.toBase64(commitment),
|
|
||||||
data: Bytes.toBase64(queryDataCiphertextData),
|
|
||||||
iv: Bytes.toBase64(iv),
|
|
||||||
mac: Bytes.toBase64(queryDataCiphertextMac),
|
|
||||||
envelopes,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bytesToUuid(bytes: Uint8Array): undefined | UUIDStringType {
|
export function bytesToUuid(bytes: Uint8Array): undefined | UUIDStringType {
|
||||||
if (bytes.byteLength !== UUID_BYTE_SIZE) {
|
if (bytes.byteLength !== UUID_BYTE_SIZE) {
|
||||||
log.warn(
|
log.warn(
|
||||||
|
|
|
@ -15,10 +15,7 @@ import { getCountryCode } from './types/PhoneNumber';
|
||||||
export type ConfigKeyType =
|
export type ConfigKeyType =
|
||||||
| 'desktop.announcementGroup'
|
| 'desktop.announcementGroup'
|
||||||
| 'desktop.calling.audioLevelForSpeaking'
|
| 'desktop.calling.audioLevelForSpeaking'
|
||||||
| 'desktop.cdsi'
|
|
||||||
| 'desktop.cdsi.beta'
|
|
||||||
| 'desktop.cdsi.returnAcisWithoutUaks'
|
| 'desktop.cdsi.returnAcisWithoutUaks'
|
||||||
| 'desktop.cdsi.mirroring'
|
|
||||||
| 'desktop.clientExpiration'
|
| 'desktop.clientExpiration'
|
||||||
| 'desktop.groupCallOutboundRing'
|
| 'desktop.groupCallOutboundRing'
|
||||||
| 'desktop.internalUser'
|
| 'desktop.internalUser'
|
||||||
|
|
|
@ -40,14 +40,7 @@ import * as linkPreviewFetch from '../linkPreviews/linkPreviewFetch';
|
||||||
import { isBadgeImageFileUrlValid } from '../badges/isBadgeImageFileUrlValid';
|
import { isBadgeImageFileUrlValid } from '../badges/isBadgeImageFileUrlValid';
|
||||||
|
|
||||||
import { SocketManager } from './SocketManager';
|
import { SocketManager } from './SocketManager';
|
||||||
import type {
|
import type { CDSAuthType, CDSResponseType } from './cds/Types.d';
|
||||||
CDSAuthType,
|
|
||||||
CDSRequestOptionsType,
|
|
||||||
CDSResponseType,
|
|
||||||
} from './cds/Types.d';
|
|
||||||
import type { CDSBase } from './cds/CDSBase';
|
|
||||||
import { LegacyCDS } from './cds/LegacyCDS';
|
|
||||||
import type { LegacyCDSPutAttestationResponseType } from './cds/LegacyCDS';
|
|
||||||
import { CDSI } from './cds/CDSI';
|
import { CDSI } from './cds/CDSI';
|
||||||
import type WebSocketResource from './WebsocketResources';
|
import type WebSocketResource from './WebsocketResources';
|
||||||
import { SignalService as Proto } from '../protobuf';
|
import { SignalService as Proto } from '../protobuf';
|
||||||
|
@ -63,12 +56,6 @@ import type {
|
||||||
import { handleStatusCode, translateError } from './Utils';
|
import { handleStatusCode, translateError } from './Utils';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
import { maybeParseUrl } from '../util/url';
|
import { maybeParseUrl } from '../util/url';
|
||||||
import {
|
|
||||||
ToastInternalError,
|
|
||||||
ToastInternalErrorKind,
|
|
||||||
} from '../components/ToastInternalError';
|
|
||||||
import { showToast } from '../util/showToast';
|
|
||||||
import { isProduction } from '../util/version';
|
|
||||||
|
|
||||||
// Note: this will break some code that expects to be able to use err.response when a
|
// Note: this will break some code that expects to be able to use err.response when a
|
||||||
// web request fails, because it will force it to text. But it is very useful for
|
// web request fails, because it will force it to text. But it is very useful for
|
||||||
|
@ -738,8 +725,6 @@ export type CdsLookupOptionsType = Readonly<{
|
||||||
acis?: ReadonlyArray<UUIDStringType>;
|
acis?: ReadonlyArray<UUIDStringType>;
|
||||||
accessKeys?: ReadonlyArray<string>;
|
accessKeys?: ReadonlyArray<string>;
|
||||||
returnAcisWithoutUaks?: boolean;
|
returnAcisWithoutUaks?: boolean;
|
||||||
isLegacy: boolean;
|
|
||||||
isMirroring: boolean;
|
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type GetProfileCommonOptionsType = Readonly<
|
type GetProfileCommonOptionsType = Readonly<
|
||||||
|
@ -1126,117 +1111,25 @@ export function initialize({
|
||||||
socketManager.authenticate({ username, password });
|
socketManager.authenticate({ username, password });
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { directoryUrl, directoryMRENCLAVE } = directoryConfig;
|
||||||
directoryType,
|
|
||||||
directoryUrl,
|
|
||||||
directoryEnclaveId,
|
|
||||||
directoryTrustAnchor,
|
|
||||||
} = directoryConfig;
|
|
||||||
|
|
||||||
let legacyCDS: LegacyCDS | undefined;
|
const cds = new CDSI({
|
||||||
let cds: CDSBase;
|
logger: log,
|
||||||
if (directoryType === 'legacy' || directoryType === 'mirrored-cdsi') {
|
proxyUrl,
|
||||||
legacyCDS = new LegacyCDS({
|
|
||||||
logger: log,
|
|
||||||
directoryEnclaveId,
|
|
||||||
directoryTrustAnchor,
|
|
||||||
proxyUrl,
|
|
||||||
|
|
||||||
async putAttestation(auth, publicKey) {
|
url: directoryUrl,
|
||||||
const data = JSON.stringify({
|
mrenclave: directoryMRENCLAVE,
|
||||||
clientPublic: Bytes.toBase64(publicKey),
|
certificateAuthority,
|
||||||
iasVersion: 4,
|
version,
|
||||||
});
|
|
||||||
const result = (await _outerAjax(null, {
|
|
||||||
certificateAuthority,
|
|
||||||
type: 'PUT',
|
|
||||||
contentType: 'application/json; charset=utf-8',
|
|
||||||
host: directoryUrl,
|
|
||||||
path: `${URL_CALLS.attestation}/${directoryEnclaveId}`,
|
|
||||||
user: auth.username,
|
|
||||||
password: auth.password,
|
|
||||||
proxyUrl,
|
|
||||||
responseType: 'jsonwithdetails',
|
|
||||||
data,
|
|
||||||
timeout: 30000,
|
|
||||||
version,
|
|
||||||
})) as JSONWithDetailsType<LegacyCDSPutAttestationResponseType>;
|
|
||||||
|
|
||||||
const { response, data: responseBody } = result;
|
async getAuth() {
|
||||||
|
return (await _ajax({
|
||||||
const cookie = response.headers.get('set-cookie') ?? undefined;
|
call: 'directoryAuthV2',
|
||||||
|
httpType: 'GET',
|
||||||
return { cookie, responseBody };
|
responseType: 'json',
|
||||||
},
|
})) as CDSAuthType;
|
||||||
|
},
|
||||||
async fetchDiscoveryData(auth, data, cookie) {
|
});
|
||||||
const response = (await _outerAjax(null, {
|
|
||||||
certificateAuthority,
|
|
||||||
type: 'PUT',
|
|
||||||
headers: cookie
|
|
||||||
? {
|
|
||||||
cookie,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
contentType: 'application/json; charset=utf-8',
|
|
||||||
host: directoryUrl,
|
|
||||||
path: `${URL_CALLS.discovery}/${directoryEnclaveId}`,
|
|
||||||
user: auth.username,
|
|
||||||
password: auth.password,
|
|
||||||
proxyUrl,
|
|
||||||
responseType: 'json',
|
|
||||||
timeout: 30000,
|
|
||||||
data: JSON.stringify(data),
|
|
||||||
version,
|
|
||||||
})) as {
|
|
||||||
requestId: string;
|
|
||||||
iv: string;
|
|
||||||
data: string;
|
|
||||||
mac: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
requestId: Bytes.fromBase64(response.requestId),
|
|
||||||
iv: Bytes.fromBase64(response.iv),
|
|
||||||
data: Bytes.fromBase64(response.data),
|
|
||||||
mac: Bytes.fromBase64(response.mac),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
async getAuth() {
|
|
||||||
return (await _ajax({
|
|
||||||
call: 'directoryAuth',
|
|
||||||
httpType: 'GET',
|
|
||||||
responseType: 'json',
|
|
||||||
})) as CDSAuthType;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (directoryType === 'legacy') {
|
|
||||||
cds = legacyCDS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (directoryType === 'cdsi' || directoryType === 'mirrored-cdsi') {
|
|
||||||
const { directoryCDSIUrl, directoryCDSIMRENCLAVE } = directoryConfig;
|
|
||||||
|
|
||||||
cds = new CDSI({
|
|
||||||
logger: log,
|
|
||||||
proxyUrl,
|
|
||||||
|
|
||||||
url: directoryCDSIUrl,
|
|
||||||
mrenclave: directoryCDSIMRENCLAVE,
|
|
||||||
certificateAuthority,
|
|
||||||
version,
|
|
||||||
|
|
||||||
async getAuth() {
|
|
||||||
return (await _ajax({
|
|
||||||
call: 'directoryAuthV2',
|
|
||||||
httpType: 'GET',
|
|
||||||
responseType: 'json',
|
|
||||||
})) as CDSAuthType;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let fetchForLinkPreviews: linkPreviewFetch.FetchFn;
|
let fetchForLinkPreviews: linkPreviewFetch.FetchFn;
|
||||||
if (proxyUrl) {
|
if (proxyUrl) {
|
||||||
|
@ -2936,74 +2829,18 @@ export function initialize({
|
||||||
return socketManager.getProvisioningResource(handler);
|
return socketManager.getProvisioningResource(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function mirroredCdsLookup(
|
|
||||||
requestOptions: CDSRequestOptionsType,
|
|
||||||
expectedMapPromise: Promise<CDSResponseType>
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
|
||||||
log.info('cdsLookup: sending mirrored request');
|
|
||||||
const actualMap = await cds.request(requestOptions);
|
|
||||||
|
|
||||||
const expectedMap = await expectedMapPromise;
|
|
||||||
let matched = 0;
|
|
||||||
let warnings = 0;
|
|
||||||
for (const [e164, { aci }] of actualMap) {
|
|
||||||
if (!aci) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const expectedACI = expectedMap.get(e164)?.aci;
|
|
||||||
if (expectedACI === aci) {
|
|
||||||
matched += 1;
|
|
||||||
} else {
|
|
||||||
warnings += 1;
|
|
||||||
log.warn(
|
|
||||||
`cdsLookup: mirrored request has aci=${aci} for ${e164}, while ` +
|
|
||||||
`expected aci=${expectedACI}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (warnings !== 0 && !isProduction(window.getVersion())) {
|
|
||||||
log.info('cdsLookup: showing error toast');
|
|
||||||
showToast(ToastInternalError, {
|
|
||||||
kind: ToastInternalErrorKind.CDSMirroringError,
|
|
||||||
onShowDebugLog: () => window.showDebugLog(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(`cdsLookup: mirrored request success, matched=${matched}`);
|
|
||||||
} catch (error) {
|
|
||||||
log.error('cdsLookup: mirrored request error', toLogFormat(error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function cdsLookup({
|
async function cdsLookup({
|
||||||
e164s,
|
e164s,
|
||||||
acis = [],
|
acis = [],
|
||||||
accessKeys = [],
|
accessKeys = [],
|
||||||
returnAcisWithoutUaks,
|
returnAcisWithoutUaks,
|
||||||
isLegacy,
|
|
||||||
isMirroring,
|
|
||||||
}: CdsLookupOptionsType): Promise<CDSResponseType> {
|
}: CdsLookupOptionsType): Promise<CDSResponseType> {
|
||||||
const requestOptions = {
|
return cds.request({
|
||||||
e164s,
|
e164s,
|
||||||
acis,
|
acis,
|
||||||
accessKeys,
|
accessKeys,
|
||||||
returnAcisWithoutUaks,
|
returnAcisWithoutUaks,
|
||||||
};
|
});
|
||||||
if (!isLegacy || !legacyCDS) {
|
|
||||||
return cds.request(requestOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
const legacyRequest = legacyCDS.request(requestOptions);
|
|
||||||
|
|
||||||
if (legacyCDS !== cds && isMirroring) {
|
|
||||||
// Intentionally not awaiting
|
|
||||||
mirroredCdsLookup(requestOptions, legacyRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
return legacyRequest;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,459 +0,0 @@
|
||||||
// Copyright 2020-2022 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
/* eslint-disable no-bitwise */
|
|
||||||
|
|
||||||
import pProps from 'p-props';
|
|
||||||
import { compact } from 'lodash';
|
|
||||||
import Long from 'long';
|
|
||||||
import { createVerify } from 'crypto';
|
|
||||||
import { pki } from 'node-forge';
|
|
||||||
|
|
||||||
import {
|
|
||||||
constantTimeEqual,
|
|
||||||
decryptAesGcm,
|
|
||||||
deriveSecrets,
|
|
||||||
encryptCdsDiscoveryRequest,
|
|
||||||
splitUuids,
|
|
||||||
} from '../../Crypto';
|
|
||||||
import { calculateAgreement, generateKeyPair } from '../../Curve';
|
|
||||||
import * as Bytes from '../../Bytes';
|
|
||||||
import { UUID } from '../../types/UUID';
|
|
||||||
import type { CDSBaseOptionsType } from './CDSBase';
|
|
||||||
import { CDSBase } from './CDSBase';
|
|
||||||
import type {
|
|
||||||
CDSRequestOptionsType,
|
|
||||||
CDSResponseType,
|
|
||||||
CDSAuthType,
|
|
||||||
CDSResponseEntryType,
|
|
||||||
} from './Types.d';
|
|
||||||
|
|
||||||
export type LegacyCDSPutAttestationResponseType = Readonly<{
|
|
||||||
attestations: Record<
|
|
||||||
string,
|
|
||||||
{
|
|
||||||
ciphertext: string;
|
|
||||||
iv: string;
|
|
||||||
quote: string;
|
|
||||||
serverEphemeralPublic: string;
|
|
||||||
serverStaticPublic: string;
|
|
||||||
signature: string;
|
|
||||||
signatureBody: string;
|
|
||||||
tag: string;
|
|
||||||
certificates: string;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type LegacyCDSPutAttestationResultType = Readonly<{
|
|
||||||
cookie?: string;
|
|
||||||
responseBody: LegacyCDSPutAttestationResponseType;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type LegacyCDSDiscoveryResponseType = Readonly<{
|
|
||||||
requestId: Uint8Array;
|
|
||||||
iv: Uint8Array;
|
|
||||||
data: Uint8Array;
|
|
||||||
mac: Uint8Array;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type LegacyCDSOptionsType = Readonly<{
|
|
||||||
directoryEnclaveId: string;
|
|
||||||
directoryTrustAnchor: string;
|
|
||||||
|
|
||||||
putAttestation: (
|
|
||||||
auth: CDSAuthType,
|
|
||||||
publicKey: Uint8Array
|
|
||||||
) => Promise<LegacyCDSPutAttestationResultType>;
|
|
||||||
fetchDiscoveryData: (
|
|
||||||
auth: CDSAuthType,
|
|
||||||
data: Record<string, unknown>,
|
|
||||||
cookie?: string
|
|
||||||
) => Promise<LegacyCDSDiscoveryResponseType>;
|
|
||||||
}> &
|
|
||||||
CDSBaseOptionsType;
|
|
||||||
|
|
||||||
type AttestationMapType = Readonly<{
|
|
||||||
cookie?: string;
|
|
||||||
attestations: Record<
|
|
||||||
string,
|
|
||||||
Readonly<{
|
|
||||||
clientKey: Uint8Array;
|
|
||||||
serverKey: Uint8Array;
|
|
||||||
requestId: Uint8Array;
|
|
||||||
}>
|
|
||||||
>;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
type SgxConstantsType = {
|
|
||||||
SGX_FLAGS_INITTED: Long;
|
|
||||||
SGX_FLAGS_DEBUG: Long;
|
|
||||||
SGX_FLAGS_MODE64BIT: Long;
|
|
||||||
SGX_FLAGS_PROVISION_KEY: Long;
|
|
||||||
SGX_FLAGS_EINITTOKEN_KEY: Long;
|
|
||||||
SGX_FLAGS_RESERVED: Long;
|
|
||||||
SGX_XFRM_LEGACY: Long;
|
|
||||||
SGX_XFRM_AVX: Long;
|
|
||||||
SGX_XFRM_RESERVED: Long;
|
|
||||||
};
|
|
||||||
|
|
||||||
let sgxConstantCache: SgxConstantsType | null = null;
|
|
||||||
|
|
||||||
function makeLong(value: string): Long {
|
|
||||||
return Long.fromString(value);
|
|
||||||
}
|
|
||||||
function getSgxConstants() {
|
|
||||||
if (sgxConstantCache) {
|
|
||||||
return sgxConstantCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
sgxConstantCache = {
|
|
||||||
SGX_FLAGS_INITTED: makeLong('x0000000000000001L'),
|
|
||||||
SGX_FLAGS_DEBUG: makeLong('x0000000000000002L'),
|
|
||||||
SGX_FLAGS_MODE64BIT: makeLong('x0000000000000004L'),
|
|
||||||
SGX_FLAGS_PROVISION_KEY: makeLong('x0000000000000004L'),
|
|
||||||
SGX_FLAGS_EINITTOKEN_KEY: makeLong('x0000000000000004L'),
|
|
||||||
SGX_FLAGS_RESERVED: makeLong('xFFFFFFFFFFFFFFC8L'),
|
|
||||||
SGX_XFRM_LEGACY: makeLong('x0000000000000003L'),
|
|
||||||
SGX_XFRM_AVX: makeLong('x0000000000000006L'),
|
|
||||||
SGX_XFRM_RESERVED: makeLong('xFFFFFFFFFFFFFFF8L'),
|
|
||||||
};
|
|
||||||
|
|
||||||
return sgxConstantCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LegacyCDS extends CDSBase<LegacyCDSOptionsType> {
|
|
||||||
public override async request({
|
|
||||||
e164s,
|
|
||||||
}: CDSRequestOptionsType): Promise<CDSResponseType> {
|
|
||||||
const directoryAuth = await this.getAuth();
|
|
||||||
const attestationResult = await this.putAttestation(directoryAuth);
|
|
||||||
|
|
||||||
// Encrypt data for discovery
|
|
||||||
const data = await encryptCdsDiscoveryRequest(
|
|
||||||
attestationResult.attestations,
|
|
||||||
e164s
|
|
||||||
);
|
|
||||||
const { cookie } = attestationResult;
|
|
||||||
|
|
||||||
// Send discovery request
|
|
||||||
const discoveryResponse = await this.options.fetchDiscoveryData(
|
|
||||||
directoryAuth,
|
|
||||||
data,
|
|
||||||
cookie
|
|
||||||
);
|
|
||||||
|
|
||||||
const returnedAttestation = Object.values(
|
|
||||||
attestationResult.attestations
|
|
||||||
).find(at => constantTimeEqual(at.requestId, discoveryResponse.requestId));
|
|
||||||
if (!returnedAttestation) {
|
|
||||||
throw new Error('No known attestations returned from CDS');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt discovery response
|
|
||||||
const decryptedDiscoveryData = decryptAesGcm(
|
|
||||||
returnedAttestation.serverKey,
|
|
||||||
discoveryResponse.iv,
|
|
||||||
Bytes.concatenate([discoveryResponse.data, discoveryResponse.mac])
|
|
||||||
);
|
|
||||||
|
|
||||||
// Process and return result
|
|
||||||
const uuids = splitUuids(decryptedDiscoveryData);
|
|
||||||
|
|
||||||
if (uuids.length !== e164s.length) {
|
|
||||||
throw new Error(
|
|
||||||
'Returned set of UUIDs did not match returned set of e164s!'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = new Map<string, CDSResponseEntryType>();
|
|
||||||
|
|
||||||
for (const [i, e164] of e164s.entries()) {
|
|
||||||
const uuid = uuids[i];
|
|
||||||
result.set(e164, {
|
|
||||||
aci: uuid ? UUID.cast(uuid) : undefined,
|
|
||||||
pni: undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Private
|
|
||||||
//
|
|
||||||
|
|
||||||
private async putAttestation(auth: CDSAuthType): Promise<AttestationMapType> {
|
|
||||||
const { privKey, pubKey } = generateKeyPair();
|
|
||||||
// Remove first "key type" byte from public key
|
|
||||||
const slicedPubKey = pubKey.slice(1);
|
|
||||||
// Do request
|
|
||||||
const { cookie, responseBody } = await this.options.putAttestation(
|
|
||||||
auth,
|
|
||||||
slicedPubKey
|
|
||||||
);
|
|
||||||
|
|
||||||
const attestationsLength = Object.keys(responseBody.attestations).length;
|
|
||||||
if (attestationsLength > 3) {
|
|
||||||
throw new Error(
|
|
||||||
'Got more than three attestations from the Contact Discovery Service'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (attestationsLength < 1) {
|
|
||||||
throw new Error('Got no attestations from the Contact Discovery Service');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode response
|
|
||||||
return {
|
|
||||||
cookie,
|
|
||||||
attestations: await pProps(
|
|
||||||
responseBody.attestations,
|
|
||||||
async attestation => {
|
|
||||||
const decoded = {
|
|
||||||
...attestation,
|
|
||||||
ciphertext: Bytes.fromBase64(attestation.ciphertext),
|
|
||||||
iv: Bytes.fromBase64(attestation.iv),
|
|
||||||
quote: Bytes.fromBase64(attestation.quote),
|
|
||||||
serverEphemeralPublic: Bytes.fromBase64(
|
|
||||||
attestation.serverEphemeralPublic
|
|
||||||
),
|
|
||||||
serverStaticPublic: Bytes.fromBase64(
|
|
||||||
attestation.serverStaticPublic
|
|
||||||
),
|
|
||||||
signature: Bytes.fromBase64(attestation.signature),
|
|
||||||
tag: Bytes.fromBase64(attestation.tag),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Validate response
|
|
||||||
this.validateAttestationQuote(decoded);
|
|
||||||
validateAttestationSignatureBody(
|
|
||||||
JSON.parse(decoded.signatureBody),
|
|
||||||
attestation.quote
|
|
||||||
);
|
|
||||||
await this.validateAttestationSignature(
|
|
||||||
decoded.signature,
|
|
||||||
decoded.signatureBody,
|
|
||||||
decoded.certificates
|
|
||||||
);
|
|
||||||
|
|
||||||
// Derive key
|
|
||||||
const ephemeralToEphemeral = calculateAgreement(
|
|
||||||
decoded.serverEphemeralPublic,
|
|
||||||
privKey
|
|
||||||
);
|
|
||||||
const ephemeralToStatic = calculateAgreement(
|
|
||||||
decoded.serverStaticPublic,
|
|
||||||
privKey
|
|
||||||
);
|
|
||||||
const masterSecret = Bytes.concatenate([
|
|
||||||
ephemeralToEphemeral,
|
|
||||||
ephemeralToStatic,
|
|
||||||
]);
|
|
||||||
const publicKeys = Bytes.concatenate([
|
|
||||||
slicedPubKey,
|
|
||||||
decoded.serverEphemeralPublic,
|
|
||||||
decoded.serverStaticPublic,
|
|
||||||
]);
|
|
||||||
const [clientKey, serverKey] = deriveSecrets(
|
|
||||||
masterSecret,
|
|
||||||
publicKeys,
|
|
||||||
new Uint8Array(0)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Decrypt ciphertext into requestId
|
|
||||||
const requestId = decryptAesGcm(
|
|
||||||
serverKey,
|
|
||||||
decoded.iv,
|
|
||||||
Bytes.concatenate([decoded.ciphertext, decoded.tag])
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
clientKey,
|
|
||||||
serverKey,
|
|
||||||
requestId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async validateAttestationSignature(
|
|
||||||
signature: Uint8Array,
|
|
||||||
signatureBody: string,
|
|
||||||
certificates: string
|
|
||||||
) {
|
|
||||||
const CERT_PREFIX = '-----BEGIN CERTIFICATE-----';
|
|
||||||
const pem = compact(
|
|
||||||
certificates.split(CERT_PREFIX).map(match => {
|
|
||||||
if (!match) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${CERT_PREFIX}${match}`;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
if (pem.length < 2) {
|
|
||||||
throw new Error(
|
|
||||||
`validateAttestationSignature: Expect two or more entries; got ${pem.length}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const verify = createVerify('RSA-SHA256');
|
|
||||||
verify.update(Buffer.from(Bytes.fromString(signatureBody)));
|
|
||||||
const isValid = verify.verify(pem[0], Buffer.from(signature));
|
|
||||||
if (!isValid) {
|
|
||||||
throw new Error('Validation of signature across signatureBody failed!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const caStore = pki.createCaStore([this.options.directoryTrustAnchor]);
|
|
||||||
const chain = compact(pem.map(cert => pki.certificateFromPem(cert)));
|
|
||||||
const isChainValid = pki.verifyCertificateChain(caStore, chain);
|
|
||||||
if (!isChainValid) {
|
|
||||||
throw new Error('Validation of certificate chain failed!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const leafCert = chain[0];
|
|
||||||
const fieldCN = leafCert.subject.getField('CN');
|
|
||||||
if (!fieldCN || fieldCN.value !== 'Intel SGX Attestation Report Signing') {
|
|
||||||
throw new Error('Leaf cert CN field had unexpected value');
|
|
||||||
}
|
|
||||||
const fieldO = leafCert.subject.getField('O');
|
|
||||||
if (!fieldO || fieldO.value !== 'Intel Corporation') {
|
|
||||||
throw new Error('Leaf cert O field had unexpected value');
|
|
||||||
}
|
|
||||||
const fieldL = leafCert.subject.getField('L');
|
|
||||||
if (!fieldL || fieldL.value !== 'Santa Clara') {
|
|
||||||
throw new Error('Leaf cert L field had unexpected value');
|
|
||||||
}
|
|
||||||
const fieldST = leafCert.subject.getField('ST');
|
|
||||||
if (!fieldST || fieldST.value !== 'CA') {
|
|
||||||
throw new Error('Leaf cert ST field had unexpected value');
|
|
||||||
}
|
|
||||||
const fieldC = leafCert.subject.getField('C');
|
|
||||||
if (!fieldC || fieldC.value !== 'US') {
|
|
||||||
throw new Error('Leaf cert C field had unexpected value');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private validateAttestationQuote({
|
|
||||||
serverStaticPublic,
|
|
||||||
quote: quoteBytes,
|
|
||||||
}: {
|
|
||||||
serverStaticPublic: Uint8Array;
|
|
||||||
quote: Uint8Array;
|
|
||||||
}): void {
|
|
||||||
const SGX_CONSTANTS = getSgxConstants();
|
|
||||||
const quote = Buffer.from(quoteBytes);
|
|
||||||
|
|
||||||
const quoteVersion = quote.readInt16LE(0) & 0xffff;
|
|
||||||
if (quoteVersion < 0 || quoteVersion > 2) {
|
|
||||||
throw new Error(`Unknown version ${quoteVersion}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const miscSelect = quote.slice(64, 64 + 4);
|
|
||||||
if (!miscSelect.every(byte => byte === 0)) {
|
|
||||||
throw new Error('Quote miscSelect invalid!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const reserved1 = quote.slice(68, 68 + 28);
|
|
||||||
if (!reserved1.every(byte => byte === 0)) {
|
|
||||||
throw new Error('Quote reserved1 invalid!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const flags = Long.fromBytesLE(
|
|
||||||
Array.from(quote.slice(96, 96 + 8).values())
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
flags.and(SGX_CONSTANTS.SGX_FLAGS_RESERVED).notEquals(0) ||
|
|
||||||
flags.and(SGX_CONSTANTS.SGX_FLAGS_INITTED).equals(0) ||
|
|
||||||
flags.and(SGX_CONSTANTS.SGX_FLAGS_MODE64BIT).equals(0)
|
|
||||||
) {
|
|
||||||
throw new Error(`Quote flags invalid ${flags.toString()}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const xfrm = Long.fromBytesLE(
|
|
||||||
Array.from(quote.slice(104, 104 + 8).values())
|
|
||||||
);
|
|
||||||
if (xfrm.and(SGX_CONSTANTS.SGX_XFRM_RESERVED).notEquals(0)) {
|
|
||||||
throw new Error(`Quote xfrm invalid ${xfrm}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mrenclave = quote.slice(112, 112 + 32);
|
|
||||||
const enclaveIdBytes = Bytes.fromHex(this.options.directoryEnclaveId);
|
|
||||||
if (mrenclave.compare(enclaveIdBytes) !== 0) {
|
|
||||||
throw new Error('Quote mrenclave invalid!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const reserved2 = quote.slice(144, 144 + 32);
|
|
||||||
if (!reserved2.every(byte => byte === 0)) {
|
|
||||||
throw new Error('Quote reserved2 invalid!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const reportData = quote.slice(368, 368 + 64);
|
|
||||||
const serverStaticPublicBytes = serverStaticPublic;
|
|
||||||
if (
|
|
||||||
!reportData.every((byte, index) => {
|
|
||||||
if (index >= 32) {
|
|
||||||
return byte === 0;
|
|
||||||
}
|
|
||||||
return byte === serverStaticPublicBytes[index];
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
throw new Error('Quote report_data invalid!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const reserved3 = quote.slice(208, 208 + 96);
|
|
||||||
if (!reserved3.every(byte => byte === 0)) {
|
|
||||||
throw new Error('Quote reserved3 invalid!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const reserved4 = quote.slice(308, 308 + 60);
|
|
||||||
if (!reserved4.every(byte => byte === 0)) {
|
|
||||||
throw new Error('Quote reserved4 invalid!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const signatureLength = quote.readInt32LE(432) >>> 0;
|
|
||||||
if (signatureLength !== quote.byteLength - 436) {
|
|
||||||
throw new Error(`Bad signatureLength ${signatureLength}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// const signature = quote.slice(436, 436 + signatureLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ALLOWED_ADVISORIES = new Set(['INTEL-SA-00334', 'INTEL-SA-00615']);
|
|
||||||
|
|
||||||
function validateAttestationSignatureBody(
|
|
||||||
signatureBody: {
|
|
||||||
timestamp: string;
|
|
||||||
version: number;
|
|
||||||
isvEnclaveQuoteBody: string;
|
|
||||||
isvEnclaveQuoteStatus: string;
|
|
||||||
advisoryIDs: ReadonlyArray<string>;
|
|
||||||
},
|
|
||||||
encodedQuote: string
|
|
||||||
) {
|
|
||||||
// Parse timestamp as UTC
|
|
||||||
const { timestamp } = signatureBody;
|
|
||||||
const utcTimestamp = timestamp.endsWith('Z') ? timestamp : `${timestamp}Z`;
|
|
||||||
const signatureTime = new Date(utcTimestamp).getTime();
|
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
if (signatureBody.version !== 4) {
|
|
||||||
throw new Error('Attestation signature invalid version!');
|
|
||||||
}
|
|
||||||
if (!encodedQuote.startsWith(signatureBody.isvEnclaveQuoteBody)) {
|
|
||||||
throw new Error('Attestion signature mismatches quote!');
|
|
||||||
}
|
|
||||||
if (signatureBody.isvEnclaveQuoteStatus !== 'SW_HARDENING_NEEDED') {
|
|
||||||
throw new Error('Attestation signature status not "SW_HARDENING_NEEDED"!');
|
|
||||||
}
|
|
||||||
if (!signatureBody.advisoryIDs.every(id => ALLOWED_ADVISORIES.has(id))) {
|
|
||||||
throw new Error('Attestation advisory ids are incorrect');
|
|
||||||
}
|
|
||||||
if (signatureBody.advisoryIDs.length > ALLOWED_ADVISORIES.size) {
|
|
||||||
throw new Error('Attestation advisory count is incorrect');
|
|
||||||
}
|
|
||||||
if (signatureTime < now - 24 * 60 * 60 * 1000) {
|
|
||||||
throw new Error('Attestation signature timestamp older than 24 hours!');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,53 +11,16 @@ export type ConfigRequiredStringType = z.infer<
|
||||||
typeof configRequiredStringSchema
|
typeof configRequiredStringSchema
|
||||||
>;
|
>;
|
||||||
|
|
||||||
const configOptionalUnknownSchema = configRequiredStringSchema.or(z.unknown());
|
|
||||||
|
|
||||||
const configOptionalStringSchema = configRequiredStringSchema.or(z.undefined());
|
const configOptionalStringSchema = configRequiredStringSchema.or(z.undefined());
|
||||||
export type configOptionalStringType = z.infer<
|
export type configOptionalStringType = z.infer<
|
||||||
typeof configOptionalStringSchema
|
typeof configOptionalStringSchema
|
||||||
>;
|
>;
|
||||||
|
|
||||||
const directoryLegacyConfigSchema = z.object({
|
export const directoryConfigSchema = z.object({
|
||||||
directoryType: z.literal('legacy'),
|
|
||||||
directoryEnclaveId: configRequiredStringSchema,
|
|
||||||
directoryTrustAnchor: configRequiredStringSchema,
|
|
||||||
directoryUrl: configRequiredStringSchema,
|
directoryUrl: configRequiredStringSchema,
|
||||||
|
directoryMRENCLAVE: configRequiredStringSchema,
|
||||||
});
|
});
|
||||||
|
|
||||||
const directoryCDSIConfigSchema = z.object({
|
|
||||||
directoryType: z.literal('cdsi'),
|
|
||||||
directoryCDSIUrl: configRequiredStringSchema,
|
|
||||||
directoryCDSIMRENCLAVE: configRequiredStringSchema,
|
|
||||||
});
|
|
||||||
|
|
||||||
const directoryMirroredCDSIConfigSchema = z.object({
|
|
||||||
directoryType: z.literal('mirrored-cdsi'),
|
|
||||||
|
|
||||||
directoryEnclaveId: configRequiredStringSchema,
|
|
||||||
directoryTrustAnchor: configRequiredStringSchema,
|
|
||||||
directoryUrl: configRequiredStringSchema,
|
|
||||||
|
|
||||||
directoryCDSIUrl: configRequiredStringSchema,
|
|
||||||
directoryCDSIMRENCLAVE: configRequiredStringSchema,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const directoryConfigSchema = z
|
|
||||||
.object({
|
|
||||||
// Unknown defaults
|
|
||||||
directoryEnclaveId: configOptionalUnknownSchema,
|
|
||||||
directoryTrustAnchor: configOptionalUnknownSchema,
|
|
||||||
directoryUrl: configOptionalUnknownSchema,
|
|
||||||
|
|
||||||
directoryCDSIUrl: configOptionalUnknownSchema,
|
|
||||||
directoryCDSIMRENCLAVE: configOptionalUnknownSchema,
|
|
||||||
})
|
|
||||||
.and(
|
|
||||||
directoryLegacyConfigSchema
|
|
||||||
.or(directoryMirroredCDSIConfigSchema)
|
|
||||||
.or(directoryCDSIConfigSchema)
|
|
||||||
);
|
|
||||||
|
|
||||||
export type DirectoryConfigType = z.infer<typeof directoryConfigSchema>;
|
export type DirectoryConfigType = z.infer<typeof directoryConfigSchema>;
|
||||||
|
|
||||||
export const rendererConfigSchema = z.object({
|
export const rendererConfigSchema = z.object({
|
||||||
|
|
|
@ -7,7 +7,6 @@ import type { UUIDStringType } from '../types/UUID';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
import { isEnabled } from '../RemoteConfig';
|
import { isEnabled } from '../RemoteConfig';
|
||||||
import { isDirectConversation, isMe } from './whatTypeOfConversation';
|
import { isDirectConversation, isMe } from './whatTypeOfConversation';
|
||||||
import { isBeta } from './version';
|
|
||||||
|
|
||||||
export async function getUuidsForE164s(
|
export async function getUuidsForE164s(
|
||||||
server: Pick<WebAPIType, 'cdsLookup'>,
|
server: Pick<WebAPIType, 'cdsLookup'>,
|
||||||
|
@ -40,11 +39,6 @@ export async function getUuidsForE164s(
|
||||||
}
|
}
|
||||||
|
|
||||||
const returnAcisWithoutUaks = isEnabled('desktop.cdsi.returnAcisWithoutUaks');
|
const returnAcisWithoutUaks = isEnabled('desktop.cdsi.returnAcisWithoutUaks');
|
||||||
const isCDSI =
|
|
||||||
isEnabled('desktop.cdsi') ||
|
|
||||||
(isBeta(window.getVersion()) && isEnabled('desktop.cdsi.beta'));
|
|
||||||
|
|
||||||
const isMirroring = isEnabled('desktop.cdsi.mirroring');
|
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
`getUuidsForE164s(${e164s}): acis=${acis.length} ` +
|
`getUuidsForE164s(${e164s}): acis=${acis.length} ` +
|
||||||
|
@ -55,7 +49,5 @@ export async function getUuidsForE164s(
|
||||||
acis,
|
acis,
|
||||||
accessKeys,
|
accessKeys,
|
||||||
returnAcisWithoutUaks,
|
returnAcisWithoutUaks,
|
||||||
isLegacy: !isCDSI,
|
|
||||||
isMirroring,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3498,13 +3498,6 @@
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
form-data "^3.0.0"
|
form-data "^3.0.0"
|
||||||
|
|
||||||
"@types/node-forge@0.9.5":
|
|
||||||
version "0.9.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-0.9.5.tgz#648231d79da197216290429020698d4e767365a0"
|
|
||||||
integrity sha512-rrN3xfA/oZIzwOnO3d2wRQz7UdeVkmMMPjWUCfpPTPuKFVb3D6G10LuiVHYYmvrivBBLMx4m0P/FICoDbNZUMA==
|
|
||||||
dependencies:
|
|
||||||
"@types/node" "*"
|
|
||||||
|
|
||||||
"@types/node@*", "@types/node@>=13.7.0":
|
"@types/node@*", "@types/node@>=13.7.0":
|
||||||
version "17.0.17"
|
version "17.0.17"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.17.tgz#a8ddf6e0c2341718d74ee3dc413a13a042c45a0c"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.17.tgz#a8ddf6e0c2341718d74ee3dc413a13a042c45a0c"
|
||||||
|
@ -12741,7 +12734,7 @@ node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url "^5.0.0"
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
node-forge@1.3.0, node-forge@^1.2.0:
|
node-forge@^1.2.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.0.tgz#37a874ea723855f37db091e6c186e5b67a01d4b2"
|
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.0.tgz#37a874ea723855f37db091e6c186e5b67a01d4b2"
|
||||||
integrity sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==
|
integrity sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==
|
||||||
|
|
Loading…
Add table
Reference in a new issue