mirror of
https://github.com/AGWA/git-crypt.git
synced 2026-01-06 10:05:47 -08:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ca8f89602 | ||
|
|
5fd36a7ac5 | ||
|
|
d5670c9552 | ||
|
|
2d2053296f | ||
|
|
216aa27009 | ||
|
|
02c52ab21a | ||
|
|
849401d733 | ||
|
|
12881f65fd | ||
|
|
280bd43ac7 | ||
|
|
b7c608da25 | ||
|
|
9cb1ad3c33 | ||
|
|
1b1715b5ec |
4
INSTALL
4
INSTALL
@@ -2,10 +2,8 @@ DEPENDENCIES
|
|||||||
|
|
||||||
To use git-crypt, you need:
|
To use git-crypt, you need:
|
||||||
|
|
||||||
* Git 1.6.0 or newer
|
* Git 1.7.2 or newer
|
||||||
* OpenSSL
|
* OpenSSL
|
||||||
* For decrypted git diff output, Git 1.6.1 or newer
|
|
||||||
* For decrypted git blame output, Git 1.7.2 or newer
|
|
||||||
|
|
||||||
To build git-crypt, you need a C++ compiler and OpenSSL development
|
To build git-crypt, you need a C++ compiler and OpenSSL development
|
||||||
headers.
|
headers.
|
||||||
|
|||||||
@@ -3,10 +3,8 @@ Dependencies
|
|||||||
|
|
||||||
To use git-crypt, you need:
|
To use git-crypt, you need:
|
||||||
|
|
||||||
* Git 1.6.0 or newer
|
* Git 1.7.2 or newer
|
||||||
* OpenSSL
|
* OpenSSL
|
||||||
* For decrypted git diff output, Git 1.6.1 or newer
|
|
||||||
* For decrypted git blame output, Git 1.7.2 or newer
|
|
||||||
|
|
||||||
To build git-crypt, you need a C++ compiler and OpenSSL development
|
To build git-crypt, you need a C++ compiler and OpenSSL development
|
||||||
headers.
|
headers.
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -25,7 +25,7 @@ util.o: util.cpp util-unix.cpp util-win32.cpp
|
|||||||
clean:
|
clean:
|
||||||
rm -f *.o git-crypt
|
rm -f *.o git-crypt
|
||||||
|
|
||||||
install:
|
install: git-crypt
|
||||||
install -m 755 git-crypt $(DESTDIR)$(PREFIX)/bin/
|
install -m 755 git-crypt $(DESTDIR)$(PREFIX)/bin/
|
||||||
|
|
||||||
.PHONY: all clean install
|
.PHONY: all clean install
|
||||||
|
|||||||
10
NEWS
10
NEWS
@@ -1,3 +1,13 @@
|
|||||||
|
v0.4.2 (2015-01-31)
|
||||||
|
* Fix unlock and lock under Git 2.2.2 and higher.
|
||||||
|
* Drop support for versions of Git older than 1.7.2.
|
||||||
|
* Minor improvements to some help/error messages.
|
||||||
|
|
||||||
|
v0.4.1 (2015-01-08)
|
||||||
|
* Important usability fix to ensure that the .git-crypt directory
|
||||||
|
can't be encrypted by accident (see RELEASE_NOTES-0.4.1.md for
|
||||||
|
more information).
|
||||||
|
|
||||||
v0.4 (2014-11-16)
|
v0.4 (2014-11-16)
|
||||||
(See RELEASE_NOTES-0.4.md for important details.)
|
(See RELEASE_NOTES-0.4.md for important details.)
|
||||||
* Add optional GPG support: GPG can be used to share the repository
|
* Add optional GPG support: GPG can be used to share the repository
|
||||||
|
|||||||
10
NEWS.md
10
NEWS.md
@@ -1,6 +1,16 @@
|
|||||||
News
|
News
|
||||||
====
|
====
|
||||||
|
|
||||||
|
######v0.4.2 (2015-01-31)
|
||||||
|
* Fix unlock and lock under Git 2.2.2 and higher.
|
||||||
|
* Drop support for versions of Git older than 1.7.2.
|
||||||
|
* Minor improvements to some help/error messages.
|
||||||
|
|
||||||
|
######v0.4.1 (2015-01-08)
|
||||||
|
* Important usability fix to ensure that the .git-crypt directory
|
||||||
|
can't be encrypted by accident (see
|
||||||
|
[the release notes](RELEASE_NOTES-0.4.1.md) for more information).
|
||||||
|
|
||||||
######v0.4 (2014-11-16)
|
######v0.4 (2014-11-16)
|
||||||
(See [the release notes](RELEASE_NOTES-0.4.md) for important details.)
|
(See [the release notes](RELEASE_NOTES-0.4.md) for important details.)
|
||||||
* Add optional GPG support: GPG can be used to share the repository
|
* Add optional GPG support: GPG can be used to share the repository
|
||||||
|
|||||||
6
README
6
README
@@ -66,7 +66,7 @@ encryption and decryption happen transparently.
|
|||||||
|
|
||||||
CURRENT STATUS
|
CURRENT STATUS
|
||||||
|
|
||||||
The latest version of git-crypt is 0.4, released on 2014-11-16.
|
The latest version of git-crypt is 0.4.2, released on 2015-01-31.
|
||||||
git-crypt aims to be bug-free and reliable, meaning it shouldn't
|
git-crypt aims to be bug-free and reliable, meaning it shouldn't
|
||||||
crash, malfunction, or expose your confidential data. However,
|
crash, malfunction, or expose your confidential data. However,
|
||||||
it has not yet reached maturity, meaning it is not as documented,
|
it has not yet reached maturity, meaning it is not as documented,
|
||||||
@@ -145,5 +145,5 @@ MAILING LISTS
|
|||||||
To stay abreast of, and provide input to, git-crypt development, consider
|
To stay abreast of, and provide input to, git-crypt development, consider
|
||||||
subscribing to one or both of our mailing lists:
|
subscribing to one or both of our mailing lists:
|
||||||
|
|
||||||
Announcements: http://lists.cloudmutt.com/mailman/listinfo/git-crypt-announce
|
Announcements: https://lists.cloudmutt.com/mailman/listinfo/git-crypt-announce
|
||||||
Discussion: http://lists.cloudmutt.com/mailman/listinfo/git-crypt-discuss
|
Discussion: https://lists.cloudmutt.com/mailman/listinfo/git-crypt-discuss
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ encryption and decryption happen transparently.
|
|||||||
Current Status
|
Current Status
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
The latest version of git-crypt is [0.4](RELEASE_NOTES-0.4.md), released on
|
The latest version of git-crypt is [0.4.2](NEWS.md), released on
|
||||||
2014-11-16. git-crypt aims to be bug-free and reliable, meaning it
|
2015-01-31. git-crypt aims to be bug-free and reliable, meaning it
|
||||||
shouldn't crash, malfunction, or expose your confidential data.
|
shouldn't crash, malfunction, or expose your confidential data.
|
||||||
However, it has not yet reached maturity, meaning it is not as
|
However, it has not yet reached maturity, meaning it is not as
|
||||||
documented, featureful, or easy-to-use as it should be. Additionally,
|
documented, featureful, or easy-to-use as it should be. Additionally,
|
||||||
@@ -147,5 +147,5 @@ Mailing Lists
|
|||||||
To stay abreast of, and provide input to, git-crypt development,
|
To stay abreast of, and provide input to, git-crypt development,
|
||||||
consider subscribing to one or both of our mailing lists:
|
consider subscribing to one or both of our mailing lists:
|
||||||
|
|
||||||
* [Announcements](http://lists.cloudmutt.com/mailman/listinfo/git-crypt-announce)
|
* [Announcements](https://lists.cloudmutt.com/mailman/listinfo/git-crypt-announce)
|
||||||
* [Discussion](http://lists.cloudmutt.com/mailman/listinfo/git-crypt-discuss)
|
* [Discussion](https://lists.cloudmutt.com/mailman/listinfo/git-crypt-discuss)
|
||||||
|
|||||||
21
RELEASE_NOTES-0.4.1.md
Normal file
21
RELEASE_NOTES-0.4.1.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
git-crypt 0.4.1 is a bugfix-only release that contains an important
|
||||||
|
usability fix for users who use GPG mode to encrypt an entire repository.
|
||||||
|
|
||||||
|
Previously, if you used a '*' pattern in the top-level .gitattributes
|
||||||
|
file, and you did not explicitly add a pattern to exclude the .git-crypt
|
||||||
|
directory, the files contained therein would be encrypted, rendering
|
||||||
|
the repository impossible to unlock with GPG.
|
||||||
|
|
||||||
|
git-crypt now adds a .gitattributes file to the .git-crypt directory
|
||||||
|
to prevent its contents from being encrypted, regardless of patterns in
|
||||||
|
the top-level .gitattributes.
|
||||||
|
|
||||||
|
If you are using git-crypt in GPG mode to encrypt an entire repository,
|
||||||
|
and you do not already have a .gitattributes pattern to exclude the
|
||||||
|
.git-crypt directory, you are strongly advised to upgrade. After
|
||||||
|
upgrading, you should do the following in each of your repositories to
|
||||||
|
ensure that the information inside .git-crypt is properly stored:
|
||||||
|
|
||||||
|
1. Remove existing key files: `rm .git-crypt/keys/*/0/*`
|
||||||
|
|
||||||
|
2. Re-add GPG user(s): `git-crypt add-gpg-user GPG_USER_ID ...`
|
||||||
201
commands.cpp
201
commands.cpp
@@ -49,6 +49,17 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
static std::string attribute_name (const char* key_name)
|
||||||
|
{
|
||||||
|
if (key_name) {
|
||||||
|
// named key
|
||||||
|
return std::string("git-crypt-") + key_name;
|
||||||
|
} else {
|
||||||
|
// default key
|
||||||
|
return "git-crypt";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void git_config (const std::string& name, const std::string& value)
|
static void git_config (const std::string& name, const std::string& value)
|
||||||
{
|
{
|
||||||
std::vector<std::string> command;
|
std::vector<std::string> command;
|
||||||
@@ -99,31 +110,20 @@ static void configure_git_filters (const char* key_name)
|
|||||||
static void unconfigure_git_filters (const char* key_name)
|
static void unconfigure_git_filters (const char* key_name)
|
||||||
{
|
{
|
||||||
// unconfigure the git-crypt filters
|
// unconfigure the git-crypt filters
|
||||||
if (key_name) {
|
git_unconfig("filter." + attribute_name(key_name));
|
||||||
// named key
|
git_unconfig("diff." + attribute_name(key_name));
|
||||||
git_unconfig(std::string("filter.git-crypt-") + key_name);
|
|
||||||
git_unconfig(std::string("diff.git-crypt-") + key_name);
|
|
||||||
} else {
|
|
||||||
// default key
|
|
||||||
git_unconfig("filter.git-crypt");
|
|
||||||
git_unconfig("diff.git-crypt");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool git_checkout_head (const std::string& top_dir)
|
static bool git_checkout (const std::vector<std::string>& paths)
|
||||||
{
|
{
|
||||||
std::vector<std::string> command;
|
std::vector<std::string> command;
|
||||||
|
|
||||||
command.push_back("git");
|
command.push_back("git");
|
||||||
command.push_back("checkout");
|
command.push_back("checkout");
|
||||||
command.push_back("-f");
|
|
||||||
command.push_back("HEAD");
|
|
||||||
command.push_back("--");
|
command.push_back("--");
|
||||||
|
|
||||||
if (top_dir.empty()) {
|
for (std::vector<std::string>::const_iterator path(paths.begin()); path != paths.end(); ++path) {
|
||||||
command.push_back(".");
|
command.push_back(*path);
|
||||||
} else {
|
|
||||||
command.push_back(top_dir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!successful_exit(exec_command(command))) {
|
if (!successful_exit(exec_command(command))) {
|
||||||
@@ -146,7 +146,7 @@ static void validate_key_name_or_throw (const char* key_name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string get_internal_keys_path ()
|
static std::string get_internal_state_path ()
|
||||||
{
|
{
|
||||||
// git rev-parse --git-dir
|
// git rev-parse --git-dir
|
||||||
std::vector<std::string> command;
|
std::vector<std::string> command;
|
||||||
@@ -162,11 +162,21 @@ static std::string get_internal_keys_path ()
|
|||||||
|
|
||||||
std::string path;
|
std::string path;
|
||||||
std::getline(output, path);
|
std::getline(output, path);
|
||||||
path += "/git-crypt/keys";
|
path += "/git-crypt";
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string get_internal_keys_path (const std::string& internal_state_path)
|
||||||
|
{
|
||||||
|
return internal_state_path + "/keys";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string get_internal_keys_path ()
|
||||||
|
{
|
||||||
|
return get_internal_keys_path(get_internal_state_path());
|
||||||
|
}
|
||||||
|
|
||||||
static std::string get_internal_key_path (const char* key_name)
|
static std::string get_internal_key_path (const char* key_name)
|
||||||
{
|
{
|
||||||
std::string path(get_internal_keys_path());
|
std::string path(get_internal_keys_path());
|
||||||
@@ -176,7 +186,7 @@ static std::string get_internal_key_path (const char* key_name)
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string get_repo_keys_path ()
|
static std::string get_repo_state_path ()
|
||||||
{
|
{
|
||||||
// git rev-parse --show-toplevel
|
// git rev-parse --show-toplevel
|
||||||
std::vector<std::string> command;
|
std::vector<std::string> command;
|
||||||
@@ -198,10 +208,20 @@ static std::string get_repo_keys_path ()
|
|||||||
throw Error("Could not determine Git working tree - is this a non-bare repo?");
|
throw Error("Could not determine Git working tree - is this a non-bare repo?");
|
||||||
}
|
}
|
||||||
|
|
||||||
path += "/.git-crypt/keys";
|
path += "/.git-crypt";
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string get_repo_keys_path (const std::string& repo_state_path)
|
||||||
|
{
|
||||||
|
return repo_state_path + "/keys";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string get_repo_keys_path ()
|
||||||
|
{
|
||||||
|
return get_repo_keys_path(get_repo_state_path());
|
||||||
|
}
|
||||||
|
|
||||||
static std::string get_path_to_top ()
|
static std::string get_path_to_top ()
|
||||||
{
|
{
|
||||||
// git rev-parse --show-cdup
|
// git rev-parse --show-cdup
|
||||||
@@ -236,18 +256,6 @@ static void get_git_status (std::ostream& output)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_if_head_exists ()
|
|
||||||
{
|
|
||||||
// git rev-parse HEAD
|
|
||||||
std::vector<std::string> command;
|
|
||||||
command.push_back("git");
|
|
||||||
command.push_back("rev-parse");
|
|
||||||
command.push_back("HEAD");
|
|
||||||
|
|
||||||
std::stringstream output;
|
|
||||||
return successful_exit(exec_command(command, output));
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns filter and diff attributes as a pair
|
// returns filter and diff attributes as a pair
|
||||||
static std::pair<std::string, std::string> get_file_attributes (const std::string& filename)
|
static std::pair<std::string, std::string> get_file_attributes (const std::string& filename)
|
||||||
{
|
{
|
||||||
@@ -348,6 +356,35 @@ static bool check_if_file_is_encrypted (const std::string& filename)
|
|||||||
return check_if_blob_is_encrypted(object_id);
|
return check_if_blob_is_encrypted(object_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_encrypted_files (std::vector<std::string>& files, const char* key_name)
|
||||||
|
{
|
||||||
|
// git ls-files -cz -- path_to_top
|
||||||
|
std::vector<std::string> command;
|
||||||
|
command.push_back("git");
|
||||||
|
command.push_back("ls-files");
|
||||||
|
command.push_back("-cz");
|
||||||
|
command.push_back("--");
|
||||||
|
const std::string path_to_top(get_path_to_top());
|
||||||
|
if (!path_to_top.empty()) {
|
||||||
|
command.push_back(path_to_top);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream output;
|
||||||
|
if (!successful_exit(exec_command(command, output))) {
|
||||||
|
throw Error("'git ls-files' failed - is this a Git repository?");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (output.peek() != -1) {
|
||||||
|
std::string filename;
|
||||||
|
std::getline(output, filename, '\0');
|
||||||
|
|
||||||
|
// TODO: get file attributes en masse for efficiency... unfortunately this requires machine-parseable output from git check-attr to be workable, and this is only supported in Git 1.8.5 and above (released 27 Nov 2013)
|
||||||
|
if (get_file_attributes(filename).first == attribute_name(key_name)) {
|
||||||
|
files.push_back(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void load_key (Key_file& key_file, const char* key_name, const char* key_path =0, const char* legacy_path =0)
|
static void load_key (Key_file& key_file, const char* key_name, const char* key_path =0, const char* legacy_path =0)
|
||||||
{
|
{
|
||||||
if (legacy_path) {
|
if (legacy_path) {
|
||||||
@@ -761,25 +798,18 @@ void help_unlock (std::ostream& out)
|
|||||||
}
|
}
|
||||||
int unlock (int argc, const char** argv)
|
int unlock (int argc, const char** argv)
|
||||||
{
|
{
|
||||||
// 0. Make sure working directory is clean (ignoring untracked files)
|
// 1. Make sure working directory is clean (ignoring untracked files)
|
||||||
// We do this because we run 'git checkout -f HEAD' later and we don't
|
// We do this because we check out files later, and we don't want the
|
||||||
// want the user to lose any changes. 'git checkout -f HEAD' doesn't touch
|
// user to lose any changes. (TODO: only care if encrypted files are
|
||||||
// untracked files so it's safe to ignore those.
|
// modified, since we only check out encrypted files)
|
||||||
|
|
||||||
// Running 'git status' also serves as a check that the Git repo is accessible.
|
// Running 'git status' also serves as a check that the Git repo is accessible.
|
||||||
|
|
||||||
std::stringstream status_output;
|
std::stringstream status_output;
|
||||||
get_git_status(status_output);
|
get_git_status(status_output);
|
||||||
|
if (status_output.peek() != -1) {
|
||||||
// 1. Check to see if HEAD exists. See below why we do this.
|
|
||||||
bool head_exists = check_if_head_exists();
|
|
||||||
|
|
||||||
if (status_output.peek() != -1 && head_exists) {
|
|
||||||
// We only care that the working directory is dirty if HEAD exists.
|
|
||||||
// If HEAD doesn't exist, we won't be resetting to it (see below) so
|
|
||||||
// it doesn't matter that the working directory is dirty.
|
|
||||||
std::clog << "Error: Working directory not clean." << std::endl;
|
std::clog << "Error: Working directory not clean." << std::endl;
|
||||||
std::clog << "Please commit your changes or 'git stash' them before running 'git-crypt' unlock." << std::endl;
|
std::clog << "Please commit your changes or 'git stash' them before running 'git-crypt unlock'." << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -830,13 +860,14 @@ int unlock (int argc, const char** argv)
|
|||||||
if (!decrypt_repo_keys(key_files, 0, gpg_secret_keys, repo_keys_path)) {
|
if (!decrypt_repo_keys(key_files, 0, gpg_secret_keys, repo_keys_path)) {
|
||||||
std::clog << "Error: no GPG secret key available to unlock this repository." << std::endl;
|
std::clog << "Error: no GPG secret key available to unlock this repository." << std::endl;
|
||||||
std::clog << "To unlock with a shared symmetric key instead, specify the path to the symmetric key as an argument to 'git-crypt unlock'." << std::endl;
|
std::clog << "To unlock with a shared symmetric key instead, specify the path to the symmetric key as an argument to 'git-crypt unlock'." << std::endl;
|
||||||
std::clog << "To see a list of GPG keys authorized to unlock this repository, run 'git-crypt ls-collabs'." << std::endl;
|
// TODO std::clog << "To see a list of GPG keys authorized to unlock this repository, run 'git-crypt ls-gpg-users'." << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 4. Install the key(s) and configure the git filters
|
// 4. Install the key(s) and configure the git filters
|
||||||
|
std::vector<std::string> encrypted_files;
|
||||||
for (std::vector<Key_file>::iterator key_file(key_files.begin()); key_file != key_files.end(); ++key_file) {
|
for (std::vector<Key_file>::iterator key_file(key_files.begin()); key_file != key_files.end(); ++key_file) {
|
||||||
std::string internal_key_path(get_internal_key_path(key_file->get_key_name()));
|
std::string internal_key_path(get_internal_key_path(key_file->get_key_name()));
|
||||||
// TODO: croak if internal_key_path already exists???
|
// TODO: croak if internal_key_path already exists???
|
||||||
@@ -847,18 +878,18 @@ int unlock (int argc, const char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
configure_git_filters(key_file->get_key_name());
|
configure_git_filters(key_file->get_key_name());
|
||||||
|
get_encrypted_files(encrypted_files, key_file->get_key_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Do a force checkout so any files that were previously checked out encrypted
|
// 5. Check out the files that are currently encrypted.
|
||||||
// will now be checked out decrypted.
|
// Git won't check out a file if its mtime hasn't changed, so touch every file first.
|
||||||
// If HEAD doesn't exist (perhaps because this repo doesn't have any files yet)
|
for (std::vector<std::string>::const_iterator file(encrypted_files.begin()); file != encrypted_files.end(); ++file) {
|
||||||
// just skip the checkout.
|
touch_file(*file);
|
||||||
if (head_exists) {
|
}
|
||||||
if (!git_checkout_head(path_to_top)) {
|
if (!git_checkout(encrypted_files)) {
|
||||||
std::clog << "Error: 'git checkout' failed" << std::endl;
|
std::clog << "Error: 'git checkout' failed" << std::endl;
|
||||||
std::clog << "git-crypt has been set up but existing encrypted files have not been decrypted" << std::endl;
|
std::clog << "git-crypt has been set up but existing encrypted files have not been decrypted" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -896,25 +927,18 @@ int lock (int argc, const char** argv)
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0. Make sure working directory is clean (ignoring untracked files)
|
// 1. Make sure working directory is clean (ignoring untracked files)
|
||||||
// We do this because we run 'git checkout -f HEAD' later and we don't
|
// We do this because we check out files later, and we don't want the
|
||||||
// want the user to lose any changes. 'git checkout -f HEAD' doesn't touch
|
// user to lose any changes. (TODO: only care if encrypted files are
|
||||||
// untracked files so it's safe to ignore those.
|
// modified, since we only check out encrypted files)
|
||||||
|
|
||||||
// Running 'git status' also serves as a check that the Git repo is accessible.
|
// Running 'git status' also serves as a check that the Git repo is accessible.
|
||||||
|
|
||||||
std::stringstream status_output;
|
std::stringstream status_output;
|
||||||
get_git_status(status_output);
|
get_git_status(status_output);
|
||||||
|
if (status_output.peek() != -1) {
|
||||||
// 1. Check to see if HEAD exists. See below why we do this.
|
|
||||||
bool head_exists = check_if_head_exists();
|
|
||||||
|
|
||||||
if (status_output.peek() != -1 && head_exists) {
|
|
||||||
// We only care that the working directory is dirty if HEAD exists.
|
|
||||||
// If HEAD doesn't exist, we won't be resetting to it (see below) so
|
|
||||||
// it doesn't matter that the working directory is dirty.
|
|
||||||
std::clog << "Error: Working directory not clean." << std::endl;
|
std::clog << "Error: Working directory not clean." << std::endl;
|
||||||
std::clog << "Please commit your changes or 'git stash' them before running 'git-crypt' lock." << std::endl;
|
std::clog << "Please commit your changes or 'git stash' them before running 'git-crypt lock'." << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -924,6 +948,7 @@ int lock (int argc, const char** argv)
|
|||||||
std::string path_to_top(get_path_to_top());
|
std::string path_to_top(get_path_to_top());
|
||||||
|
|
||||||
// 3. unconfigure the git filters and remove decrypted keys
|
// 3. unconfigure the git filters and remove decrypted keys
|
||||||
|
std::vector<std::string> encrypted_files;
|
||||||
if (all_keys) {
|
if (all_keys) {
|
||||||
// unconfigure for all keys
|
// unconfigure for all keys
|
||||||
std::vector<std::string> dirents = get_directory_contents(get_internal_keys_path().c_str());
|
std::vector<std::string> dirents = get_directory_contents(get_internal_keys_path().c_str());
|
||||||
@@ -932,6 +957,7 @@ int lock (int argc, const char** argv)
|
|||||||
const char* this_key_name = (*dirent == "default" ? 0 : dirent->c_str());
|
const char* this_key_name = (*dirent == "default" ? 0 : dirent->c_str());
|
||||||
remove_file(get_internal_key_path(this_key_name));
|
remove_file(get_internal_key_path(this_key_name));
|
||||||
unconfigure_git_filters(this_key_name);
|
unconfigure_git_filters(this_key_name);
|
||||||
|
get_encrypted_files(encrypted_files, this_key_name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// just handle the given key
|
// just handle the given key
|
||||||
@@ -947,18 +973,18 @@ int lock (int argc, const char** argv)
|
|||||||
|
|
||||||
remove_file(internal_key_path);
|
remove_file(internal_key_path);
|
||||||
unconfigure_git_filters(key_name);
|
unconfigure_git_filters(key_name);
|
||||||
|
get_encrypted_files(encrypted_files, key_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Do a force checkout so any files that were previously checked out decrypted
|
// 4. Check out the files that are currently decrypted but should be encrypted.
|
||||||
// will now be checked out encrypted.
|
// Git won't check out a file if its mtime hasn't changed, so touch every file first.
|
||||||
// If HEAD doesn't exist (perhaps because this repo doesn't have any files yet)
|
for (std::vector<std::string>::const_iterator file(encrypted_files.begin()); file != encrypted_files.end(); ++file) {
|
||||||
// just skip the checkout.
|
touch_file(*file);
|
||||||
if (head_exists) {
|
}
|
||||||
if (!git_checkout_head(path_to_top)) {
|
if (!git_checkout(encrypted_files)) {
|
||||||
std::clog << "Error: 'git checkout' failed" << std::endl;
|
std::clog << "Error: 'git checkout' failed" << std::endl;
|
||||||
std::clog << "git-crypt has been locked but up but existing decrypted files have not been encrypted" << std::endl;
|
std::clog << "git-crypt has been locked but up but existing decrypted files have not been encrypted" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1015,10 +1041,23 @@ int add_gpg_user (int argc, const char** argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string keys_path(get_repo_keys_path());
|
const std::string state_path(get_repo_state_path());
|
||||||
std::vector<std::string> new_files;
|
std::vector<std::string> new_files;
|
||||||
|
|
||||||
encrypt_repo_key(key_name, *key, collab_keys, keys_path, &new_files);
|
encrypt_repo_key(key_name, *key, collab_keys, get_repo_keys_path(state_path), &new_files);
|
||||||
|
|
||||||
|
// Add a .gitatributes file to the repo state directory to prevent files in it from being encrypted.
|
||||||
|
const std::string state_gitattributes_path(state_path + "/.gitattributes");
|
||||||
|
if (access(state_gitattributes_path.c_str(), F_OK) != 0) {
|
||||||
|
std::ofstream state_gitattributes_file(state_gitattributes_path.c_str());
|
||||||
|
state_gitattributes_file << "* !filter !diff\n";
|
||||||
|
state_gitattributes_file.close();
|
||||||
|
if (!state_gitattributes_file) {
|
||||||
|
std::clog << "Error: unable to write " << state_gitattributes_path << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
new_files.push_back(state_gitattributes_path);
|
||||||
|
}
|
||||||
|
|
||||||
// add/commit the new files
|
// add/commit the new files
|
||||||
if (!new_files.empty()) {
|
if (!new_files.empty()) {
|
||||||
|
|||||||
@@ -78,6 +78,11 @@ static void print_usage (std::ostream& out)
|
|||||||
out << "See 'git-crypt help COMMAND' for more information on a specific command." << std::endl;
|
out << "See 'git-crypt help COMMAND' for more information on a specific command." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_version (std::ostream& out)
|
||||||
|
{
|
||||||
|
out << "git-crypt " << VERSION << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
static bool help_for_command (const char* command, std::ostream& out)
|
static bool help_for_command (const char* command, std::ostream& out)
|
||||||
{
|
{
|
||||||
if (std::strcmp(command, "init") == 0) {
|
if (std::strcmp(command, "init") == 0) {
|
||||||
@@ -121,6 +126,12 @@ static int help (int argc, const char** argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int version (int argc, const char** argv)
|
||||||
|
{
|
||||||
|
print_version(std::cout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main (int argc, const char** argv)
|
int main (int argc, const char** argv)
|
||||||
try {
|
try {
|
||||||
@@ -141,6 +152,9 @@ try {
|
|||||||
if (std::strcmp(argv[arg_index], "--help") == 0) {
|
if (std::strcmp(argv[arg_index], "--help") == 0) {
|
||||||
print_usage(std::clog);
|
print_usage(std::clog);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (std::strcmp(argv[arg_index], "--version") == 0) {
|
||||||
|
print_version(std::clog);
|
||||||
|
return 0;
|
||||||
} else if (std::strcmp(argv[arg_index], "--") == 0) {
|
} else if (std::strcmp(argv[arg_index], "--") == 0) {
|
||||||
++arg_index;
|
++arg_index;
|
||||||
break;
|
break;
|
||||||
@@ -171,6 +185,9 @@ try {
|
|||||||
if (std::strcmp(command, "help") == 0) {
|
if (std::strcmp(command, "help") == 0) {
|
||||||
return help(argc, argv);
|
return help(argc, argv);
|
||||||
}
|
}
|
||||||
|
if (std::strcmp(command, "version") == 0) {
|
||||||
|
return version(argc, argv);
|
||||||
|
}
|
||||||
if (std::strcmp(command, "init") == 0) {
|
if (std::strcmp(command, "init") == 0) {
|
||||||
return init(argc, argv);
|
return init(argc, argv);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
#ifndef GIT_CRYPT_GIT_CRYPT_HPP
|
#ifndef GIT_CRYPT_GIT_CRYPT_HPP
|
||||||
#define GIT_CRYPT_GIT_CRYPT_HPP
|
#define GIT_CRYPT_GIT_CRYPT_HPP
|
||||||
|
|
||||||
|
#define VERSION "0.4.2"
|
||||||
|
|
||||||
extern const char* argv0; // initialized in main() to argv[0]
|
extern const char* argv0; // initialized in main() to argv[0]
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user