1use crate::crypto::CryptoKey;
2use crate::error::{GitCryptError, Result};
3use git2::Repository;
4use std::io::{self, Read, Write};
5use std::path::Path;
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).map_err(|_| GitCryptError::NotInGitRepo)?;
15 Ok(Self { repo })
16 }
17
18 pub fn git_dir(&self) -> &Path {
20 self.repo.path()
21 }
22
23 pub fn configure_filters(&self) -> Result<()> {
25 let mut config = self.repo.config()?;
26
27 config.set_str("filter.git-crypt.clean", "git-crypt clean")?;
29
30 config.set_str("filter.git-crypt.smudge", "git-crypt smudge")?;
32
33 config.set_str("filter.git-crypt.diff", "git-crypt diff")?;
35
36 config.set_bool("filter.git-crypt.required", true)?;
38
39 Ok(())
40 }
41
42 pub fn remove_filters(&self) -> Result<()> {
44 let mut config = self.repo.config()?;
45
46 let _ = config.remove("filter.git-crypt.clean");
47 let _ = config.remove("filter.git-crypt.smudge");
48 let _ = config.remove("filter.git-crypt.diff");
49 let _ = config.remove("filter.git-crypt.required");
50
51 Ok(())
52 }
53
54 #[allow(dead_code)]
56 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!(
108 io::stdout(),
109 "*** This file is encrypted with git-crypt ***"
110 )?;
111 } else {
112 io::stdout().write_all(&input)?;
113 }
114
115 Ok(())
116}