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 pub fn workdir(&self) -> Result<&Path> {
57 self.repo.workdir().ok_or(GitCryptError::Other(
58 "Repository has no working directory".into(),
59 ))
60 }
61}
62
63pub fn clean_filter(key: &CryptoKey) -> Result<()> {
65 let mut input = Vec::new();
66 io::stdin().read_to_end(&mut input)?;
67
68 if CryptoKey::is_encrypted(&input) {
70 io::stdout().write_all(&input)?;
71 return Ok(());
72 }
73
74 let encrypted = key.encrypt(&input)?;
75
76 io::stdout().write_all(&encrypted)?;
78
79 Ok(())
80}
81
82pub fn smudge_filter(key: &CryptoKey) -> Result<()> {
84 let mut input = Vec::new();
85 io::stdin().read_to_end(&mut input)?;
86
87 if !CryptoKey::is_encrypted(&input) {
89 io::stdout().write_all(&input)?;
90 return Ok(());
91 }
92
93 let decrypted = key.decrypt(&input)?;
94
95 io::stdout().write_all(&decrypted)?;
97
98 Ok(())
99}
100
101pub fn diff_filter() -> Result<()> {
103 let mut input = Vec::new();
104 io::stdin().read_to_end(&mut input)?;
105
106 if CryptoKey::is_encrypted(&input) {
107 writeln!(io::stdout(), "*** This file is encrypted with git-crypt ***")?;
108 } else {
109 io::stdout().write_all(&input)?;
110 }
111
112 Ok(())
113}