1: <?php
2:
3: /**
4: * PGP modules
5: * @package modules
6: * @subpackage pgp
7: */
8:
9: if (!defined('DEBUG_MODE')) { die(); }
10:
11:
12: /**
13: * @subpackage pgp/handler
14: */
15: class Hm_Handler_load_pgp_data extends Hm_Handler_Module {
16: public function process() {
17: $this->out('pgp_public_keys', $this->user_config->get('pgp_public_keys', array()));
18: }
19: }
20:
21: /**
22: * @subpackage pgp/handler
23: */
24: class Hm_Handler_pgp_delete_public_key extends Hm_Handler_Module {
25: public function process() {
26: list($success, $form) = $this->process_form(array('delete_public_key_id'));
27: if (!$success) {
28: return;
29: }
30: $keys = $this->user_config->get('pgp_public_keys', array());
31: if (!array_key_exists($form['delete_public_key_id'], $keys)) {
32: Hm_Msgs::add('Could not find public key to remove', 'warning');
33: return;
34: }
35: unset($keys[$form['delete_public_key_id']]);
36: $this->session->set('pgp_public_keys', $keys, true);
37: $this->session->record_unsaved('Public key deleted');
38: Hm_Msgs::add('Public key deleted');
39: }
40: }
41:
42: /**
43: * @subpackage pgp/handler
44: */
45: class Hm_Handler_pgp_import_public_key extends Hm_Handler_Module {
46: public function process() {
47: list($success, $form) = $this->process_form(array('public_key_email'));
48: if (!$success) {
49: return;
50: }
51: if (! check_file_upload($this->request, 'public_key')) {
52: return;
53: }
54: $fingerprint = validate_public_key($this->request->files['public_key']['tmp_name']);
55: if (!$fingerprint) {
56: Hm_Msgs::add('Unable to import public key', 'danger');
57: return;
58: }
59: $keys = $this->user_config->get('pgp_public_keys', array());
60: $keys[] = array('fingerprint' => $fingerprint, 'key' => file_get_contents($this->request->files['public_key']['tmp_name']), 'email' => $form['public_key_email']);
61: $this->session->set('pgp_public_keys', $keys, true);
62: $this->session->record_unsaved('Public key imported');
63: Hm_Msgs::add('Public key imported');
64: }
65: }
66:
67: /**
68: * @subpackage pgp/handler
69: */
70: class Hm_Handler_pgp_compose_data extends Hm_Handler_Module {
71: public function process() {
72: $this->out('html_mail', $this->user_config->get('smtp_compose_type_setting', DEFAULT_SMTP_COMPOSE_TYPE));
73: $this->out('pgp_public_keys', $this->user_config->get('pgp_public_keys', array()));
74: }
75: }
76:
77: /**
78: * @subpackage pgp/handler
79: */
80: class Hm_Handler_pgp_message_check extends Hm_Handler_Module {
81: public function process() {
82: /* TODO: Check for pgp parts, look at current part for pgp lines */
83: $pgp = false;
84: $struct = $this->get('msg_struct', array());
85: $text = $this->get('msg_text');
86: if (mb_strpos($text, '----BEGIN PGP MESSAGE-----') !== false) {
87: $pgp = true;
88: }
89: $part_struct = $this->get('msg_struct_current', array());
90: if (is_array($part_struct) && array_key_exists('type', $part_struct) &&
91: $part_struct['type'] == 'application' && $part_struct['subtype'] == 'pgp-encrypted') {
92: $pgp = true;
93: }
94: $this->out('pgp_msg_part', $pgp);
95: }
96: }
97:
98: /**
99: * @subpackage pgp/output
100: */
101: class Hm_Output_pgp_compose_controls extends Hm_Output_Module {
102: protected function output() {
103: if ($this->get('html_mail', 0)) {
104: return;
105: }
106: $pub_keys = $this->get('pgp_public_keys', array());
107: $res = '<script type="text/javascript" src="'.WEB_ROOT.'modules/pgp/assets/openpgp.min.js"></script>';
108: $res .= '<div class="container">';
109: $res .= '<div class="row justify-content-md-center">';
110: $res .= '<div class="col col-lg-8">';
111: $res .= '<div class="pgp_section">';
112:
113: $res .= '<span class="pgp_sign"><label for="pgp_sign" class="form-label">'.$this->trans('PGP Sign as').'</label>';
114: $res .= '<select id="pgp_sign" size="1" class="form-control"></select></span>';
115:
116: if (count($pub_keys) > 0) {
117: $res .= '<label for="pgp_encrypt" class="form-label" style="margin-top:1rem">'.$this->trans('PGP Encrypt for').
118: '</label><select id="pgp_encrypt" size="1" class="form-control"><option disabled selected value=""></option>';
119: foreach ($pub_keys as $vals) {
120: $res .= '<option value="'.$vals['key'].'">'.$vals['email'].'</option>';
121: }
122: $res .= '</select>';
123: }
124: $res .= '</div></div></div></div>';
125: return $res;
126: }
127: }
128:
129: /**
130: * @subpackage pgp/output
131: */
132: class Hm_Output_pgp_settings_start extends Hm_Output_Module {
133: protected function output() {
134: $res = '<div class="pgp_settings p-0"><div class="content_title px-3">'.$this->trans('PGP Settings').'</div>';
135: $res .= '<script type="text/javascript" src="'.WEB_ROOT.'modules/pgp/assets/openpgp.min.js"></script>';
136: return $res;
137: }
138: }
139:
140: /**
141: * @subpackage pgp/output
142: */
143: class Hm_Output_pgp_settings_public_keys extends Hm_Output_Module {
144: protected function output() {
145: $res = '<div class="public_title settings_subtitle p-3 border-bottom cursor-pointer"><i class="bi bi-filetype-key me-3"></i> '.$this->trans('Public Keys');
146: $res .= '<span class="key_count">'.sprintf($this->trans('%s imported'), count($this->get('pgp_public_keys', array()))).'</span></div>';
147: $res .= '<div class="public_keys pgp_block col-lg-7 col-xl-4">';
148: $res .= '<form enctype="multipart/form-data" method="post" action="?page=pgp#public_keys" class="pgp_subblock col-lg-6"><div class="mb-2"><label class="form-label">'.$this->trans('Import a public key from a file').'</label><input required id="public_key" name="public_key" type="file" class="form-control"></div>';
149: $res .= '<div class="mb-2"><input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />';
150: $res .= '<label class="form-label" for="public_email">For</label>';
151: $res .= '<input required id="public_email" name="public_key_email" placeholder="'.$this->trans('E-mail Address');
152: $res .= '" type="email" class="form-control warn_on_paste"></div> <input type="submit" value="'.$this->trans('Import').'" class="btn btn-primary">';
153: $res .= '</form>';
154: $res .= '<table class="pgp_keys table mt-3"><thead><tr><th>'.$this->trans('Fingerprint').'</th>';
155: $res .= '<th>'.$this->trans('E-mail').'</th><th></th></tr>';
156: $res .= '</thead><tbody>';
157: foreach ($this->get('pgp_public_keys', array()) as $index => $vals) {
158: $res .= '<tr><td>'.$this->html_safe($vals['fingerprint']).'</td><td>'.$this->html_safe($vals['email']).'</td>';
159: $res .= '</td><td><form method="post" action="?page=pgp#public_keys">';
160: $res .= '<input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />';
161: $res .= '<input type="hidden" value="'.$this->html_safe($index).'" name="delete_public_key_id" />'.
162: '<button type="submit" class="delete_pgp_key btn btn-light" title="'.$this->trans('Delete').'">';
163: $res .= '"<i class="bi bi-x-circle-fill"></i></button></form></td></tr>';
164: }
165: $res .= '</tbody></table>';
166: $res .= '</div>';
167: return $res;
168: }
169: }
170:
171: /**
172: * @subpackage pgp/output
173: */
174: class Hm_Output_pgp_settings_private_key extends Hm_Output_Module {
175: protected function output() {
176: $res = '<div class="priv_title settings_subtitle p-3 border-bottom cursor-pointer"><i class="bi bi-key-fill me-3"></i> '.$this->trans('Private Keys');
177: $res .= '<span class="private_key_count">'.sprintf($this->trans('%s imported'), 0).'</span></div>';
178: $res .= '<div class="priv_keys pgp_block col-lg-7 col-xl-4"><div class="pgp_subblock mb-3">';
179: $res .= $this->trans('Private keys never leave your browser, and are deleted when you logout');
180: $res .= '<input id="priv_key" type="file" class="form-control">';
181: $res .= '</div>'.$this->trans('Existing Keys').'<table class="pgp_keys private_key_list table"><thead><tr><th>'.$this->trans('Identity').'</th><th></th></tr>';
182: $res .= '</thead><tbody></tbody></table>';
183: $res .= '</div>';
184: return $res;
185: }
186: }
187:
188: /**
189: * @subpackage pgp/output
190: */
191: class Hm_Output_pgp_settings_end extends Hm_Output_Module {
192: protected function output() {
193: return '</div>';
194: }
195: }
196:
197: /**
198: * @subpackage pgp/output
199: */
200: class Hm_Output_pgp_msg_controls extends Hm_Output_Module {
201: protected function output() {
202: return '<script type="text/javascript" src="'.WEB_ROOT.'modules/pgp/assets/openpgp.min.js"></script>'.
203: '<div class="pgp_msg_controls input-group"><select class="pgp_private_keys form-control"></select> <input type="button" class="pgp_btn btn-primary" value="Decrypt" /></div>'.prompt_for_passhrase($this);
204: }
205: }
206:
207: /**
208: * @subpackage pgp/output
209: */
210: class Hm_Output_pgp_settings_link extends Hm_Output_Module {
211: protected function output() {
212: $res = '<li class="menu_pgp"><a class="unread_link" href="?page=pgp">';
213: if (!$this->get('hide_folder_icons')) {
214: $res .= '<i class="bi bi-lock-fill account_icon menu-icon"></i> ';
215: }
216: $res .= $this->trans('PGP').'</a></li>';
217: if ($this->format == 'HTML5') {
218: return $res;
219: }
220: $this->concat('formatted_folder_list', $res);
221: }
222: }
223:
224: /**
225: * @subpackage pgp/functions
226: */
227: if (!hm_exists('validate_public_key')) {
228: function validate_public_key($file_location) {
229: if (!class_exists('gnupg')) {
230: Hm_Debug::add('Gnupg PECL extension not found', 'warning');
231: return false;
232: }
233: if (!is_readable($file_location)) {
234: Hm_Debug::add('Uploaded public key not readable', 'warning');
235: return false;
236: }
237: $data = file_get_contents($file_location);
238: if (!$data) {
239: Hm_Debug::add('Uploaded public key not readable', 'warning');
240: return false;
241: }
242: $tmp_dir = ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir();
243: putenv(sprintf('GNUPGHOME=%s/.gnupg', $tmp_dir));
244: $gpg = new gnupg();
245: $info = $gpg->import($data);
246: if (is_array($info) && array_key_exists('fingerprint', $info)) {
247: return $info['fingerprint'];
248: }
249: return false;
250: }}
251:
252: /**
253: * @subpackage pgp/functions
254: */
255: if (!hm_exists('prompt_for_passhrase')) {
256: function prompt_for_passhrase($mod) {
257: return '<div class="passphrase_prompt"><div class="title">'.$mod->trans('Please enter your passphrase').'</div><div class="input-group"><input type="password" value="" id="pgp_pass" class="form-control" /> <input id="submit_pgp_pass" type="button" value="'.$mod->trans('Submit').'" class="btn btn-primary" /></div></div>';
258: }}
259: