1use git2::Repository;
2use std::io::{self, Read, Write};
3use std::path::Path;
4use crate::crypto::CryptoKey;
5use crate::error::{GitCryptError, Result};
6
7pub struct GitRepo {
8 repo: Repository,
9}
10
11impl GitRepo {
12 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
14 let repo = Repository::discover(path)
15 .map_err(|_| GitCryptError::NotInGitRepo)?;
16 Ok(Self { repo })
17 }
18
19 pub fn git_dir(&self) -> &Path {
21 self.repo.path()
22 }
23
24 pub fn configure_filters(&self) -> Result<()> {
26 let mut config = self.repo.config()?;
27
28 config.set_str("filter.git-crypt.clean", "git-crypt clean")?;
30
31 config.set_str("filter.git-crypt.smudge", "git-crypt smudge")?;
33
34 config.set_str("filter.git-crypt.diff", "git-crypt diff")?;
36
37 config.set_bool("filter.git-crypt.required", true)?;
39
40 Ok(())
41 }
42
43 pub fn remove_filters(&self) -> Result<()> {
45 let mut config = self.repo.config()?;
46
47 let _ = config.remove("filter.git-crypt.clean");
48 let _ = config.remove("filter.git-crypt.smudge");
49 let _ = config.remove("filter.git-crypt.diff");
50 let _ = config.remove("filter.git-crypt.required");
51
52 Ok(())
53 }
54
55 #[allow(dead_code)]
57 pub fn workdir(&self) -> Result<&Path> {
58 self.repo.workdir().ok_or(GitCryptError::Other(
59 "Repository has no working directory".into(),
60 ))
61 }
62}
63
64pub fn clean_filter(key: &CryptoKey) -> Result<()> {
66 let mut input = Vec::new();
67 io::stdin().read_to_end(&mut input)?;
68
69 if CryptoKey::is_encrypted(&input) {
71 io::stdout().write_all(&input)?;
72 return Ok(());
73 }
74
75 let encrypted = key.encrypt(&input)?;
76
77 io::stdout().write_all(&encrypted)?;
79
80 Ok(())
81}
82
83pub fn smudge_filter(key: &CryptoKey) -> Result<()> {
85 let mut input = Vec::new();
86 io::stdin().read_to_end(&mut input)?;
87
88 if !CryptoKey::is_encrypted(&input) {
90 io::stdout().write_all(&input)?;
91 return Ok(());
92 }
93
94 let decrypted = key.decrypt(&input)?;
95
96 io::stdout().write_all(&decrypted)?;
98
99 Ok(())
100}
101
102pub fn diff_filter() -> Result<()> {
104 let mut input = Vec::new();
105 io::stdin().read_to_end(&mut input)?;
106
107 if CryptoKey::is_encrypted(&input) {
108 writeln!(io::stdout(), "*** This file is encrypted with git-crypt ***")?;
109 } else {
110 io::stdout().write_all(&input)?;
111 }
112
113 Ok(())
114}