| 1: | <?php |
| 2: | |
| 3: | |
| 4: | |
| 5: | |
| 6: | |
| 7: | |
| 8: | |
| 9: | if (!defined('DEBUG_MODE')) { die(); } |
| 10: | |
| 11: | |
| 12: | |
| 13: | |
| 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: | |
| 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: | |
| 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: | |
| 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: | |
| 79: | |
| 80: | class Hm_Handler_pgp_message_check extends Hm_Handler_Module { |
| 81: | public function process() { |
| 82: | |
| 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: | |
| 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: | |
| 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: | |
| 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: | |
| 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: | |
| 190: | |
| 191: | class Hm_Output_pgp_settings_end extends Hm_Output_Module { |
| 192: | protected function output() { |
| 193: | return '</div>'; |
| 194: | } |
| 195: | } |
| 196: | |
| 197: | |
| 198: | |
| 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: | |
| 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: | |
| 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: | |
| 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: | |