mirror of
				https://github.com/dani-garcia/vaultwarden.git
				synced 2025-10-28 00:40:01 +02:00 
			
		
		
		
	Merge branch 'main' into fix-domain-description
This commit is contained in:
		
							
								
								
									
										5
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -48,7 +48,10 @@ jobs: | |||||||
|         ports: |         ports: | ||||||
|           - 5000:5000 |           - 5000:5000 | ||||||
|     env: |     env: | ||||||
|       DOCKER_BUILDKIT: 1 # Disabled for now, but we should look at this because it will speedup building! |       # Use BuildKit (https://docs.docker.com/build/buildkit/) for better | ||||||
|  |       # build performance and the ability to copy extended file attributes | ||||||
|  |       # (e.g., for executable capabilities) across build phases. | ||||||
|  |       DOCKER_BUILDKIT: 1 | ||||||
|       # DOCKER_REPO/secrets.DOCKERHUB_REPO needs to be 'index.docker.io/<user>/<repo>' |       # DOCKER_REPO/secrets.DOCKERHUB_REPO needs to be 'index.docker.io/<user>/<repo>' | ||||||
|       DOCKER_REPO: ${{ secrets.DOCKERHUB_REPO }} |       DOCKER_REPO: ${{ secrets.DOCKERHUB_REPO }} | ||||||
|       SOURCE_COMMIT: ${{ github.sha }} |       SOURCE_COMMIT: ${{ github.sha }} | ||||||
|   | |||||||
| @@ -3,5 +3,7 @@ ignored: | |||||||
|   - DL3008 |   - DL3008 | ||||||
|   # disable explicit version for apk install |   # disable explicit version for apk install | ||||||
|   - DL3018 |   - DL3018 | ||||||
|  |   # disable check for consecutive `RUN` instructions | ||||||
|  |   - DL3059 | ||||||
| trustedRegistries: | trustedRegistries: | ||||||
|   - docker.io |   - docker.io | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ resolver = "2" | |||||||
|  |  | ||||||
| repository = "https://github.com/dani-garcia/vaultwarden" | repository = "https://github.com/dani-garcia/vaultwarden" | ||||||
| readme = "README.md" | readme = "README.md" | ||||||
| license = "GPL-3.0-only" | license = "AGPL-3.0-only" | ||||||
| publish = false | publish = false | ||||||
| build = "build.rs" | build = "build.rs" | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										143
									
								
								LICENSE.txt
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								LICENSE.txt
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
|                     GNU GENERAL PUBLIC LICENSE |                     GNU AFFERO GENERAL PUBLIC LICENSE | ||||||
|                        Version 3, 29 June 2007 |                        Version 3, 19 November 2007 | ||||||
|  |  | ||||||
|  Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> |  Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> | ||||||
|  Everyone is permitted to copy and distribute verbatim copies |  Everyone is permitted to copy and distribute verbatim copies | ||||||
| @@ -7,17 +7,15 @@ | |||||||
|  |  | ||||||
|                             Preamble |                             Preamble | ||||||
|  |  | ||||||
|   The GNU General Public License is a free, copyleft license for |   The GNU Affero General Public License is a free, copyleft license for | ||||||
| software and other kinds of works. | 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 |   The licenses for most software and other practical works are designed | ||||||
| to take away your freedom to share and change the works.  By contrast, | to take away your freedom to share and change the works.  By contrast, | ||||||
| the GNU General Public License is intended to guarantee your freedom to | 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 | share and change all versions of a program--to make sure it remains free | ||||||
| software for all its users.  We, the Free Software Foundation, use the | software for all its users. | ||||||
| GNU General Public License for most of our software; it applies also to |  | ||||||
| any other work released this way by its authors.  You can apply it to |  | ||||||
| your programs, too. |  | ||||||
|  |  | ||||||
|   When we speak of free software, we are referring to freedom, not |   When we speak of free software, we are referring to freedom, not | ||||||
| price.  Our General Public Licenses are designed to make sure that you | price.  Our General Public Licenses are designed to make sure that you | ||||||
| @@ -26,44 +24,34 @@ 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 | 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. | free programs, and that you know you can do these things. | ||||||
|  |  | ||||||
|   To protect your rights, we need to prevent others from denying you |   Developers that use our General Public Licenses protect your rights | ||||||
| these rights or asking you to surrender the rights.  Therefore, you have | with two steps: (1) assert copyright on the software, and (2) offer | ||||||
| certain responsibilities if you distribute copies of the software, or if | you this License which gives you legal permission to copy, distribute | ||||||
| you modify it: responsibilities to respect the freedom of others. | and/or modify the software. | ||||||
|  |  | ||||||
|   For example, if you distribute copies of such a program, whether |   A secondary benefit of defending all users' freedom is that | ||||||
| gratis or for a fee, you must pass on to the recipients the same | improvements made in alternate versions of the program, if they | ||||||
| freedoms that you received.  You must make sure that they, too, receive | receive widespread use, become available for other developers to | ||||||
| or can get the source code.  And you must show them these terms so they | incorporate.  Many developers of free software are heartened and | ||||||
| know their rights. | 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. | ||||||
|  |  | ||||||
|   Developers that use the GNU GPL protect your rights with two steps: |   The GNU Affero General Public License is designed specifically to | ||||||
| (1) assert copyright on the software, and (2) offer you this License | ensure that, in such cases, the modified source code becomes available | ||||||
| giving you legal permission to copy, distribute and/or modify it. | 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. | ||||||
|  |  | ||||||
|   For the developers' and authors' protection, the GPL clearly explains |   An older license, called the Affero General Public License and | ||||||
| that there is no warranty for this free software.  For both users' and | published by Affero, was designed to accomplish similar goals.  This is | ||||||
| authors' sake, the GPL requires that modified versions be marked as | a different license, not a version of the Affero GPL, but Affero has | ||||||
| changed, so that their problems will not be attributed erroneously to | released a new version of the Affero GPL which permits relicensing under | ||||||
| authors of previous versions. | this license. | ||||||
|  |  | ||||||
|   Some devices are designed to deny users access to install or run |  | ||||||
| modified versions of the software inside them, although the manufacturer |  | ||||||
| can do so.  This is fundamentally incompatible with the aim of |  | ||||||
| protecting users' freedom to change the software.  The systematic |  | ||||||
| pattern of such abuse occurs in the area of products for individuals to |  | ||||||
| use, which is precisely where it is most unacceptable.  Therefore, we |  | ||||||
| have designed this version of the GPL to prohibit the practice for those |  | ||||||
| products.  If such problems arise substantially in other domains, we |  | ||||||
| stand ready to extend this provision to those domains in future versions |  | ||||||
| of the GPL, as needed to protect the freedom of users. |  | ||||||
|  |  | ||||||
|   Finally, every program is threatened constantly by software patents. |  | ||||||
| States should not allow patents to restrict development and use of |  | ||||||
| software on general-purpose computers, but in those that do, we wish to |  | ||||||
| avoid the special danger that patents applied to a free program could |  | ||||||
| make it effectively proprietary.  To prevent this, the GPL assures that |  | ||||||
| patents cannot be used to render the program non-free. |  | ||||||
|  |  | ||||||
|   The precise terms and conditions for copying, distribution and |   The precise terms and conditions for copying, distribution and | ||||||
| modification follow. | modification follow. | ||||||
| @@ -72,7 +60,7 @@ modification follow. | |||||||
|  |  | ||||||
|   0. Definitions. |   0. Definitions. | ||||||
|  |  | ||||||
|   "This License" refers to version 3 of the GNU General Public License. |   "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 |   "Copyright" also means copyright-like laws that apply to other kinds of | ||||||
| works, such as semiconductor masks. | works, such as semiconductor masks. | ||||||
| @@ -549,35 +537,45 @@ 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 | the Program, the only way you could satisfy both those terms and this | ||||||
| License would be to refrain entirely from conveying the Program. | License would be to refrain entirely from conveying the Program. | ||||||
|  |  | ||||||
|   13. Use with the GNU Affero General Public License. |   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 |   Notwithstanding any other provision of this License, you have | ||||||
| permission to link or combine any covered work with a work licensed | permission to link or combine any covered work with a work licensed | ||||||
| under version 3 of the GNU Affero General Public License into a single | under version 3 of the GNU General Public License into a single | ||||||
| combined work, and to convey the resulting work.  The terms of this | 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, | License will continue to apply to the part which is the covered work, | ||||||
| but the special requirements of the GNU Affero General Public License, | but the work with which it is combined will remain governed by version | ||||||
| section 13, concerning interaction through a network will apply to the | 3 of the GNU General Public License. | ||||||
| combination as such. |  | ||||||
|  |  | ||||||
|   14. Revised Versions of this License. |   14. Revised Versions of this License. | ||||||
|  |  | ||||||
|   The Free Software Foundation may publish revised and/or new versions of |   The Free Software Foundation may publish revised and/or new versions of | ||||||
| the GNU General Public License from time to time.  Such new versions will | the GNU Affero General Public License from time to time.  Such new versions | ||||||
| be similar in spirit to the present version, but may differ in detail to | will be similar in spirit to the present version, but may differ in detail to | ||||||
| address new problems or concerns. | address new problems or concerns. | ||||||
|  |  | ||||||
|   Each version is given a distinguishing version number.  If the |   Each version is given a distinguishing version number.  If the | ||||||
| Program specifies that a certain numbered version of the GNU General | Program specifies that a certain numbered version of the GNU Affero General | ||||||
| Public License "or any later version" applies to it, you have the | Public License "or any later version" applies to it, you have the | ||||||
| option of following the terms and conditions either of that numbered | option of following the terms and conditions either of that numbered | ||||||
| version or of any later version published by the Free Software | version or of any later version published by the Free Software | ||||||
| Foundation.  If the Program does not specify a version number of the | Foundation.  If the Program does not specify a version number of the | ||||||
| GNU General Public License, you may choose any version ever published | GNU Affero General Public License, you may choose any version ever published | ||||||
| by the Free Software Foundation. | by the Free Software Foundation. | ||||||
|  |  | ||||||
|   If the Program specifies that a proxy can decide which future |   If the Program specifies that a proxy can decide which future | ||||||
| versions of the GNU General Public License can be used, that proxy's | versions of the GNU Affero General Public License can be used, that proxy's | ||||||
| public statement of acceptance of a version permanently authorizes you | public statement of acceptance of a version permanently authorizes you | ||||||
| to choose that version for the Program. | to choose that version for the Program. | ||||||
|  |  | ||||||
| @@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found. | |||||||
|     Copyright (C) <year>  <name of author> |     Copyright (C) <year>  <name of author> | ||||||
|  |  | ||||||
|     This program is free software: you can redistribute it and/or modify |     This program is free software: you can redistribute it and/or modify | ||||||
|     it under the terms of the GNU General Public License as published by |     it under the terms of the GNU Affero General Public License as published | ||||||
|     the Free Software Foundation, either version 3 of the License, or |     by the Free Software Foundation, either version 3 of the License, or | ||||||
|     (at your option) any later version. |     (at your option) any later version. | ||||||
|  |  | ||||||
|     This program is distributed in the hope that it will be useful, |     This program is distributed in the hope that it will be useful, | ||||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of |     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|     GNU General Public License for more details. |     GNU Affero General Public License for more details. | ||||||
|  |  | ||||||
|     You should have received a copy of the GNU General Public License |     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/>. |     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. | Also add information on how to contact you by electronic and paper mail. | ||||||
|  |  | ||||||
|   If the program does terminal interaction, make it output a short |   If your software can interact with users remotely through a computer | ||||||
| notice like this when it starts in an interactive mode: | 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 | ||||||
|     <program>  Copyright (C) <year>  <name of author> | interface could display a "Source" link that leads users to an archive | ||||||
|     This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | of the code.  There are many ways you could offer source, and different | ||||||
|     This is free software, and you are welcome to redistribute it | solutions will be better for different programs; see section 13 for the | ||||||
|     under certain conditions; type `show c' for details. | specific requirements. | ||||||
|  |  | ||||||
| The hypothetical commands `show w' and `show c' should show the appropriate |  | ||||||
| parts of the General Public License.  Of course, your program's commands |  | ||||||
| might be different; for a GUI interface, you would use an "about box". |  | ||||||
|  |  | ||||||
|   You should also get your employer (if you work as a programmer) or school, |   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. | 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 GPL, see | For more information on this, and how to apply and follow the GNU AGPL, see | ||||||
| <https://www.gnu.org/licenses/>. | <https://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|   The GNU General Public License does not permit incorporating your program |  | ||||||
| into proprietary programs.  If your program is a subroutine library, you |  | ||||||
| may consider it more useful to permit linking proprietary applications with |  | ||||||
| the library.  If this is what you want to do, use the GNU Lesser General |  | ||||||
| Public License instead of this License.  But first, please read |  | ||||||
| <https://www.gnu.org/licenses/why-not-lgpl.html>. |  | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
| [](https://hub.docker.com/r/vaultwarden/server) | [](https://hub.docker.com/r/vaultwarden/server) | ||||||
| [](https://deps.rs/repo/github/dani-garcia/vaultwarden) | [](https://deps.rs/repo/github/dani-garcia/vaultwarden) | ||||||
| [](https://github.com/dani-garcia/vaultwarden/releases/latest) | [](https://github.com/dani-garcia/vaultwarden/releases/latest) | ||||||
| [](https://github.com/dani-garcia/vaultwarden/blob/main/LICENSE.txt) | [](https://github.com/dani-garcia/vaultwarden/blob/main/LICENSE.txt) | ||||||
| [](https://matrix.to/#/#vaultwarden:matrix.org) | [](https://matrix.to/#/#vaultwarden:matrix.org) | ||||||
|  |  | ||||||
| Image is based on [Rust implementation of Bitwarden API](https://github.com/dani-garcia/vaultwarden). | Image is based on [Rust implementation of Bitwarden API](https://github.com/dani-garcia/vaultwarden). | ||||||
| @@ -39,7 +39,7 @@ docker run -d --name vaultwarden -v /vw-data/:/data/ -p 80:80 vaultwarden/server | |||||||
| ``` | ``` | ||||||
| This will preserve any persistent data under /vw-data/, you can adapt the path to whatever suits you. | This will preserve any persistent data under /vw-data/, you can adapt the path to whatever suits you. | ||||||
|  |  | ||||||
| **IMPORTANT**: Some web browsers, like Chrome, disallow the use of Web Crypto APIs in insecure contexts. In this case, you might get an error like `Cannot read property 'importKey'`. To solve this problem, you need to access the web vault from HTTPS.  | **IMPORTANT**: Some web browsers, like Chrome, disallow the use of Web Crypto APIs in insecure contexts. In this case, you might get an error like `Cannot read property 'importKey'`. To solve this problem, you need to access the web vault from HTTPS. | ||||||
|  |  | ||||||
| This can be configured in [vaultwarden directly](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-HTTPS) or using a third-party reverse proxy ([some examples](https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples)). | This can be configured in [vaultwarden directly](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-HTTPS) or using a third-party reverse proxy ([some examples](https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples)). | ||||||
|  |  | ||||||
|   | |||||||
| @@ -50,7 +50,7 @@ | |||||||
| {% else %} | {% else %} | ||||||
| {%   set package_arch_target_param = "" %} | {%   set package_arch_target_param = "" %} | ||||||
| {% endif %} | {% endif %} | ||||||
| {% if "buildx" in target_file %} | {% if "buildkit" in target_file %} | ||||||
| {%   set mount_rust_cache = "--mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry " %} | {%   set mount_rust_cache = "--mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry " %} | ||||||
| {% else %} | {% else %} | ||||||
| {%   set mount_rust_cache = "" %} | {%   set mount_rust_cache = "" %} | ||||||
| @@ -83,8 +83,6 @@ FROM vaultwarden/web-vault@{{ vault_image_digest }} as vault | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM {{ build_stage_base_image }} as build | FROM {{ build_stage_base_image }} as build | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -93,7 +91,6 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN {{ mount_rust_cache -}} mkdir -pv "${CARGO_HOME}" \ | RUN {{ mount_rust_cache -}} mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| @@ -104,21 +101,20 @@ RUN {{ mount_rust_cache -}} mkdir -pv "${CARGO_HOME}" \ | |||||||
| ENV RUSTFLAGS='-Clink-arg=/usr/local/musl/{{ package_arch_target }}/lib/libatomic.a' | ENV RUSTFLAGS='-Clink-arg=/usr/local/musl/{{ package_arch_target }}/lib/libatomic.a' | ||||||
| {%   endif %} | {%   endif %} | ||||||
| {% elif "arm" in target_file %} | {% elif "arm" in target_file %} | ||||||
| # | # Install build dependencies for the {{ package_arch_name }} architecture | ||||||
| # Install required build libs for {{ package_arch_name }} architecture. |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN dpkg --add-architecture {{ package_arch_name }} \ | RUN dpkg --add-architecture {{ package_arch_name }} \ | ||||||
|     && apt-get update \ |     && apt-get update \ | ||||||
|     && apt-get install -y \ |     && apt-get install -y \ | ||||||
|         --no-install-recommends \ |         --no-install-recommends \ | ||||||
|         libssl-dev{{ package_arch_prefix }} \ |         gcc-{{ package_cross_compiler }} \ | ||||||
|         libc6-dev{{ package_arch_prefix }} \ |         libc6-dev{{ package_arch_prefix }} \ | ||||||
|         libpq5{{ package_arch_prefix }} \ |         libcap2-bin \ | ||||||
|         libpq-dev{{ package_arch_prefix }} \ |  | ||||||
|         libmariadb3{{ package_arch_prefix }} \ |  | ||||||
|         libmariadb-dev{{ package_arch_prefix }} \ |         libmariadb-dev{{ package_arch_prefix }} \ | ||||||
|         libmariadb-dev-compat{{ package_arch_prefix }} \ |         libmariadb-dev-compat{{ package_arch_prefix }} \ | ||||||
|         gcc-{{ package_cross_compiler }} \ |         libmariadb3{{ package_arch_prefix }} \ | ||||||
|  |         libpq-dev{{ package_arch_prefix }} \ | ||||||
|  |         libpq5{{ package_arch_prefix }} \ | ||||||
|  |         libssl-dev{{ package_arch_prefix }} \ | ||||||
|     # |     # | ||||||
|     # Make sure cargo has the right target config |     # Make sure cargo has the right target config | ||||||
|     && echo '[target.{{ package_arch_target }}]' >> "${CARGO_HOME}/config" \ |     && echo '[target.{{ package_arch_target }}]' >> "${CARGO_HOME}/config" \ | ||||||
| @@ -130,16 +126,14 @@ ENV CC_{{ package_arch_target | replace("-", "_") }}="/usr/bin/{{ package_cross_ | |||||||
|     CROSS_COMPILE="1" \ |     CROSS_COMPILE="1" \ | ||||||
|     OPENSSL_INCLUDE_DIR="/usr/include/{{ package_cross_compiler }}" \ |     OPENSSL_INCLUDE_DIR="/usr/include/{{ package_cross_compiler }}" \ | ||||||
|     OPENSSL_LIB_DIR="/usr/lib/{{ package_cross_compiler }}" |     OPENSSL_LIB_DIR="/usr/lib/{{ package_cross_compiler }}" | ||||||
|  |  | ||||||
| {% elif "amd64" in target_file %} | {% elif "amd64" in target_file %} | ||||||
| # Install DB packages | # Install build dependencies | ||||||
| RUN apt-get update \ | RUN apt-get update \ | ||||||
|     && apt-get install -y \ |     && apt-get install -y \ | ||||||
|         --no-install-recommends \ |         --no-install-recommends \ | ||||||
|         libmariadb-dev{{ package_arch_prefix }} \ |         libcap2-bin \ | ||||||
|         libpq-dev{{ package_arch_prefix }} \ |         libmariadb-dev \ | ||||||
|     && apt-get clean \ |         libpq-dev | ||||||
|     && rm -rf /var/lib/apt/lists/* |  | ||||||
| {% endif %} | {% endif %} | ||||||
|  |  | ||||||
| # Creates a dummy project used to grab dependencies | # Creates a dummy project used to grab dependencies | ||||||
| @@ -178,9 +172,20 @@ RUN touch src/main.rs | |||||||
|  |  | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN {{ mount_rust_cache -}} cargo build --features ${DB} --release{{ package_arch_target_param }} | RUN {{ mount_rust_cache -}} cargo build --features ${DB} --release{{ package_arch_target_param }} | ||||||
|  |  | ||||||
|  | {% if "buildkit" in target_file %} | ||||||
|  | # Add the `cap_net_bind_service` capability to allow listening on | ||||||
|  | # privileged (< 1024) ports even when running as a non-root user. | ||||||
|  | # This is only done if building with BuildKit; with the legacy | ||||||
|  | # builder, the `COPY` instruction doesn't carry over capabilities. | ||||||
|  | {%   if package_arch_target is defined %} | ||||||
|  | RUN setcap cap_net_bind_service=+ep target/{{ package_arch_target }}/release/vaultwarden | ||||||
|  | {%   else %} | ||||||
|  | RUN setcap cap_net_bind_service=+ep target/release/vaultwarden | ||||||
|  | {%   endif %} | ||||||
|  | {% endif %} | ||||||
|  |  | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -195,7 +200,6 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|  |  | ||||||
|  |  | ||||||
| {% if "amd64" not in target_file %} | {% if "amd64" not in target_file %} | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
| {% endif %} | {% endif %} | ||||||
|  |  | ||||||
| @@ -203,18 +207,18 @@ RUN [ "cross-build-start" ] | |||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
| {% if "alpine" in runtime_stage_base_image %} | {% if "alpine" in runtime_stage_base_image %} | ||||||
|     && apk add --no-cache \ |     && apk add --no-cache \ | ||||||
|         openssl \ |         ca-certificates \ | ||||||
|         tzdata \ |  | ||||||
|         curl \ |         curl \ | ||||||
|         ca-certificates |         openssl \ | ||||||
|  |         tzdata | ||||||
| {% else %} | {% else %} | ||||||
|     && apt-get update && apt-get install -y \ |     && apt-get update && apt-get install -y \ | ||||||
|     --no-install-recommends \ |     --no-install-recommends \ | ||||||
|     openssl \ |  | ||||||
|     ca-certificates \ |     ca-certificates \ | ||||||
|     curl \ |     curl \ | ||||||
|     libmariadb-dev-compat \ |     libmariadb-dev-compat \ | ||||||
|     libpq5 \ |     libpq5 \ | ||||||
|  |     openssl \ | ||||||
|     && apt-get clean \ |     && apt-get clean \ | ||||||
|     && rm -rf /var/lib/apt/lists/* |     && rm -rf /var/lib/apt/lists/* | ||||||
| {% endif %} | {% endif %} | ||||||
| @@ -222,13 +226,11 @@ RUN mkdir /data \ | |||||||
| {% if "armv6" in target_file and "alpine" not in target_file %} | {% if "armv6" in target_file and "alpine" not in target_file %} | ||||||
| # In the Balena Bullseye images for armv6/rpi-debian there is a missing symlink. | # In the Balena Bullseye images for armv6/rpi-debian there is a missing symlink. | ||||||
| # This symlink was there in the buster images, and for some reason this is needed. | # This symlink was there in the buster images, and for some reason this is needed. | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN ln -v -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3 | RUN ln -v -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3 | ||||||
|  |  | ||||||
| {% endif -%} | {% endif -%} | ||||||
|  |  | ||||||
| {% if "amd64" not in target_file %} | {% if "amd64" not in target_file %} | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
| {% endif %} | {% endif %} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,8 +8,8 @@ all: $(OBJECTS) | |||||||
| %/Dockerfile.alpine: Dockerfile.j2 render_template | %/Dockerfile.alpine: Dockerfile.j2 render_template | ||||||
| 	./render_template "$<" "{\"target_file\":\"$@\"}" > "$@" | 	./render_template "$<" "{\"target_file\":\"$@\"}" > "$@" | ||||||
|  |  | ||||||
| %/Dockerfile.buildx: Dockerfile.j2 render_template | %/Dockerfile.buildkit: Dockerfile.j2 render_template | ||||||
| 	./render_template "$<" "{\"target_file\":\"$@\"}" > "$@" | 	./render_template "$<" "{\"target_file\":\"$@\"}" > "$@" | ||||||
|  |  | ||||||
| %/Dockerfile.buildx.alpine: Dockerfile.j2 render_template | %/Dockerfile.buildkit.alpine: Dockerfile.j2 render_template | ||||||
| 	./render_template "$<" "{\"target_file\":\"$@\"}" > "$@" | 	./render_template "$<" "{\"target_file\":\"$@\"}" > "$@" | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM rust:1.66-bullseye as build | FROM rust:1.66-bullseye as build | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,19 +37,17 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN mkdir -pv "${CARGO_HOME}" \ | RUN mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
|  |  | ||||||
| # Install DB packages | # Install build dependencies | ||||||
| RUN apt-get update \ | RUN apt-get update \ | ||||||
|     && apt-get install -y \ |     && apt-get install -y \ | ||||||
|         --no-install-recommends \ |         --no-install-recommends \ | ||||||
|  |         libcap2-bin \ | ||||||
|         libmariadb-dev \ |         libmariadb-dev \ | ||||||
|         libpq-dev \ |         libpq-dev | ||||||
|     && apt-get clean \ |  | ||||||
|     && rm -rf /var/lib/apt/lists/* |  | ||||||
|  |  | ||||||
| # Creates a dummy project used to grab dependencies | # Creates a dummy project used to grab dependencies | ||||||
| RUN USER=root cargo new --bin /app | RUN USER=root cargo new --bin /app | ||||||
| @@ -81,9 +77,9 @@ RUN touch src/main.rs | |||||||
|  |  | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN cargo build --features ${DB} --release | RUN cargo build --features ${DB} --release | ||||||
|  |  | ||||||
|  |  | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -98,11 +94,11 @@ ENV ROCKET_PROFILE="release" \ | |||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apt-get update && apt-get install -y \ |     && apt-get update && apt-get install -y \ | ||||||
|     --no-install-recommends \ |     --no-install-recommends \ | ||||||
|     openssl \ |  | ||||||
|     ca-certificates \ |     ca-certificates \ | ||||||
|     curl \ |     curl \ | ||||||
|     libmariadb-dev-compat \ |     libmariadb-dev-compat \ | ||||||
|     libpq5 \ |     libpq5 \ | ||||||
|  |     openssl \ | ||||||
|     && apt-get clean \ |     && apt-get clean \ | ||||||
|     && rm -rf /var/lib/apt/lists/* |     && rm -rf /var/lib/apt/lists/* | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM blackdex/rust-musl:x86_64-musl-stable-1.66.1 as build | FROM blackdex/rust-musl:x86_64-musl-stable-1.66.1 as build | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,7 +37,6 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN mkdir -pv "${CARGO_HOME}" \ | RUN mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| @@ -75,9 +72,9 @@ RUN touch src/main.rs | |||||||
|  |  | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN cargo build --features ${DB} --release --target=x86_64-unknown-linux-musl | RUN cargo build --features ${DB} --release --target=x86_64-unknown-linux-musl | ||||||
|  |  | ||||||
|  |  | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -93,10 +90,10 @@ ENV ROCKET_PROFILE="release" \ | |||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apk add --no-cache \ |     && apk add --no-cache \ | ||||||
|         openssl \ |         ca-certificates \ | ||||||
|         tzdata \ |  | ||||||
|         curl \ |         curl \ | ||||||
|         ca-certificates |         openssl \ | ||||||
|  |         tzdata | ||||||
|  |  | ||||||
|  |  | ||||||
| VOLUME /data | VOLUME /data | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM rust:1.66-bullseye as build | FROM rust:1.66-bullseye as build | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,19 +37,17 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| 
 | 
 | ||||||
| # Install DB packages | # Install build dependencies | ||||||
| RUN apt-get update \ | RUN apt-get update \ | ||||||
|     && apt-get install -y \ |     && apt-get install -y \ | ||||||
|         --no-install-recommends \ |         --no-install-recommends \ | ||||||
|  |         libcap2-bin \ | ||||||
|         libmariadb-dev \ |         libmariadb-dev \ | ||||||
|         libpq-dev \ |         libpq-dev | ||||||
|     && apt-get clean \ |  | ||||||
|     && rm -rf /var/lib/apt/lists/* |  | ||||||
| 
 | 
 | ||||||
| # Creates a dummy project used to grab dependencies | # Creates a dummy project used to grab dependencies | ||||||
| RUN USER=root cargo new --bin /app | RUN USER=root cargo new --bin /app | ||||||
| @@ -81,9 +77,14 @@ RUN touch src/main.rs | |||||||
| 
 | 
 | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release | ||||||
| 
 | 
 | ||||||
|  | # Add the `cap_net_bind_service` capability to allow listening on | ||||||
|  | # privileged (< 1024) ports even when running as a non-root user. | ||||||
|  | # This is only done if building with BuildKit; with the legacy | ||||||
|  | # builder, the `COPY` instruction doesn't carry over capabilities. | ||||||
|  | RUN setcap cap_net_bind_service=+ep target/release/vaultwarden | ||||||
|  | 
 | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -98,11 +99,11 @@ ENV ROCKET_PROFILE="release" \ | |||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apt-get update && apt-get install -y \ |     && apt-get update && apt-get install -y \ | ||||||
|     --no-install-recommends \ |     --no-install-recommends \ | ||||||
|     openssl \ |  | ||||||
|     ca-certificates \ |     ca-certificates \ | ||||||
|     curl \ |     curl \ | ||||||
|     libmariadb-dev-compat \ |     libmariadb-dev-compat \ | ||||||
|     libpq5 \ |     libpq5 \ | ||||||
|  |     openssl \ | ||||||
|     && apt-get clean \ |     && apt-get clean \ | ||||||
|     && rm -rf /var/lib/apt/lists/* |     && rm -rf /var/lib/apt/lists/* | ||||||
| 
 | 
 | ||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM blackdex/rust-musl:x86_64-musl-stable-1.66.1 as build | FROM blackdex/rust-musl:x86_64-musl-stable-1.66.1 as build | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,7 +37,6 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| @@ -75,9 +72,14 @@ RUN touch src/main.rs | |||||||
| 
 | 
 | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=x86_64-unknown-linux-musl | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=x86_64-unknown-linux-musl | ||||||
| 
 | 
 | ||||||
|  | # Add the `cap_net_bind_service` capability to allow listening on | ||||||
|  | # privileged (< 1024) ports even when running as a non-root user. | ||||||
|  | # This is only done if building with BuildKit; with the legacy | ||||||
|  | # builder, the `COPY` instruction doesn't carry over capabilities. | ||||||
|  | RUN setcap cap_net_bind_service=+ep target/x86_64-unknown-linux-musl/release/vaultwarden | ||||||
|  | 
 | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -93,10 +95,10 @@ ENV ROCKET_PROFILE="release" \ | |||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apk add --no-cache \ |     && apk add --no-cache \ | ||||||
|         openssl \ |         ca-certificates \ | ||||||
|         tzdata \ |  | ||||||
|         curl \ |         curl \ | ||||||
|         ca-certificates |         openssl \ | ||||||
|  |         tzdata | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| VOLUME /data | VOLUME /data | ||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM rust:1.66-bullseye as build | FROM rust:1.66-bullseye as build | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,26 +37,24 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN mkdir -pv "${CARGO_HOME}" \ | RUN mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
|  |  | ||||||
| # | # Install build dependencies for the arm64 architecture | ||||||
| # Install required build libs for arm64 architecture. |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN dpkg --add-architecture arm64 \ | RUN dpkg --add-architecture arm64 \ | ||||||
|     && apt-get update \ |     && apt-get update \ | ||||||
|     && apt-get install -y \ |     && apt-get install -y \ | ||||||
|         --no-install-recommends \ |         --no-install-recommends \ | ||||||
|         libssl-dev:arm64 \ |         gcc-aarch64-linux-gnu \ | ||||||
|         libc6-dev:arm64 \ |         libc6-dev:arm64 \ | ||||||
|         libpq5:arm64 \ |         libcap2-bin \ | ||||||
|         libpq-dev:arm64 \ |  | ||||||
|         libmariadb3:arm64 \ |  | ||||||
|         libmariadb-dev:arm64 \ |         libmariadb-dev:arm64 \ | ||||||
|         libmariadb-dev-compat:arm64 \ |         libmariadb-dev-compat:arm64 \ | ||||||
|         gcc-aarch64-linux-gnu \ |         libmariadb3:arm64 \ | ||||||
|  |         libpq-dev:arm64 \ | ||||||
|  |         libpq5:arm64 \ | ||||||
|  |         libssl-dev:arm64 \ | ||||||
|     # |     # | ||||||
|     # Make sure cargo has the right target config |     # Make sure cargo has the right target config | ||||||
|     && echo '[target.aarch64-unknown-linux-gnu]' >> "${CARGO_HOME}/config" \ |     && echo '[target.aarch64-unknown-linux-gnu]' >> "${CARGO_HOME}/config" \ | ||||||
| @@ -71,7 +67,6 @@ ENV CC_aarch64_unknown_linux_gnu="/usr/bin/aarch64-linux-gnu-gcc" \ | |||||||
|     OPENSSL_INCLUDE_DIR="/usr/include/aarch64-linux-gnu" \ |     OPENSSL_INCLUDE_DIR="/usr/include/aarch64-linux-gnu" \ | ||||||
|     OPENSSL_LIB_DIR="/usr/lib/aarch64-linux-gnu" |     OPENSSL_LIB_DIR="/usr/lib/aarch64-linux-gnu" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Creates a dummy project used to grab dependencies | # Creates a dummy project used to grab dependencies | ||||||
| RUN USER=root cargo new --bin /app | RUN USER=root cargo new --bin /app | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
| @@ -101,9 +96,9 @@ RUN touch src/main.rs | |||||||
|  |  | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN cargo build --features ${DB} --release --target=aarch64-unknown-linux-gnu | RUN cargo build --features ${DB} --release --target=aarch64-unknown-linux-gnu | ||||||
|  |  | ||||||
|  |  | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -113,22 +108,20 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     ROCKET_ADDRESS=0.0.0.0 \ |     ROCKET_ADDRESS=0.0.0.0 \ | ||||||
|     ROCKET_PORT=80 |     ROCKET_PORT=80 | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
|  |  | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apt-get update && apt-get install -y \ |     && apt-get update && apt-get install -y \ | ||||||
|     --no-install-recommends \ |     --no-install-recommends \ | ||||||
|     openssl \ |  | ||||||
|     ca-certificates \ |     ca-certificates \ | ||||||
|     curl \ |     curl \ | ||||||
|     libmariadb-dev-compat \ |     libmariadb-dev-compat \ | ||||||
|     libpq5 \ |     libpq5 \ | ||||||
|  |     openssl \ | ||||||
|     && apt-get clean \ |     && apt-get clean \ | ||||||
|     && rm -rf /var/lib/apt/lists/* |     && rm -rf /var/lib/apt/lists/* | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
|  |  | ||||||
| VOLUME /data | VOLUME /data | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM blackdex/rust-musl:aarch64-musl-stable-1.66.1 as build | FROM blackdex/rust-musl:aarch64-musl-stable-1.66.1 as build | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,7 +37,6 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN mkdir -pv "${CARGO_HOME}" \ | RUN mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| @@ -75,9 +72,9 @@ RUN touch src/main.rs | |||||||
|  |  | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN cargo build --features ${DB} --release --target=aarch64-unknown-linux-musl | RUN cargo build --features ${DB} --release --target=aarch64-unknown-linux-musl | ||||||
|  |  | ||||||
|  |  | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -89,18 +86,16 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     SSL_CERT_DIR=/etc/ssl/certs |     SSL_CERT_DIR=/etc/ssl/certs | ||||||
|  |  | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
|  |  | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apk add --no-cache \ |     && apk add --no-cache \ | ||||||
|         openssl \ |         ca-certificates \ | ||||||
|         tzdata \ |  | ||||||
|         curl \ |         curl \ | ||||||
|         ca-certificates |         openssl \ | ||||||
|  |         tzdata | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
|  |  | ||||||
| VOLUME /data | VOLUME /data | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM rust:1.66-bullseye as build | FROM rust:1.66-bullseye as build | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,26 +37,24 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| 
 | 
 | ||||||
| # | # Install build dependencies for the arm64 architecture | ||||||
| # Install required build libs for arm64 architecture. |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN dpkg --add-architecture arm64 \ | RUN dpkg --add-architecture arm64 \ | ||||||
|     && apt-get update \ |     && apt-get update \ | ||||||
|     && apt-get install -y \ |     && apt-get install -y \ | ||||||
|         --no-install-recommends \ |         --no-install-recommends \ | ||||||
|         libssl-dev:arm64 \ |         gcc-aarch64-linux-gnu \ | ||||||
|         libc6-dev:arm64 \ |         libc6-dev:arm64 \ | ||||||
|         libpq5:arm64 \ |         libcap2-bin \ | ||||||
|         libpq-dev:arm64 \ |  | ||||||
|         libmariadb3:arm64 \ |  | ||||||
|         libmariadb-dev:arm64 \ |         libmariadb-dev:arm64 \ | ||||||
|         libmariadb-dev-compat:arm64 \ |         libmariadb-dev-compat:arm64 \ | ||||||
|         gcc-aarch64-linux-gnu \ |         libmariadb3:arm64 \ | ||||||
|  |         libpq-dev:arm64 \ | ||||||
|  |         libpq5:arm64 \ | ||||||
|  |         libssl-dev:arm64 \ | ||||||
|     # |     # | ||||||
|     # Make sure cargo has the right target config |     # Make sure cargo has the right target config | ||||||
|     && echo '[target.aarch64-unknown-linux-gnu]' >> "${CARGO_HOME}/config" \ |     && echo '[target.aarch64-unknown-linux-gnu]' >> "${CARGO_HOME}/config" \ | ||||||
| @@ -71,7 +67,6 @@ ENV CC_aarch64_unknown_linux_gnu="/usr/bin/aarch64-linux-gnu-gcc" \ | |||||||
|     OPENSSL_INCLUDE_DIR="/usr/include/aarch64-linux-gnu" \ |     OPENSSL_INCLUDE_DIR="/usr/include/aarch64-linux-gnu" \ | ||||||
|     OPENSSL_LIB_DIR="/usr/lib/aarch64-linux-gnu" |     OPENSSL_LIB_DIR="/usr/lib/aarch64-linux-gnu" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Creates a dummy project used to grab dependencies | # Creates a dummy project used to grab dependencies | ||||||
| RUN USER=root cargo new --bin /app | RUN USER=root cargo new --bin /app | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
| @@ -101,9 +96,14 @@ RUN touch src/main.rs | |||||||
| 
 | 
 | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=aarch64-unknown-linux-gnu | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=aarch64-unknown-linux-gnu | ||||||
| 
 | 
 | ||||||
|  | # Add the `cap_net_bind_service` capability to allow listening on | ||||||
|  | # privileged (< 1024) ports even when running as a non-root user. | ||||||
|  | # This is only done if building with BuildKit; with the legacy | ||||||
|  | # builder, the `COPY` instruction doesn't carry over capabilities. | ||||||
|  | RUN setcap cap_net_bind_service=+ep target/aarch64-unknown-linux-gnu/release/vaultwarden | ||||||
|  | 
 | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -113,22 +113,20 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     ROCKET_ADDRESS=0.0.0.0 \ |     ROCKET_ADDRESS=0.0.0.0 \ | ||||||
|     ROCKET_PORT=80 |     ROCKET_PORT=80 | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
| 
 | 
 | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apt-get update && apt-get install -y \ |     && apt-get update && apt-get install -y \ | ||||||
|     --no-install-recommends \ |     --no-install-recommends \ | ||||||
|     openssl \ |  | ||||||
|     ca-certificates \ |     ca-certificates \ | ||||||
|     curl \ |     curl \ | ||||||
|     libmariadb-dev-compat \ |     libmariadb-dev-compat \ | ||||||
|     libpq5 \ |     libpq5 \ | ||||||
|  |     openssl \ | ||||||
|     && apt-get clean \ |     && apt-get clean \ | ||||||
|     && rm -rf /var/lib/apt/lists/* |     && rm -rf /var/lib/apt/lists/* | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
| 
 | 
 | ||||||
| VOLUME /data | VOLUME /data | ||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM blackdex/rust-musl:aarch64-musl-stable-1.66.1 as build | FROM blackdex/rust-musl:aarch64-musl-stable-1.66.1 as build | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,7 +37,6 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| @@ -75,9 +72,14 @@ RUN touch src/main.rs | |||||||
| 
 | 
 | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=aarch64-unknown-linux-musl | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=aarch64-unknown-linux-musl | ||||||
| 
 | 
 | ||||||
|  | # Add the `cap_net_bind_service` capability to allow listening on | ||||||
|  | # privileged (< 1024) ports even when running as a non-root user. | ||||||
|  | # This is only done if building with BuildKit; with the legacy | ||||||
|  | # builder, the `COPY` instruction doesn't carry over capabilities. | ||||||
|  | RUN setcap cap_net_bind_service=+ep target/aarch64-unknown-linux-musl/release/vaultwarden | ||||||
|  | 
 | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -89,18 +91,16 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     SSL_CERT_DIR=/etc/ssl/certs |     SSL_CERT_DIR=/etc/ssl/certs | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
| 
 | 
 | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apk add --no-cache \ |     && apk add --no-cache \ | ||||||
|         openssl \ |         ca-certificates \ | ||||||
|         tzdata \ |  | ||||||
|         curl \ |         curl \ | ||||||
|         ca-certificates |         openssl \ | ||||||
|  |         tzdata | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
| 
 | 
 | ||||||
| VOLUME /data | VOLUME /data | ||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM rust:1.66-bullseye as build | FROM rust:1.66-bullseye as build | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,26 +37,24 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN mkdir -pv "${CARGO_HOME}" \ | RUN mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
|  |  | ||||||
| # | # Install build dependencies for the armel architecture | ||||||
| # Install required build libs for armel architecture. |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN dpkg --add-architecture armel \ | RUN dpkg --add-architecture armel \ | ||||||
|     && apt-get update \ |     && apt-get update \ | ||||||
|     && apt-get install -y \ |     && apt-get install -y \ | ||||||
|         --no-install-recommends \ |         --no-install-recommends \ | ||||||
|         libssl-dev:armel \ |         gcc-arm-linux-gnueabi \ | ||||||
|         libc6-dev:armel \ |         libc6-dev:armel \ | ||||||
|         libpq5:armel \ |         libcap2-bin \ | ||||||
|         libpq-dev:armel \ |  | ||||||
|         libmariadb3:armel \ |  | ||||||
|         libmariadb-dev:armel \ |         libmariadb-dev:armel \ | ||||||
|         libmariadb-dev-compat:armel \ |         libmariadb-dev-compat:armel \ | ||||||
|         gcc-arm-linux-gnueabi \ |         libmariadb3:armel \ | ||||||
|  |         libpq-dev:armel \ | ||||||
|  |         libpq5:armel \ | ||||||
|  |         libssl-dev:armel \ | ||||||
|     # |     # | ||||||
|     # Make sure cargo has the right target config |     # Make sure cargo has the right target config | ||||||
|     && echo '[target.arm-unknown-linux-gnueabi]' >> "${CARGO_HOME}/config" \ |     && echo '[target.arm-unknown-linux-gnueabi]' >> "${CARGO_HOME}/config" \ | ||||||
| @@ -71,7 +67,6 @@ ENV CC_arm_unknown_linux_gnueabi="/usr/bin/arm-linux-gnueabi-gcc" \ | |||||||
|     OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabi" \ |     OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabi" \ | ||||||
|     OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabi" |     OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabi" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Creates a dummy project used to grab dependencies | # Creates a dummy project used to grab dependencies | ||||||
| RUN USER=root cargo new --bin /app | RUN USER=root cargo new --bin /app | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
| @@ -101,9 +96,9 @@ RUN touch src/main.rs | |||||||
|  |  | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN cargo build --features ${DB} --release --target=arm-unknown-linux-gnueabi | RUN cargo build --features ${DB} --release --target=arm-unknown-linux-gnueabi | ||||||
|  |  | ||||||
|  |  | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -113,27 +108,24 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     ROCKET_ADDRESS=0.0.0.0 \ |     ROCKET_ADDRESS=0.0.0.0 \ | ||||||
|     ROCKET_PORT=80 |     ROCKET_PORT=80 | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
|  |  | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apt-get update && apt-get install -y \ |     && apt-get update && apt-get install -y \ | ||||||
|     --no-install-recommends \ |     --no-install-recommends \ | ||||||
|     openssl \ |  | ||||||
|     ca-certificates \ |     ca-certificates \ | ||||||
|     curl \ |     curl \ | ||||||
|     libmariadb-dev-compat \ |     libmariadb-dev-compat \ | ||||||
|     libpq5 \ |     libpq5 \ | ||||||
|  |     openssl \ | ||||||
|     && apt-get clean \ |     && apt-get clean \ | ||||||
|     && rm -rf /var/lib/apt/lists/* |     && rm -rf /var/lib/apt/lists/* | ||||||
|  |  | ||||||
| # In the Balena Bullseye images for armv6/rpi-debian there is a missing symlink. | # In the Balena Bullseye images for armv6/rpi-debian there is a missing symlink. | ||||||
| # This symlink was there in the buster images, and for some reason this is needed. | # This symlink was there in the buster images, and for some reason this is needed. | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN ln -v -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3 | RUN ln -v -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3 | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
|  |  | ||||||
| VOLUME /data | VOLUME /data | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM blackdex/rust-musl:arm-musleabi-stable-1.66.1 as build | FROM blackdex/rust-musl:arm-musleabi-stable-1.66.1 as build | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,7 +37,6 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN mkdir -pv "${CARGO_HOME}" \ | RUN mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| @@ -77,9 +74,9 @@ RUN touch src/main.rs | |||||||
|  |  | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN cargo build --features ${DB} --release --target=arm-unknown-linux-musleabi | RUN cargo build --features ${DB} --release --target=arm-unknown-linux-musleabi | ||||||
|  |  | ||||||
|  |  | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -91,18 +88,16 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     SSL_CERT_DIR=/etc/ssl/certs |     SSL_CERT_DIR=/etc/ssl/certs | ||||||
|  |  | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
|  |  | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apk add --no-cache \ |     && apk add --no-cache \ | ||||||
|         openssl \ |         ca-certificates \ | ||||||
|         tzdata \ |  | ||||||
|         curl \ |         curl \ | ||||||
|         ca-certificates |         openssl \ | ||||||
|  |         tzdata | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
|  |  | ||||||
| VOLUME /data | VOLUME /data | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM rust:1.66-bullseye as build | FROM rust:1.66-bullseye as build | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,26 +37,24 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| 
 | 
 | ||||||
| # | # Install build dependencies for the armel architecture | ||||||
| # Install required build libs for armel architecture. |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN dpkg --add-architecture armel \ | RUN dpkg --add-architecture armel \ | ||||||
|     && apt-get update \ |     && apt-get update \ | ||||||
|     && apt-get install -y \ |     && apt-get install -y \ | ||||||
|         --no-install-recommends \ |         --no-install-recommends \ | ||||||
|         libssl-dev:armel \ |         gcc-arm-linux-gnueabi \ | ||||||
|         libc6-dev:armel \ |         libc6-dev:armel \ | ||||||
|         libpq5:armel \ |         libcap2-bin \ | ||||||
|         libpq-dev:armel \ |  | ||||||
|         libmariadb3:armel \ |  | ||||||
|         libmariadb-dev:armel \ |         libmariadb-dev:armel \ | ||||||
|         libmariadb-dev-compat:armel \ |         libmariadb-dev-compat:armel \ | ||||||
|         gcc-arm-linux-gnueabi \ |         libmariadb3:armel \ | ||||||
|  |         libpq-dev:armel \ | ||||||
|  |         libpq5:armel \ | ||||||
|  |         libssl-dev:armel \ | ||||||
|     # |     # | ||||||
|     # Make sure cargo has the right target config |     # Make sure cargo has the right target config | ||||||
|     && echo '[target.arm-unknown-linux-gnueabi]' >> "${CARGO_HOME}/config" \ |     && echo '[target.arm-unknown-linux-gnueabi]' >> "${CARGO_HOME}/config" \ | ||||||
| @@ -71,7 +67,6 @@ ENV CC_arm_unknown_linux_gnueabi="/usr/bin/arm-linux-gnueabi-gcc" \ | |||||||
|     OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabi" \ |     OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabi" \ | ||||||
|     OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabi" |     OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabi" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Creates a dummy project used to grab dependencies | # Creates a dummy project used to grab dependencies | ||||||
| RUN USER=root cargo new --bin /app | RUN USER=root cargo new --bin /app | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
| @@ -101,9 +96,14 @@ RUN touch src/main.rs | |||||||
| 
 | 
 | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=arm-unknown-linux-gnueabi | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=arm-unknown-linux-gnueabi | ||||||
| 
 | 
 | ||||||
|  | # Add the `cap_net_bind_service` capability to allow listening on | ||||||
|  | # privileged (< 1024) ports even when running as a non-root user. | ||||||
|  | # This is only done if building with BuildKit; with the legacy | ||||||
|  | # builder, the `COPY` instruction doesn't carry over capabilities. | ||||||
|  | RUN setcap cap_net_bind_service=+ep target/arm-unknown-linux-gnueabi/release/vaultwarden | ||||||
|  | 
 | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -113,27 +113,24 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     ROCKET_ADDRESS=0.0.0.0 \ |     ROCKET_ADDRESS=0.0.0.0 \ | ||||||
|     ROCKET_PORT=80 |     ROCKET_PORT=80 | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
| 
 | 
 | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apt-get update && apt-get install -y \ |     && apt-get update && apt-get install -y \ | ||||||
|     --no-install-recommends \ |     --no-install-recommends \ | ||||||
|     openssl \ |  | ||||||
|     ca-certificates \ |     ca-certificates \ | ||||||
|     curl \ |     curl \ | ||||||
|     libmariadb-dev-compat \ |     libmariadb-dev-compat \ | ||||||
|     libpq5 \ |     libpq5 \ | ||||||
|  |     openssl \ | ||||||
|     && apt-get clean \ |     && apt-get clean \ | ||||||
|     && rm -rf /var/lib/apt/lists/* |     && rm -rf /var/lib/apt/lists/* | ||||||
| 
 | 
 | ||||||
| # In the Balena Bullseye images for armv6/rpi-debian there is a missing symlink. | # In the Balena Bullseye images for armv6/rpi-debian there is a missing symlink. | ||||||
| # This symlink was there in the buster images, and for some reason this is needed. | # This symlink was there in the buster images, and for some reason this is needed. | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN ln -v -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3 | RUN ln -v -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3 | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
| 
 | 
 | ||||||
| VOLUME /data | VOLUME /data | ||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM blackdex/rust-musl:arm-musleabi-stable-1.66.1 as build | FROM blackdex/rust-musl:arm-musleabi-stable-1.66.1 as build | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,7 +37,6 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| @@ -77,9 +74,14 @@ RUN touch src/main.rs | |||||||
| 
 | 
 | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=arm-unknown-linux-musleabi | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=arm-unknown-linux-musleabi | ||||||
| 
 | 
 | ||||||
|  | # Add the `cap_net_bind_service` capability to allow listening on | ||||||
|  | # privileged (< 1024) ports even when running as a non-root user. | ||||||
|  | # This is only done if building with BuildKit; with the legacy | ||||||
|  | # builder, the `COPY` instruction doesn't carry over capabilities. | ||||||
|  | RUN setcap cap_net_bind_service=+ep target/arm-unknown-linux-musleabi/release/vaultwarden | ||||||
|  | 
 | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -91,18 +93,16 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     SSL_CERT_DIR=/etc/ssl/certs |     SSL_CERT_DIR=/etc/ssl/certs | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
| 
 | 
 | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apk add --no-cache \ |     && apk add --no-cache \ | ||||||
|         openssl \ |         ca-certificates \ | ||||||
|         tzdata \ |  | ||||||
|         curl \ |         curl \ | ||||||
|         ca-certificates |         openssl \ | ||||||
|  |         tzdata | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
| 
 | 
 | ||||||
| VOLUME /data | VOLUME /data | ||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM rust:1.66-bullseye as build | FROM rust:1.66-bullseye as build | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,26 +37,24 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN mkdir -pv "${CARGO_HOME}" \ | RUN mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
|  |  | ||||||
| # | # Install build dependencies for the armhf architecture | ||||||
| # Install required build libs for armhf architecture. |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN dpkg --add-architecture armhf \ | RUN dpkg --add-architecture armhf \ | ||||||
|     && apt-get update \ |     && apt-get update \ | ||||||
|     && apt-get install -y \ |     && apt-get install -y \ | ||||||
|         --no-install-recommends \ |         --no-install-recommends \ | ||||||
|         libssl-dev:armhf \ |         gcc-arm-linux-gnueabihf \ | ||||||
|         libc6-dev:armhf \ |         libc6-dev:armhf \ | ||||||
|         libpq5:armhf \ |         libcap2-bin \ | ||||||
|         libpq-dev:armhf \ |  | ||||||
|         libmariadb3:armhf \ |  | ||||||
|         libmariadb-dev:armhf \ |         libmariadb-dev:armhf \ | ||||||
|         libmariadb-dev-compat:armhf \ |         libmariadb-dev-compat:armhf \ | ||||||
|         gcc-arm-linux-gnueabihf \ |         libmariadb3:armhf \ | ||||||
|  |         libpq-dev:armhf \ | ||||||
|  |         libpq5:armhf \ | ||||||
|  |         libssl-dev:armhf \ | ||||||
|     # |     # | ||||||
|     # Make sure cargo has the right target config |     # Make sure cargo has the right target config | ||||||
|     && echo '[target.armv7-unknown-linux-gnueabihf]' >> "${CARGO_HOME}/config" \ |     && echo '[target.armv7-unknown-linux-gnueabihf]' >> "${CARGO_HOME}/config" \ | ||||||
| @@ -71,7 +67,6 @@ ENV CC_armv7_unknown_linux_gnueabihf="/usr/bin/arm-linux-gnueabihf-gcc" \ | |||||||
|     OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabihf" \ |     OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabihf" \ | ||||||
|     OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabihf" |     OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabihf" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Creates a dummy project used to grab dependencies | # Creates a dummy project used to grab dependencies | ||||||
| RUN USER=root cargo new --bin /app | RUN USER=root cargo new --bin /app | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
| @@ -101,9 +96,9 @@ RUN touch src/main.rs | |||||||
|  |  | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-gnueabihf | RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-gnueabihf | ||||||
|  |  | ||||||
|  |  | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -113,22 +108,20 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     ROCKET_ADDRESS=0.0.0.0 \ |     ROCKET_ADDRESS=0.0.0.0 \ | ||||||
|     ROCKET_PORT=80 |     ROCKET_PORT=80 | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
|  |  | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apt-get update && apt-get install -y \ |     && apt-get update && apt-get install -y \ | ||||||
|     --no-install-recommends \ |     --no-install-recommends \ | ||||||
|     openssl \ |  | ||||||
|     ca-certificates \ |     ca-certificates \ | ||||||
|     curl \ |     curl \ | ||||||
|     libmariadb-dev-compat \ |     libmariadb-dev-compat \ | ||||||
|     libpq5 \ |     libpq5 \ | ||||||
|  |     openssl \ | ||||||
|     && apt-get clean \ |     && apt-get clean \ | ||||||
|     && rm -rf /var/lib/apt/lists/* |     && rm -rf /var/lib/apt/lists/* | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
|  |  | ||||||
| VOLUME /data | VOLUME /data | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM blackdex/rust-musl:armv7-musleabihf-stable-1.66.1 as build | FROM blackdex/rust-musl:armv7-musleabihf-stable-1.66.1 as build | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,7 +37,6 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN mkdir -pv "${CARGO_HOME}" \ | RUN mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| @@ -75,9 +72,9 @@ RUN touch src/main.rs | |||||||
|  |  | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-musleabihf | RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-musleabihf | ||||||
|  |  | ||||||
|  |  | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -89,18 +86,16 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     SSL_CERT_DIR=/etc/ssl/certs |     SSL_CERT_DIR=/etc/ssl/certs | ||||||
|  |  | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
|  |  | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apk add --no-cache \ |     && apk add --no-cache \ | ||||||
|         openssl \ |         ca-certificates \ | ||||||
|         tzdata \ |  | ||||||
|         curl \ |         curl \ | ||||||
|         ca-certificates |         openssl \ | ||||||
|  |         tzdata | ||||||
|  |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
|  |  | ||||||
| VOLUME /data | VOLUME /data | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM rust:1.66-bullseye as build | FROM rust:1.66-bullseye as build | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,26 +37,24 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| 
 | 
 | ||||||
| # | # Install build dependencies for the armhf architecture | ||||||
| # Install required build libs for armhf architecture. |  | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN dpkg --add-architecture armhf \ | RUN dpkg --add-architecture armhf \ | ||||||
|     && apt-get update \ |     && apt-get update \ | ||||||
|     && apt-get install -y \ |     && apt-get install -y \ | ||||||
|         --no-install-recommends \ |         --no-install-recommends \ | ||||||
|         libssl-dev:armhf \ |         gcc-arm-linux-gnueabihf \ | ||||||
|         libc6-dev:armhf \ |         libc6-dev:armhf \ | ||||||
|         libpq5:armhf \ |         libcap2-bin \ | ||||||
|         libpq-dev:armhf \ |  | ||||||
|         libmariadb3:armhf \ |  | ||||||
|         libmariadb-dev:armhf \ |         libmariadb-dev:armhf \ | ||||||
|         libmariadb-dev-compat:armhf \ |         libmariadb-dev-compat:armhf \ | ||||||
|         gcc-arm-linux-gnueabihf \ |         libmariadb3:armhf \ | ||||||
|  |         libpq-dev:armhf \ | ||||||
|  |         libpq5:armhf \ | ||||||
|  |         libssl-dev:armhf \ | ||||||
|     # |     # | ||||||
|     # Make sure cargo has the right target config |     # Make sure cargo has the right target config | ||||||
|     && echo '[target.armv7-unknown-linux-gnueabihf]' >> "${CARGO_HOME}/config" \ |     && echo '[target.armv7-unknown-linux-gnueabihf]' >> "${CARGO_HOME}/config" \ | ||||||
| @@ -71,7 +67,6 @@ ENV CC_armv7_unknown_linux_gnueabihf="/usr/bin/arm-linux-gnueabihf-gcc" \ | |||||||
|     OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabihf" \ |     OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabihf" \ | ||||||
|     OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabihf" |     OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabihf" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Creates a dummy project used to grab dependencies | # Creates a dummy project used to grab dependencies | ||||||
| RUN USER=root cargo new --bin /app | RUN USER=root cargo new --bin /app | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
| @@ -101,9 +96,14 @@ RUN touch src/main.rs | |||||||
| 
 | 
 | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=armv7-unknown-linux-gnueabihf | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=armv7-unknown-linux-gnueabihf | ||||||
| 
 | 
 | ||||||
|  | # Add the `cap_net_bind_service` capability to allow listening on | ||||||
|  | # privileged (< 1024) ports even when running as a non-root user. | ||||||
|  | # This is only done if building with BuildKit; with the legacy | ||||||
|  | # builder, the `COPY` instruction doesn't carry over capabilities. | ||||||
|  | RUN setcap cap_net_bind_service=+ep target/armv7-unknown-linux-gnueabihf/release/vaultwarden | ||||||
|  | 
 | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -113,22 +113,20 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     ROCKET_ADDRESS=0.0.0.0 \ |     ROCKET_ADDRESS=0.0.0.0 \ | ||||||
|     ROCKET_PORT=80 |     ROCKET_PORT=80 | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
| 
 | 
 | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apt-get update && apt-get install -y \ |     && apt-get update && apt-get install -y \ | ||||||
|     --no-install-recommends \ |     --no-install-recommends \ | ||||||
|     openssl \ |  | ||||||
|     ca-certificates \ |     ca-certificates \ | ||||||
|     curl \ |     curl \ | ||||||
|     libmariadb-dev-compat \ |     libmariadb-dev-compat \ | ||||||
|     libpq5 \ |     libpq5 \ | ||||||
|  |     openssl \ | ||||||
|     && apt-get clean \ |     && apt-get clean \ | ||||||
|     && rm -rf /var/lib/apt/lists/* |     && rm -rf /var/lib/apt/lists/* | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
| 
 | 
 | ||||||
| VOLUME /data | VOLUME /data | ||||||
| @@ -29,8 +29,6 @@ FROM vaultwarden/web-vault@sha256:d5f71fb05c4b87935bf51d84140db0f8716cabfe2974fb | |||||||
| ########################## BUILD IMAGE  ########################## | ########################## BUILD IMAGE  ########################## | ||||||
| FROM blackdex/rust-musl:armv7-musleabihf-stable-1.66.1 as build | FROM blackdex/rust-musl:armv7-musleabihf-stable-1.66.1 as build | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Build time options to avoid dpkg warnings and help with reproducible builds. | # Build time options to avoid dpkg warnings and help with reproducible builds. | ||||||
| ENV DEBIAN_FRONTEND=noninteractive \ | ENV DEBIAN_FRONTEND=noninteractive \ | ||||||
|     LANG=C.UTF-8 \ |     LANG=C.UTF-8 \ | ||||||
| @@ -39,7 +37,6 @@ ENV DEBIAN_FRONTEND=noninteractive \ | |||||||
|     CARGO_HOME="/root/.cargo" \ |     CARGO_HOME="/root/.cargo" \ | ||||||
|     USER="root" |     USER="root" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Create CARGO_HOME folder and don't download rust docs | # Create CARGO_HOME folder and don't download rust docs | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ | ||||||
|     && rustup set profile minimal |     && rustup set profile minimal | ||||||
| @@ -75,9 +72,14 @@ RUN touch src/main.rs | |||||||
| 
 | 
 | ||||||
| # Builds again, this time it'll just be | # Builds again, this time it'll just be | ||||||
| # your actual source files being built | # your actual source files being built | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=armv7-unknown-linux-musleabihf | RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=armv7-unknown-linux-musleabihf | ||||||
| 
 | 
 | ||||||
|  | # Add the `cap_net_bind_service` capability to allow listening on | ||||||
|  | # privileged (< 1024) ports even when running as a non-root user. | ||||||
|  | # This is only done if building with BuildKit; with the legacy | ||||||
|  | # builder, the `COPY` instruction doesn't carry over capabilities. | ||||||
|  | RUN setcap cap_net_bind_service=+ep target/armv7-unknown-linux-musleabihf/release/vaultwarden | ||||||
|  | 
 | ||||||
| ######################## RUNTIME IMAGE  ######################## | ######################## RUNTIME IMAGE  ######################## | ||||||
| # Create a new stage with a minimal image | # Create a new stage with a minimal image | ||||||
| # because we already have a binary built | # because we already have a binary built | ||||||
| @@ -89,18 +91,16 @@ ENV ROCKET_PROFILE="release" \ | |||||||
|     SSL_CERT_DIR=/etc/ssl/certs |     SSL_CERT_DIR=/etc/ssl/certs | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-start" ] | RUN [ "cross-build-start" ] | ||||||
| 
 | 
 | ||||||
| # Create data folder and Install needed libraries | # Create data folder and Install needed libraries | ||||||
| RUN mkdir /data \ | RUN mkdir /data \ | ||||||
|     && apk add --no-cache \ |     && apk add --no-cache \ | ||||||
|         openssl \ |         ca-certificates \ | ||||||
|         tzdata \ |  | ||||||
|         curl \ |         curl \ | ||||||
|         ca-certificates |         openssl \ | ||||||
|  |         tzdata | ||||||
| 
 | 
 | ||||||
| # hadolint ignore=DL3059 |  | ||||||
| RUN [ "cross-build-end" ] | RUN [ "cross-build-end" ] | ||||||
| 
 | 
 | ||||||
| VOLUME /data | VOLUME /data | ||||||
| @@ -23,7 +23,7 @@ LABELS=( | |||||||
|     # https://github.com/opencontainers/image-spec/blob/master/annotations.md |     # https://github.com/opencontainers/image-spec/blob/master/annotations.md | ||||||
|     org.opencontainers.image.created="$(date --utc --iso-8601=seconds)" |     org.opencontainers.image.created="$(date --utc --iso-8601=seconds)" | ||||||
|     org.opencontainers.image.documentation="https://github.com/dani-garcia/vaultwarden/wiki" |     org.opencontainers.image.documentation="https://github.com/dani-garcia/vaultwarden/wiki" | ||||||
|     org.opencontainers.image.licenses="GPL-3.0-only" |     org.opencontainers.image.licenses="AGPL-3.0-only" | ||||||
|     org.opencontainers.image.revision="${SOURCE_COMMIT}" |     org.opencontainers.image.revision="${SOURCE_COMMIT}" | ||||||
|     org.opencontainers.image.source="${SOURCE_REPOSITORY_URL}" |     org.opencontainers.image.source="${SOURCE_REPOSITORY_URL}" | ||||||
|     org.opencontainers.image.url="https://hub.docker.com/r/${DOCKER_REPO#*/}" |     org.opencontainers.image.url="https://hub.docker.com/r/${DOCKER_REPO#*/}" | ||||||
| @@ -34,9 +34,9 @@ for label in "${LABELS[@]}"; do | |||||||
|     LABEL_ARGS+=(--label "${label}") |     LABEL_ARGS+=(--label "${label}") | ||||||
| done | done | ||||||
|  |  | ||||||
| # Check if DOCKER_BUILDKIT is set, if so, use the Dockerfile.buildx as template | # Check if DOCKER_BUILDKIT is set, if so, use the Dockerfile.buildkit as template | ||||||
| if [[ -n "${DOCKER_BUILDKIT}" ]]; then | if [[ -n "${DOCKER_BUILDKIT}" ]]; then | ||||||
|     buildx_suffix=.buildx |     buildkit_suffix=.buildkit | ||||||
| fi | fi | ||||||
|  |  | ||||||
| set -ex | set -ex | ||||||
| @@ -45,6 +45,6 @@ for arch in "${arches[@]}"; do | |||||||
|     docker build \ |     docker build \ | ||||||
|            "${LABEL_ARGS[@]}" \ |            "${LABEL_ARGS[@]}" \ | ||||||
|            -t "${DOCKER_REPO}:${DOCKER_TAG}-${arch}" \ |            -t "${DOCKER_REPO}:${DOCKER_TAG}-${arch}" \ | ||||||
|            -f docker/${arch}/Dockerfile${buildx_suffix}${distro_suffix} \ |            -f docker/${arch}/Dockerfile${buildkit_suffix}${distro_suffix} \ | ||||||
|            . |            . | ||||||
| done | done | ||||||
|   | |||||||
| @@ -0,0 +1,2 @@ | |||||||
|  | ALTER TABLE users_organizations | ||||||
|  | ADD COLUMN reset_password_key TEXT; | ||||||
| @@ -0,0 +1,2 @@ | |||||||
|  | ALTER TABLE users_organizations | ||||||
|  | ADD COLUMN reset_password_key TEXT; | ||||||
| @@ -0,0 +1,2 @@ | |||||||
|  | ALTER TABLE users_organizations | ||||||
|  | ADD COLUMN reset_password_key TEXT; | ||||||
| @@ -123,7 +123,9 @@ async fn post_emergency_access( | |||||||
|  |  | ||||||
|     emergency_access.atype = new_type; |     emergency_access.atype = new_type; | ||||||
|     emergency_access.wait_time_days = data.WaitTimeDays; |     emergency_access.wait_time_days = data.WaitTimeDays; | ||||||
|     emergency_access.key_encrypted = data.KeyEncrypted; |     if data.KeyEncrypted.is_some() { | ||||||
|  |         emergency_access.key_encrypted = data.KeyEncrypted; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     emergency_access.save(&mut conn).await?; |     emergency_access.save(&mut conn).await?; | ||||||
|     Ok(Json(emergency_access.to_json())) |     Ok(Json(emergency_access.to_json())) | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ pub fn routes() -> Vec<Route> { | |||||||
|         get_plans_tax_rates, |         get_plans_tax_rates, | ||||||
|         import, |         import, | ||||||
|         post_org_keys, |         post_org_keys, | ||||||
|  |         get_organization_keys, | ||||||
|         bulk_public_keys, |         bulk_public_keys, | ||||||
|         deactivate_organization_user, |         deactivate_organization_user, | ||||||
|         bulk_deactivate_organization_user, |         bulk_deactivate_organization_user, | ||||||
| @@ -86,6 +87,9 @@ pub fn routes() -> Vec<Route> { | |||||||
|         put_user_groups, |         put_user_groups, | ||||||
|         delete_group_user, |         delete_group_user, | ||||||
|         post_delete_group_user, |         post_delete_group_user, | ||||||
|  |         put_reset_password_enrollment, | ||||||
|  |         get_reset_password_details, | ||||||
|  |         put_reset_password, | ||||||
|         get_org_export |         get_org_export | ||||||
|     ] |     ] | ||||||
| } | } | ||||||
| @@ -882,6 +886,7 @@ async fn _reinvite_user(org_id: &str, user_org: &str, invited_by_email: &str, co | |||||||
| #[allow(non_snake_case)] | #[allow(non_snake_case)] | ||||||
| struct AcceptData { | struct AcceptData { | ||||||
|     Token: String, |     Token: String, | ||||||
|  |     ResetPasswordKey: Option<String>, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[post("/organizations/<org_id>/users/<_org_user_id>/accept", data = "<data>")] | #[post("/organizations/<org_id>/users/<_org_user_id>/accept", data = "<data>")] | ||||||
| @@ -909,6 +914,11 @@ async fn accept_invite( | |||||||
|                     err!("User already accepted the invitation") |                     err!("User already accepted the invitation") | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |                 let master_password_required = OrgPolicy::org_is_reset_password_auto_enroll(org, &mut conn).await; | ||||||
|  |                 if data.ResetPasswordKey.is_none() && master_password_required { | ||||||
|  |                     err!("Reset password key is required, but not provided."); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 // This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type |                 // This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type | ||||||
|                 // It returns different error messages per function. |                 // It returns different error messages per function. | ||||||
|                 if user_org.atype < UserOrgType::Admin { |                 if user_org.atype < UserOrgType::Admin { | ||||||
| @@ -924,6 +934,11 @@ async fn accept_invite( | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 user_org.status = UserOrgStatus::Accepted as i32; |                 user_org.status = UserOrgStatus::Accepted as i32; | ||||||
|  |  | ||||||
|  |                 if master_password_required { | ||||||
|  |                     user_org.reset_password_key = data.ResetPasswordKey; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 user_org.save(&mut conn).await?; |                 user_org.save(&mut conn).await?; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -2460,6 +2475,204 @@ async fn delete_group_user( | |||||||
|     GroupUser::delete_by_group_id_and_user_id(&group_id, &org_user_id, &mut conn).await |     GroupUser::delete_by_group_id_and_user_id(&group_id, &org_user_id, &mut conn).await | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Deserialize)] | ||||||
|  | #[allow(non_snake_case)] | ||||||
|  | struct OrganizationUserResetPasswordEnrollmentRequest { | ||||||
|  |     ResetPasswordKey: Option<String>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Deserialize)] | ||||||
|  | #[allow(non_snake_case)] | ||||||
|  | struct OrganizationUserResetPasswordRequest { | ||||||
|  |     NewMasterPasswordHash: String, | ||||||
|  |     Key: String, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[get("/organizations/<org_id>/keys")] | ||||||
|  | async fn get_organization_keys(org_id: String, mut conn: DbConn) -> JsonResult { | ||||||
|  |     let org = match Organization::find_by_uuid(&org_id, &mut conn).await { | ||||||
|  |         Some(organization) => organization, | ||||||
|  |         None => err!("Organization not found"), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     Ok(Json(json!({ | ||||||
|  |         "Object": "organizationKeys", | ||||||
|  |         "PublicKey": org.public_key, | ||||||
|  |         "PrivateKey": org.private_key, | ||||||
|  |     }))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[put("/organizations/<org_id>/users/<org_user_id>/reset-password", data = "<data>")] | ||||||
|  | async fn put_reset_password( | ||||||
|  |     org_id: String, | ||||||
|  |     org_user_id: String, | ||||||
|  |     headers: AdminHeaders, | ||||||
|  |     data: JsonUpcase<OrganizationUserResetPasswordRequest>, | ||||||
|  |     mut conn: DbConn, | ||||||
|  |     ip: ClientIp, | ||||||
|  |     nt: Notify<'_>, | ||||||
|  | ) -> EmptyResult { | ||||||
|  |     let org = match Organization::find_by_uuid(&org_id, &mut conn).await { | ||||||
|  |         Some(org) => org, | ||||||
|  |         None => err!("Required organization not found"), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     let org_user = match UserOrganization::find_by_uuid_and_org(&org_user_id, &org.uuid, &mut conn).await { | ||||||
|  |         Some(user) => user, | ||||||
|  |         None => err!("User to reset isn't member of required organization"), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     let mut user = match User::find_by_uuid(&org_user.user_uuid, &mut conn).await { | ||||||
|  |         Some(user) => user, | ||||||
|  |         None => err!("User not found"), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     check_reset_password_applicable_and_permissions(&org_id, &org_user_id, &headers, &mut conn).await?; | ||||||
|  |  | ||||||
|  |     if org_user.reset_password_key.is_none() { | ||||||
|  |         err!("Password reset not or not correctly enrolled"); | ||||||
|  |     } | ||||||
|  |     if org_user.status != (UserOrgStatus::Confirmed as i32) { | ||||||
|  |         err!("Organization user must be confirmed for password reset functionality"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Sending email before resetting password to ensure working email configuration and the resulting | ||||||
|  |     // user notification. Also this might add some protection against security flaws and misuse | ||||||
|  |     if let Err(e) = mail::send_admin_reset_password(&user.email, &user.name, &org.name).await { | ||||||
|  |         error!("Error sending user reset password email: {:#?}", e); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let reset_request = data.into_inner().data; | ||||||
|  |  | ||||||
|  |     user.set_password(reset_request.NewMasterPasswordHash.as_str(), Some(reset_request.Key), true, None); | ||||||
|  |     user.save(&mut conn).await?; | ||||||
|  |  | ||||||
|  |     nt.send_logout(&user, None).await; | ||||||
|  |  | ||||||
|  |     log_event( | ||||||
|  |         EventType::OrganizationUserAdminResetPassword as i32, | ||||||
|  |         &org_user_id, | ||||||
|  |         org.uuid.clone(), | ||||||
|  |         headers.user.uuid.clone(), | ||||||
|  |         headers.device.atype, | ||||||
|  |         &ip.ip, | ||||||
|  |         &mut conn, | ||||||
|  |     ) | ||||||
|  |     .await; | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[get("/organizations/<org_id>/users/<org_user_id>/reset-password-details")] | ||||||
|  | async fn get_reset_password_details( | ||||||
|  |     org_id: String, | ||||||
|  |     org_user_id: String, | ||||||
|  |     headers: AdminHeaders, | ||||||
|  |     mut conn: DbConn, | ||||||
|  | ) -> JsonResult { | ||||||
|  |     let org = match Organization::find_by_uuid(&org_id, &mut conn).await { | ||||||
|  |         Some(org) => org, | ||||||
|  |         None => err!("Required organization not found"), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     let org_user = match UserOrganization::find_by_uuid_and_org(&org_user_id, &org_id, &mut conn).await { | ||||||
|  |         Some(user) => user, | ||||||
|  |         None => err!("User to reset isn't member of required organization"), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     let user = match User::find_by_uuid(&org_user.user_uuid, &mut conn).await { | ||||||
|  |         Some(user) => user, | ||||||
|  |         None => err!("User not found"), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     check_reset_password_applicable_and_permissions(&org_id, &org_user_id, &headers, &mut conn).await?; | ||||||
|  |  | ||||||
|  |     Ok(Json(json!({ | ||||||
|  |         "Object": "organizationUserResetPasswordDetails", | ||||||
|  |         "Kdf":user.client_kdf_type, | ||||||
|  |         "KdfIterations":user.client_kdf_iter, | ||||||
|  |         "ResetPasswordKey":org_user.reset_password_key, | ||||||
|  |         "EncryptedPrivateKey":org.private_key , | ||||||
|  |  | ||||||
|  |     }))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async fn check_reset_password_applicable_and_permissions( | ||||||
|  |     org_id: &str, | ||||||
|  |     org_user_id: &str, | ||||||
|  |     headers: &AdminHeaders, | ||||||
|  |     conn: &mut DbConn, | ||||||
|  | ) -> EmptyResult { | ||||||
|  |     check_reset_password_applicable(org_id, conn).await?; | ||||||
|  |  | ||||||
|  |     let target_user = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { | ||||||
|  |         Some(user) => user, | ||||||
|  |         None => err!("Reset target user not found"), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     // Resetting user must be higher/equal to user to reset | ||||||
|  |     match headers.org_user_type { | ||||||
|  |         UserOrgType::Owner => Ok(()), | ||||||
|  |         UserOrgType::Admin if target_user.atype <= UserOrgType::Admin => Ok(()), | ||||||
|  |         _ => err!("No permission to reset this user's password"), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async fn check_reset_password_applicable(org_id: &str, conn: &mut DbConn) -> EmptyResult { | ||||||
|  |     if !CONFIG.mail_enabled() { | ||||||
|  |         err!("Password reset is not supported on an email-disabled instance."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let policy = match OrgPolicy::find_by_org_and_type(org_id, OrgPolicyType::ResetPassword, conn).await { | ||||||
|  |         Some(p) => p, | ||||||
|  |         None => err!("Policy not found"), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     if !policy.enabled { | ||||||
|  |         err!("Reset password policy not enabled"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[put("/organizations/<org_id>/users/<org_user_id>/reset-password-enrollment", data = "<data>")] | ||||||
|  | async fn put_reset_password_enrollment( | ||||||
|  |     org_id: String, | ||||||
|  |     org_user_id: String, | ||||||
|  |     headers: Headers, | ||||||
|  |     data: JsonUpcase<OrganizationUserResetPasswordEnrollmentRequest>, | ||||||
|  |     mut conn: DbConn, | ||||||
|  |     ip: ClientIp, | ||||||
|  | ) -> EmptyResult { | ||||||
|  |     let mut org_user = match UserOrganization::find_by_user_and_org(&headers.user.uuid, &org_id, &mut conn).await { | ||||||
|  |         Some(u) => u, | ||||||
|  |         None => err!("User to enroll isn't member of required organization"), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     check_reset_password_applicable(&org_id, &mut conn).await?; | ||||||
|  |  | ||||||
|  |     let reset_request = data.into_inner().data; | ||||||
|  |  | ||||||
|  |     if reset_request.ResetPasswordKey.is_none() | ||||||
|  |         && OrgPolicy::org_is_reset_password_auto_enroll(&org_id, &mut conn).await | ||||||
|  |     { | ||||||
|  |         err!("Reset password can't be withdrawed due to an enterprise policy"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     org_user.reset_password_key = reset_request.ResetPasswordKey; | ||||||
|  |     org_user.save(&mut conn).await?; | ||||||
|  |  | ||||||
|  |     let log_id = if org_user.reset_password_key.is_some() { | ||||||
|  |         EventType::OrganizationUserResetPasswordEnroll as i32 | ||||||
|  |     } else { | ||||||
|  |         EventType::OrganizationUserResetPasswordWithdraw as i32 | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     log_event(log_id, &org_user_id, org_id, headers.user.uuid.clone(), headers.device.atype, &ip.ip, &mut conn).await; | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
| // This is a new function active since the v2022.9.x clients. | // This is a new function active since the v2022.9.x clients. | ||||||
| // It combines the previous two calls done before. | // It combines the previous two calls done before. | ||||||
| // We call those two functions here and combine them our selfs. | // We call those two functions here and combine them our selfs. | ||||||
|   | |||||||
| @@ -1138,6 +1138,7 @@ where | |||||||
|     reg!("email/email_footer"); |     reg!("email/email_footer"); | ||||||
|     reg!("email/email_footer_text"); |     reg!("email/email_footer_text"); | ||||||
|  |  | ||||||
|  |     reg!("email/admin_reset_password", ".html"); | ||||||
|     reg!("email/change_email", ".html"); |     reg!("email/change_email", ".html"); | ||||||
|     reg!("email/delete_account", ".html"); |     reg!("email/delete_account", ".html"); | ||||||
|     reg!("email/emergency_access_invite_accepted", ".html"); |     reg!("email/emergency_access_invite_accepted", ".html"); | ||||||
|   | |||||||
| @@ -87,9 +87,9 @@ pub enum EventType { | |||||||
|     OrganizationUserRemoved = 1503, |     OrganizationUserRemoved = 1503, | ||||||
|     OrganizationUserUpdatedGroups = 1504, |     OrganizationUserUpdatedGroups = 1504, | ||||||
|     // OrganizationUserUnlinkedSso = 1505, // Not supported |     // OrganizationUserUnlinkedSso = 1505, // Not supported | ||||||
|     // OrganizationUserResetPasswordEnroll = 1506, // Not supported |     OrganizationUserResetPasswordEnroll = 1506, | ||||||
|     // OrganizationUserResetPasswordWithdraw = 1507, // Not supported |     OrganizationUserResetPasswordWithdraw = 1507, | ||||||
|     // OrganizationUserAdminResetPassword = 1508, // Not supported |     OrganizationUserAdminResetPassword = 1508, | ||||||
|     // OrganizationUserResetSsoLink = 1509, // Not supported |     // OrganizationUserResetSsoLink = 1509, // Not supported | ||||||
|     // OrganizationUserFirstSsoLogin = 1510, // Not supported |     // OrganizationUserFirstSsoLogin = 1510, // Not supported | ||||||
|     OrganizationUserRevoked = 1511, |     OrganizationUserRevoked = 1511, | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ pub enum OrgPolicyType { | |||||||
|     PersonalOwnership = 5, |     PersonalOwnership = 5, | ||||||
|     DisableSend = 6, |     DisableSend = 6, | ||||||
|     SendOptions = 7, |     SendOptions = 7, | ||||||
|     // ResetPassword = 8, // Not supported |     ResetPassword = 8, | ||||||
|     // MaximumVaultTimeout = 9, // Not supported (Not AGPLv3 Licensed) |     // MaximumVaultTimeout = 9, // Not supported (Not AGPLv3 Licensed) | ||||||
|     // DisablePersonalVaultExport = 10, // Not supported (Not AGPLv3 Licensed) |     // DisablePersonalVaultExport = 10, // Not supported (Not AGPLv3 Licensed) | ||||||
| } | } | ||||||
| @@ -44,6 +44,13 @@ pub struct SendOptionsPolicyData { | |||||||
|     pub DisableHideEmail: bool, |     pub DisableHideEmail: bool, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // https://github.com/bitwarden/server/blob/5cbdee137921a19b1f722920f0fa3cd45af2ef0f/src/Core/Models/Data/Organizations/Policies/ResetPasswordDataModel.cs | ||||||
|  | #[derive(Deserialize)] | ||||||
|  | #[allow(non_snake_case)] | ||||||
|  | pub struct ResetPasswordDataModel { | ||||||
|  |     pub AutoEnrollEnabled: bool, | ||||||
|  | } | ||||||
|  |  | ||||||
| pub type OrgPolicyResult = Result<(), OrgPolicyErr>; | pub type OrgPolicyResult = Result<(), OrgPolicyErr>; | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| @@ -298,6 +305,20 @@ impl OrgPolicy { | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub async fn org_is_reset_password_auto_enroll(org_uuid: &str, conn: &mut DbConn) -> bool { | ||||||
|  |         match OrgPolicy::find_by_org_and_type(org_uuid, OrgPolicyType::ResetPassword, conn).await { | ||||||
|  |             Some(policy) => match serde_json::from_str::<UpCase<ResetPasswordDataModel>>(&policy.data) { | ||||||
|  |                 Ok(opts) => { | ||||||
|  |                     return opts.data.AutoEnrollEnabled; | ||||||
|  |                 } | ||||||
|  |                 _ => error!("Failed to deserialize ResetPasswordDataModel: {}", policy.data), | ||||||
|  |             }, | ||||||
|  |             None => return false, | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         false | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Returns true if the user belongs to an org that has enabled the `DisableHideEmail` |     /// Returns true if the user belongs to an org that has enabled the `DisableHideEmail` | ||||||
|     /// option of the `Send Options` policy, and the user is not an owner or admin of that org. |     /// option of the `Send Options` policy, and the user is not an owner or admin of that org. | ||||||
|     pub async fn is_hide_email_disabled(user_uuid: &str, conn: &mut DbConn) -> bool { |     pub async fn is_hide_email_disabled(user_uuid: &str, conn: &mut DbConn) -> bool { | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ db_object! { | |||||||
|         pub akey: String, |         pub akey: String, | ||||||
|         pub status: i32, |         pub status: i32, | ||||||
|         pub atype: i32, |         pub atype: i32, | ||||||
|  |         pub reset_password_key: Option<String>, | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -158,7 +159,7 @@ impl Organization { | |||||||
|             "SelfHost": true, |             "SelfHost": true, | ||||||
|             "UseApi": false, // Not supported |             "UseApi": false, // Not supported | ||||||
|             "HasPublicAndPrivateKeys": self.private_key.is_some() && self.public_key.is_some(), |             "HasPublicAndPrivateKeys": self.private_key.is_some() && self.public_key.is_some(), | ||||||
|             "UseResetPassword": false, // Not supported |             "UseResetPassword": CONFIG.mail_enabled(), | ||||||
|  |  | ||||||
|             "BusinessName": null, |             "BusinessName": null, | ||||||
|             "BusinessAddress1": null, |             "BusinessAddress1": null, | ||||||
| @@ -194,6 +195,7 @@ impl UserOrganization { | |||||||
|             akey: String::new(), |             akey: String::new(), | ||||||
|             status: UserOrgStatus::Accepted as i32, |             status: UserOrgStatus::Accepted as i32, | ||||||
|             atype: UserOrgType::User as i32, |             atype: UserOrgType::User as i32, | ||||||
|  |             reset_password_key: None, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -311,7 +313,8 @@ impl UserOrganization { | |||||||
|             "UseApi": false, // Not supported |             "UseApi": false, // Not supported | ||||||
|             "SelfHost": true, |             "SelfHost": true, | ||||||
|             "HasPublicAndPrivateKeys": org.private_key.is_some() && org.public_key.is_some(), |             "HasPublicAndPrivateKeys": org.private_key.is_some() && org.public_key.is_some(), | ||||||
|             "ResetPasswordEnrolled": false, // Not supported |             "ResetPasswordEnrolled": self.reset_password_key.is_some(), | ||||||
|  |             "UseResetPassword": CONFIG.mail_enabled(), | ||||||
|             "SsoBound": false, // Not supported |             "SsoBound": false, // Not supported | ||||||
|             "UseSso": false, // Not supported |             "UseSso": false, // Not supported | ||||||
|             "ProviderId": null, |             "ProviderId": null, | ||||||
| @@ -377,6 +380,7 @@ impl UserOrganization { | |||||||
|             "Type": self.atype, |             "Type": self.atype, | ||||||
|             "AccessAll": self.access_all, |             "AccessAll": self.access_all, | ||||||
|             "TwoFactorEnabled": twofactor_enabled, |             "TwoFactorEnabled": twofactor_enabled, | ||||||
|  |             "ResetPasswordEnrolled":self.reset_password_key.is_some(), | ||||||
|  |  | ||||||
|             "Object": "organizationUserUserDetails", |             "Object": "organizationUserUserDetails", | ||||||
|         }) |         }) | ||||||
|   | |||||||
| @@ -222,6 +222,7 @@ table! { | |||||||
|         akey -> Text, |         akey -> Text, | ||||||
|         status -> Integer, |         status -> Integer, | ||||||
|         atype -> Integer, |         atype -> Integer, | ||||||
|  |         reset_password_key -> Nullable<Text>, | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -222,6 +222,7 @@ table! { | |||||||
|         akey -> Text, |         akey -> Text, | ||||||
|         status -> Integer, |         status -> Integer, | ||||||
|         atype -> Integer, |         atype -> Integer, | ||||||
|  |         reset_password_key -> Nullable<Text>, | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -222,6 +222,7 @@ table! { | |||||||
|         akey -> Text, |         akey -> Text, | ||||||
|         status -> Integer, |         status -> Integer, | ||||||
|         atype -> Integer, |         atype -> Integer, | ||||||
|  |         reset_password_key -> Nullable<Text>, | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								src/mail.rs
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/mail.rs
									
									
									
									
									
								
							| @@ -496,6 +496,19 @@ pub async fn send_test(address: &str) -> EmptyResult { | |||||||
|     send_email(address, &subject, body_html, body_text).await |     send_email(address, &subject, body_html, body_text).await | ||||||
| } | } | ||||||
|  |  | ||||||
|  | pub async fn send_admin_reset_password(address: &str, user_name: &str, org_name: &str) -> EmptyResult { | ||||||
|  |     let (subject, body_html, body_text) = get_text( | ||||||
|  |         "email/admin_reset_password", | ||||||
|  |         json!({ | ||||||
|  |             "url": CONFIG.domain(), | ||||||
|  |             "img_src": CONFIG._smtp_img_src(), | ||||||
|  |             "user_name": user_name, | ||||||
|  |             "org_name": org_name, | ||||||
|  |         }), | ||||||
|  |     )?; | ||||||
|  |     send_email(address, &subject, body_html, body_text).await | ||||||
|  | } | ||||||
|  |  | ||||||
| async fn send_email(address: &str, subject: &str, body_html: String, body_text: String) -> EmptyResult { | async fn send_email(address: &str, subject: &str, body_html: String, body_text: String) -> EmptyResult { | ||||||
|     let smtp_from = &CONFIG.smtp_from(); |     let smtp_from = &CONFIG.smtp_from(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -47,7 +47,7 @@ | |||||||
|                             <div class="row my-2 align-items-center pt-3 border-top" title="Send a test email to given email address"> |                             <div class="row my-2 align-items-center pt-3 border-top" title="Send a test email to given email address"> | ||||||
|                                 <label for="smtp-test-email" class="col-sm-3 col-form-label">Test SMTP</label> |                                 <label for="smtp-test-email" class="col-sm-3 col-form-label">Test SMTP</label> | ||||||
|                                 <div class="col-sm-8 input-group"> |                                 <div class="col-sm-8 input-group"> | ||||||
|                                     <input class="form-control" id="smtp-test-email" type="email" placeholder="Enter test email" required> |                                     <input class="form-control" id="smtp-test-email" type="email" placeholder="Enter test email" required spellcheck="false"> | ||||||
|                                     <button type="button" class="btn btn-outline-primary input-group-text" id="smtpTest">Send test email</button> |                                     <button type="button" class="btn btn-outline-primary input-group-text" id="smtpTest">Send test email</button> | ||||||
|                                     <div class="invalid-tooltip">Please provide a valid email address</div> |                                     <div class="invalid-tooltip">Please provide a valid email address</div> | ||||||
|                                 </div> |                                 </div> | ||||||
| @@ -85,7 +85,7 @@ | |||||||
|                                     <input readonly class="form-control" id="input_{{name}}" type="password" value="{{value}}" {{#if default}} placeholder="Default: {{default}}" {{/if}}> |                                     <input readonly class="form-control" id="input_{{name}}" type="password" value="{{value}}" {{#if default}} placeholder="Default: {{default}}" {{/if}}> | ||||||
|                                     <button class="btn btn-outline-secondary" type="button" data-vw-pw-toggle="input_{{name}}">Show/hide</button> |                                     <button class="btn btn-outline-secondary" type="button" data-vw-pw-toggle="input_{{name}}">Show/hide</button> | ||||||
|                                 {{else}} |                                 {{else}} | ||||||
|                                     <input readonly class="form-control" id="input_{{name}}" type="{{type}}" value="{{value}}" {{#if default}} placeholder="Default: {{default}}" {{/if}}> |                                     <input readonly class="form-control" id="input_{{name}}" type="{{type}}" value="{{value}}" {{#if default}} placeholder="Default: {{default}}" {{/if}} spellcheck="false"> | ||||||
|                                     {{#case type "password"}} |                                     {{#case type "password"}} | ||||||
|                                     <button class="btn btn-outline-secondary" type="button" data-vw-pw-toggle="input_{{name}}">Show/hide</button> |                                     <button class="btn btn-outline-secondary" type="button" data-vw-pw-toggle="input_{{name}}">Show/hide</button> | ||||||
|                                     {{/case}} |                                     {{/case}} | ||||||
|   | |||||||
| @@ -96,7 +96,7 @@ | |||||||
|             <small>Email:</small> |             <small>Email:</small> | ||||||
|  |  | ||||||
|             <form class="form-inline input-group w-50" id="inviteUserForm"> |             <form class="form-inline input-group w-50" id="inviteUserForm"> | ||||||
|                 <input type="email" class="form-control me-2" id="inviteEmail" placeholder="Enter email" required> |                 <input type="email" class="form-control me-2" id="inviteEmail" placeholder="Enter email" required spellcheck="false"> | ||||||
|                 <button type="submit" class="btn btn-primary">Invite</button> |                 <button type="submit" class="btn btn-primary">Invite</button> | ||||||
|             </form> |             </form> | ||||||
|         </div> |         </div> | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								src/static/templates/email/admin_reset_password.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/static/templates/email/admin_reset_password.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | Master Password Has Been Changed | ||||||
|  | <!----------------> | ||||||
|  | The master password for {{user_name}} has been changed by an administrator in your {{org_name}} organization. If you did not initiate this request, please reach out to your administrator immediately. | ||||||
|  |  | ||||||
|  | === | ||||||
|  | Github: https://github.com/dani-garcia/vaultwarden | ||||||
							
								
								
									
										11
									
								
								src/static/templates/email/admin_reset_password.html.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/static/templates/email/admin_reset_password.html.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | Master Password Has Been Changed | ||||||
|  | <!----------------> | ||||||
|  | {{> email/email_header }} | ||||||
|  | <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> | ||||||
|  |     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> | ||||||
|  |         <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top"> | ||||||
|  |             The master password for <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{user_name}}</b> has been changed by an administrator in your <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{org_name}}</b> organization. If you did not initiate this request, please reach out to your administrator immediately. | ||||||
|  |         </td> | ||||||
|  |     </tr> | ||||||
|  | </table> | ||||||
|  | {{> email/email_footer }} | ||||||
		Reference in New Issue
	
	Block a user