webpg-npapi 0.6.1
|
00001 /**********************************************************\ 00002 Original Author: Kyle L. Huff (kylehuff) 00003 00004 Created: Jan 14, 2011 00005 License: GNU General Public License, version 2 00006 http://www.gnu.org/licenses/gpl-2.0.html 00007 00008 Copyright 2011 Kyle L. Huff, CURETHEITCH development team 00009 \**********************************************************/ 00010 00011 #include "JSObject.h" 00012 #include "variant_list.h" 00013 #include "DOM/Document.h" 00014 #include "DOM/Window.h" 00015 #include "global/config.h" 00016 00017 #include "webpgPluginAPI.h" 00018 #include "keyedit.h" 00019 00020 /* 00021 * Define non-member methods/inlines 00022 */ 00023 00024 #ifdef HAVE_W32_SYSTEM 00025 #define __func__ __FUNCTION__ 00026 #endif 00027 00028 FB::VariantMap get_error_map(const std::string& method, 00029 gpgme_error_t gpg_error_code, 00030 const std::string& error_string, 00031 int line, const std::string& file, 00032 std::string data="") 00033 { 00034 FB::VariantMap error_map_obj; 00035 error_map_obj["error"] = true; 00036 error_map_obj["method"] = method; 00037 error_map_obj["gpg_error_code"] = gpg_error_code; 00038 error_map_obj["error_string"] = error_string; 00039 error_map_obj["line"] = line; 00040 error_map_obj["file"] = file; 00041 if (data.length()) 00042 error_map_obj["data"] = data; 00043 return error_map_obj; 00044 } 00045 00046 /* An inline method to convert a null char */ 00047 inline 00048 static const char * 00049 nonnull (const char *s) 00050 { 00051 return s? s :"[none]"; 00052 } 00053 00054 std::string LoadFileAsString(const std::string& filename) 00055 { 00056 std::ifstream fin(filename.c_str()); 00057 00058 if(!fin) 00059 { 00060 return ""; 00061 } 00062 00063 std::ostringstream oss; 00064 oss << fin.rdbuf(); 00065 00066 return oss.str(); 00067 } 00068 00069 static bool gpgme_invalid = false; 00070 00081 webpgPluginAPI::webpgPluginAPI(const webpgPluginPtr& plugin, const FB::BrowserHostPtr& host) : m_plugin(plugin), m_host(host) 00082 { 00083 static bool allow_op = true; 00084 #ifdef _EXTENSIONIZE 00085 std::string location = m_host->getDOMWindow()->getLocation(); 00086 size_t firefox_ext = location.find("chrome://"); 00087 size_t chrome_ext = location.find("chrome-extension://"); 00088 if (chrome_ext != std::string::npos || firefox_ext != std::string::npos) 00089 allow_op = true; 00090 else 00091 allow_op = false; 00092 #endif 00093 00094 if (allow_op == true) { 00095 registerMethod("getKeyList", make_method(this, &webpgPluginAPI::getKeyList)); 00096 registerMethod("getPublicKeyList", make_method(this, &webpgPluginAPI::getPublicKeyList)); 00097 registerMethod("getPrivateKeyList", make_method(this, &webpgPluginAPI::getPrivateKeyList)); 00098 registerMethod("getNamedKey", make_method(this, &webpgPluginAPI::getNamedKey)); 00099 registerMethod("gpgSetPreference", make_method(this, &webpgPluginAPI::gpgSetPreference)); 00100 registerMethod("gpgGetPreference", make_method(this, &webpgPluginAPI::gpgGetPreference)); 00101 registerMethod("gpgSetHomeDir", make_method(this, &webpgPluginAPI::gpgSetHomeDir)); 00102 registerMethod("gpgGetHomeDir", make_method(this, &webpgPluginAPI::gpgGetHomeDir)); 00103 registerMethod("gpgEncrypt", make_method(this, &webpgPluginAPI::gpgEncrypt)); 00104 registerMethod("gpgSymmetricEncrypt", make_method(this, &webpgPluginAPI::gpgSymmetricEncrypt)); 00105 registerMethod("gpgDecrypt", make_method(this, &webpgPluginAPI::gpgDecrypt)); 00106 registerMethod("gpgVerify", make_method(this, &webpgPluginAPI::gpgVerify)); 00107 registerMethod("gpgSignText", make_method(this, &webpgPluginAPI::gpgSignText)); 00108 registerMethod("gpgSignUID", make_method(this, &webpgPluginAPI::gpgSignUID)); 00109 registerMethod("gpgEnableKey", make_method(this, &webpgPluginAPI::gpgEnableKey)); 00110 registerMethod("gpgDisableKey", make_method(this, &webpgPluginAPI::gpgDisableKey)); 00111 registerMethod("gpgDeleteUIDSign", make_method(this, &webpgPluginAPI::gpgDeleteUIDSign)); 00112 registerMethod("gpgGenKey", make_method(this, &webpgPluginAPI::gpgGenKey)); 00113 registerMethod("gpgGenSubKey", make_method(this, &webpgPluginAPI::gpgGenSubKey)); 00114 registerMethod("gpgImportKey", make_method(this, &webpgPluginAPI::gpgImportKey)); 00115 registerMethod("gpgDeletePublicKey", make_method(this, &webpgPluginAPI::gpgDeletePublicKey)); 00116 registerMethod("gpgDeletePrivateKey", make_method(this, &webpgPluginAPI::gpgDeletePrivateKey)); 00117 registerMethod("gpgDeletePrivateSubKey", make_method(this, &webpgPluginAPI::gpgDeletePrivateSubKey)); 00118 registerMethod("gpgSetKeyTrust", make_method(this, &webpgPluginAPI::gpgSetKeyTrust)); 00119 registerMethod("gpgAddUID", make_method(this, &webpgPluginAPI::gpgAddUID)); 00120 registerMethod("gpgDeleteUID", make_method(this, &webpgPluginAPI::gpgDeleteUID)); 00121 registerMethod("gpgSetPrimaryUID", make_method(this, &webpgPluginAPI::gpgSetPrimaryUID)); 00122 registerMethod("gpgSetSubkeyExpire", make_method(this, &webpgPluginAPI::gpgSetSubkeyExpire)); 00123 registerMethod("gpgSetPubkeyExpire", make_method(this, &webpgPluginAPI::gpgSetPubkeyExpire)); 00124 registerMethod("gpgExportPublicKey", make_method(this, &webpgPluginAPI::gpgExportPublicKey)); 00125 registerMethod("gpgRevokeKey", make_method(this, &webpgPluginAPI::gpgRevokeKey)); 00126 registerMethod("gpgRevokeUID", make_method(this, &webpgPluginAPI::gpgRevokeUID)); 00127 registerMethod("gpgRevokeSignature", make_method(this, &webpgPluginAPI::gpgRevokeSignature)); 00128 registerMethod("gpgChangePassphrase", make_method(this, &webpgPluginAPI::gpgChangePassphrase)); 00129 00130 registerMethod("setTempGPGOption", make_method(this, &webpgPluginAPI::setTempGPGOption)); 00131 registerMethod("restoreGPGConfig", make_method(this, &webpgPluginAPI::restoreGPGConfig)); 00132 registerMethod("getTemporaryPath", make_method(this, &webpgPluginAPI::getTemporaryPath)); 00133 00134 registerEvent("onkeygenprogress"); 00135 registerEvent("onkeygencomplete"); 00136 } 00137 00138 // Read-only property 00139 registerProperty("version", 00140 make_property(this, 00141 &webpgPluginAPI::get_version)); 00142 00143 registerProperty("webpg_status", 00144 make_property(this, 00145 &webpgPluginAPI::get_webpg_status)); 00146 00147 registerProperty("gpgconf_detected", 00148 make_property(this, 00149 &webpgPluginAPI::gpgconf_detected)); 00150 00151 webpgPluginAPI::init(); 00152 } 00153 00161 webpgPluginAPI::~webpgPluginAPI() 00162 { 00163 } 00164 00173 webpgPluginPtr webpgPluginAPI::getPlugin() 00174 { 00175 webpgPluginPtr plugin(m_plugin.lock()); 00176 if (!plugin) { 00177 throw FB::script_error("The plugin is invalid"); 00178 } 00179 return plugin; 00180 } 00181 00187 void webpgPluginAPI::init() 00188 { 00189 gpgme_ctx_t ctx; 00190 gpgme_error_t err; 00191 FB::VariantMap error_map; 00192 FB::VariantMap response; 00193 FB::VariantMap protocol_info, plugin_info; 00194 gpgme_engine_info_t engine_info; 00195 00196 plugin_info["source_url"] = m_host->getDOMWindow()->getLocation(); 00197 plugin_info["path"] = getPlugin()->getPluginPath(); 00198 plugin_info["params"] = getPlugin()->getPluginParams(); 00199 plugin_info["version"] = FBSTRING_PLUGIN_VERSION; 00200 response["plugin"] = plugin_info; 00201 00202 #ifdef _EXTENSIONIZE 00203 response["extensionize"] = true; 00204 std::string location = m_host->getDOMWindow()->getLocation(); 00205 size_t firefox_ext = location.find("chrome://"); 00206 size_t chrome_ext = location.find("chrome-extension://"); 00207 response["extension"] = (chrome_ext != std::string::npos) ? 00208 "chrome" : (firefox_ext != std::string::npos) ? "firefox" : "unknown"; 00209 #endif 00210 00211 /* Initialize the locale environment. 00212 * The function `gpgme_check_version` must be called before any other 00213 * function in the library, because it initializes the thread support 00214 * subsystem in GPGME. (from the info page) */ 00215 std::string gpgme_version = (char *) gpgme_check_version(NULL); 00216 00217 setlocale (LC_ALL, ""); 00218 gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL)); 00219 #ifdef LC_MESSAGES 00220 gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL)); 00221 #endif 00222 00223 err = gpgme_engine_check_version (GPGME_PROTOCOL_OpenPGP); 00224 if (err != GPG_ERR_NO_ERROR) 00225 error_map = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 00226 00227 if (error_map.size()) { 00228 response["openpgp_valid"] = false; 00229 response["error"] = true; 00230 response["error_map"] = error_map; 00231 webpgPluginAPI::webpg_status_map = error_map; 00232 gpgme_invalid = true; 00233 return; 00234 } 00235 00236 ctx = get_gpgme_ctx(); 00237 00238 response["error"] = false; 00239 response["gpgme_valid"] = true; 00240 response["gpgconf_detected"] = gpgconf_detected(); 00241 if (!gpgconf_detected()) 00242 response["gpgconf_response"] = gpgme_strerror (gpgme_engine_check_version (GPGME_PROTOCOL_GPGCONF)); 00243 response["gpgme_version"] = gpgme_version; 00244 engine_info = gpgme_ctx_get_engine_info (ctx); 00245 if (engine_info) { 00246 if (engine_info->file_name) 00247 protocol_info["file_name"] = (char *) engine_info->file_name; 00248 if (engine_info->version) 00249 protocol_info["version"] = (char *) engine_info->version; 00250 if (engine_info->home_dir) 00251 protocol_info["home_dir"] = (char *) engine_info->home_dir; 00252 if (engine_info->req_version) 00253 protocol_info["req_version"] = (char *) engine_info->req_version; 00254 response[(char *) gpgme_get_protocol_name (engine_info->protocol)] = protocol_info; 00255 } else { 00256 response["OpenPGP"] = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 00257 } 00258 00259 response["GNUPGHOME"] = GNUPGHOME; 00260 00261 // Retrieve the GPG_AGENT_INFO environment variable 00262 char *gpg_agent_info = getenv("GPG_AGENT_INFO"); 00263 00264 if (gpg_agent_info != NULL) { 00265 response["gpg_agent_info"] = gpg_agent_info; 00266 } else { 00267 response["gpg_agent_info"] = "unknown"; 00268 } 00269 00270 if (ctx) 00271 gpgme_release (ctx); 00272 00273 webpgPluginAPI::webpg_status_map = response; 00274 }; 00275 00281 gpgme_ctx_t webpgPluginAPI::get_gpgme_ctx() 00282 { 00283 gpgme_ctx_t ctx; 00284 gpgme_error_t err; 00285 00286 setlocale (LC_ALL, ""); 00287 gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL)); 00288 #ifdef LC_MESSAGES 00289 gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL)); 00290 #endif 00291 00292 // Check the GNUPGHOME variable, if not null, set that 00293 if (GNUPGHOME.length() > 0) { 00294 err = gpgme_new (&ctx); 00295 gpgme_engine_info_t engine_info = gpgme_ctx_get_engine_info (ctx); 00296 if (engine_info) { 00297 err = gpgme_ctx_set_engine_info (ctx, engine_info->protocol, 00298 engine_info->file_name, 00299 GNUPGHOME.c_str()); 00300 } else { 00301 std::string env = "GNUPGHOME=" + GNUPGHOME; 00302 putenv(strdup(env.c_str())); 00303 err = gpgme_new (&ctx); 00304 } 00305 } else { 00306 err = gpgme_new (&ctx); 00307 } 00308 00309 gpgme_set_textmode (ctx, 1); 00310 gpgme_set_armor (ctx, 1); 00311 00312 return ctx; 00313 } 00314 00321 std::string webpgPluginAPI::getGPGConfigFilename() { 00322 std::string config_path = ""; 00323 00324 if (GNUPGHOME.length() > 0) { 00325 config_path = GNUPGHOME; 00326 } else { 00327 char const* home = getenv("HOME"); 00328 if (home || (home = getenv("USERPROFILE"))) { 00329 config_path = home; 00330 } else { 00331 char const *hdrive = getenv("HOMEDRIVE"), 00332 *hpath = getenv("HOMEPATH"); 00333 assert(hdrive); // or other error handling 00334 assert(hpath); 00335 config_path = std::string(hdrive) + hpath; 00336 } 00337 } 00338 00339 #ifdef HAVE_W32_SYSTEM 00340 config_path += "\\Application Data\\gnupg\\gpg.conf"; 00341 #else 00342 config_path += "/.gnupg/gpg.conf"; 00343 #endif 00344 00345 return config_path; 00346 } 00347 00354 FB::variant webpgPluginAPI::setTempGPGOption(const std::string& option, const std::string& value) { 00355 00356 std::string result; 00357 std::string config_path = webpgPluginAPI::getGPGConfigFilename(); 00358 std::string tmp_config_path = config_path + "-webpg.save"; 00359 00360 std::string gpgconfigfile = LoadFileAsString(config_path); 00361 00362 if (gpgconfigfile.length()) { 00363 // Test if we already made a backup, if not, make one! 00364 std::ifstream tmp_config_exists(tmp_config_path.c_str()); 00365 if (!tmp_config_exists) { 00366 // Backup the current contents 00367 std::ofstream tmp_file(tmp_config_path.c_str()); 00368 if (!tmp_file) 00369 return "error opening temp_file"; 00370 tmp_file << gpgconfigfile; 00371 tmp_file.close(); 00372 } 00373 00374 // Ensure we are not appending to an existing line 00375 gpgconfigfile += "\n"; 00376 gpgconfigfile += option; 00377 if (value.length()) 00378 gpgconfigfile += " " + value; 00379 gpgconfigfile += "\n"; 00380 00381 std::ofstream gpg_file(config_path.c_str()); 00382 if (!gpg_file) 00383 return "error writing gpg_file"; 00384 gpg_file << gpgconfigfile; 00385 gpg_file.close(); 00386 } 00387 00388 if (gpgconfigfile.length()) 00389 result = "Set "; 00390 else 00391 result = "Unable to set "; 00392 00393 if (value.length()) 00394 result += "'" + option + " = " + value + "' in file: " + config_path; 00395 else 00396 result += "'" + option + "' in file: " + config_path; 00397 00398 return result; 00399 } 00400 00406 FB::variant webpgPluginAPI::restoreGPGConfig() { 00407 00408 std::string config_path = getGPGConfigFilename(); 00409 std::string tmp_config_path = config_path + "-webpg.save"; 00410 00411 std::string restore_string; 00412 std::string result = "gpg config restored from memory"; 00413 00414 if (!original_gpg_config.length()) { 00415 // We don't have the original file in memory, lets restore the backup 00416 original_gpg_config = LoadFileAsString(tmp_config_path); 00417 if (!original_gpg_config.length()) 00418 return "error restoring gpg_file from disk"; 00419 result = "gpg config restored from disk."; 00420 } 00421 00422 std::ofstream gpg_file(config_path.c_str()); 00423 00424 if (!gpg_file) 00425 return "error restoring gpg_file from memory"; 00426 00427 gpg_file << original_gpg_config; 00428 gpg_file.close(); 00429 00430 remove(tmp_config_path.c_str()); 00431 original_gpg_config = ""; 00432 00433 return result; 00434 } 00435 00443 FB::variant webpgPluginAPI::gpgSetHomeDir(const std::string& gnupg_path) 00444 { 00445 GNUPGHOME = gnupg_path; 00446 return GNUPGHOME; 00447 } 00448 00449 FB::variant webpgPluginAPI::gpgGetHomeDir() 00450 { 00451 return GNUPGHOME; 00452 } 00453 00459 FB::variant webpgPluginAPI::getTemporaryPath() 00460 { 00461 char *gnupghome_envvar = getenv("TEMP"); 00462 if (gnupghome_envvar != NULL) { 00463 return gnupghome_envvar; 00464 } else { 00465 return ""; 00466 } 00467 } 00468 00477 00503 00504 FB::VariantMap webpgPluginAPI::get_webpg_status() 00505 { 00506 webpgPluginAPI::init(); 00507 webpgPluginAPI::webpg_status_map["edit_status"] = edit_status; 00508 return webpgPluginAPI::webpg_status_map; 00509 } 00510 00521 00624 00625 /* 00626 This method retrieves all keys matching name, or if name is left empty, 00627 returns all keys in the keyring. 00628 NOTE: This method is not exposed to the NPAPI plugin, it is only called internally 00629 */ 00630 FB::VariantMap webpgPluginAPI::getKeyList(const std::string& name, int secret_only) 00631 { 00632 /* declare variables */ 00633 gpgme_ctx_t ctx = get_gpgme_ctx(); 00634 gpgme_error_t err; 00635 gpgme_key_t key; 00636 gpgme_keylist_result_t result; 00637 gpgme_user_id_t uid; 00638 gpgme_key_sig_t sig; 00639 gpgme_subkey_t subkey; 00640 FB::VariantMap keylist_map; 00641 00642 FB::VariantMap uid_map; 00643 00644 /* set protocol to use in our context */ 00645 err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP); 00646 if(err != GPG_ERR_NO_ERROR) 00647 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 00648 00649 /* apply the keylist mode to the context and set 00650 the keylist_mode 00651 NOTE: The keylist mode flag GPGME_KEYLIST_MODE_SIGS 00652 returns the signatures of UIDS with the key */ 00653 gpgme_set_keylist_mode (ctx, (gpgme_get_keylist_mode (ctx) 00654 | GPGME_KEYLIST_MODE_SIGS 00655 | GPGME_KEYLIST_MODE_VALIDATE)); 00656 00657 /* gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only) */ 00658 if (name.length() > 0){ // limit key listing to search criteria 'name' 00659 err = gpgme_op_keylist_start (ctx, name.c_str(), secret_only); 00660 } else { // list all keys 00661 err = gpgme_op_keylist_start (ctx, NULL, secret_only); 00662 } 00663 if(err != GPG_ERR_NO_ERROR) 00664 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 00665 00666 while (!(err = gpgme_op_keylist_next (ctx, &key))) 00667 { 00668 /*declare nuids (Number of UIDs) 00669 and nsigs (Number of signatures) 00670 and nsubs (Number of Subkeys)*/ 00671 int nuids; 00672 int nsigs; 00673 int nsubs; 00674 int tnsigs; 00675 FB::VariantMap key_map; 00676 00677 /* if secret keys being returned, re-retrieve the key so we get all of the key info */ 00678 if(secret_only != 0 && key->subkeys && key->subkeys->keyid) 00679 err = gpgme_get_key (ctx, key->subkeys->keyid, &key, 0); 00680 00681 /* iterate through the keys/subkeys and add them to the key_map object */ 00682 if (key->uids && key->uids->name) 00683 key_map["name"] = nonnull (key->uids->name); 00684 if (key->subkeys && key->subkeys->fpr) 00685 key_map["fingerprint"] = nonnull (key->subkeys->fpr); 00686 if (key->uids && key->uids->email) 00687 key_map["email"] = nonnull (key->uids->email); 00688 key_map["expired"] = key->expired? true : false; 00689 key_map["revoked"] = key->revoked? true : false; 00690 key_map["disabled"] = key->disabled? true : false; 00691 key_map["invalid"] = key->invalid? true : false; 00692 key_map["secret"] = key->secret? true : false; 00693 key_map["protocol"] = key->protocol == GPGME_PROTOCOL_OpenPGP? "OpenPGP": 00694 key->protocol == GPGME_PROTOCOL_CMS? "CMS": 00695 key->protocol == GPGME_PROTOCOL_UNKNOWN? "Unknown": "[?]"; 00696 key_map["can_encrypt"] = key->can_encrypt? true : false; 00697 key_map["can_sign"] = key->can_sign? true : false; 00698 key_map["can_certify"] = key->can_certify? true : false; 00699 key_map["can_authenticate"] = key->can_authenticate? true : false; 00700 key_map["is_qualified"] = key->is_qualified? true : false; 00701 key_map["owner_trust"] = key->owner_trust == GPGME_VALIDITY_UNKNOWN? "unknown": 00702 key->owner_trust == GPGME_VALIDITY_UNDEFINED? "undefined": 00703 key->owner_trust == GPGME_VALIDITY_NEVER? "never": 00704 key->owner_trust == GPGME_VALIDITY_MARGINAL? "marginal": 00705 key->owner_trust == GPGME_VALIDITY_FULL? "full": 00706 key->owner_trust == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]"; 00707 00708 FB::VariantMap subkeys_map; 00709 for (nsubs=0, subkey=key->subkeys; subkey; subkey = subkey->next, nsubs++) { 00710 FB::VariantMap subkey_item_map; 00711 subkey_item_map["subkey"] = nonnull (subkey->fpr); 00712 subkey_item_map["expired"] = subkey->expired? true : false; 00713 subkey_item_map["revoked"] = subkey->revoked? true : false; 00714 subkey_item_map["disabled"] = subkey->disabled? true : false; 00715 subkey_item_map["invalid"] = subkey->invalid? true : false; 00716 subkey_item_map["secret"] = subkey->secret? true : false; 00717 subkey_item_map["can_encrypt"] = subkey->can_encrypt? true : false; 00718 subkey_item_map["can_sign"] = subkey->can_sign? true : false; 00719 subkey_item_map["can_certify"] = subkey->can_certify? true : false; 00720 subkey_item_map["can_authenticate"] = subkey->can_authenticate? true : false; 00721 subkey_item_map["is_qualified"] = subkey->is_qualified? true : false; 00722 subkey_item_map["algorithm"] = subkey->pubkey_algo; 00723 subkey_item_map["algorithm_name"] = nonnull (gpgme_pubkey_algo_name(subkey->pubkey_algo)); 00724 subkey_item_map["size"] = subkey->length; 00725 subkey_item_map["created"] = subkey->timestamp; 00726 subkey_item_map["expires"] = subkey->expires; 00727 subkeys_map[i_to_str(nsubs)] = subkey_item_map; 00728 } 00729 00730 key_map["subkeys"] = subkeys_map; 00731 00732 FB::VariantMap uids_map; 00733 for (nuids=0, uid=key->uids; uid; uid = uid->next, nuids++) { 00734 FB::VariantMap uid_item_map; 00735 uid_item_map["uid"] = nonnull (uid->name); 00736 uid_item_map["email"] = nonnull (uid->email); 00737 uid_item_map["comment"] = nonnull (uid->comment); 00738 uid_item_map["invalid"] = uid->invalid? true : false; 00739 uid_item_map["revoked"] = uid->revoked? true : false; 00740 tnsigs = 0; 00741 for (nsigs=0, sig=uid->signatures; sig; sig = sig->next, nsigs++) { 00742 tnsigs += 1; 00743 } 00744 uid_item_map["signatures_count"] = tnsigs; 00745 00746 FB::VariantMap signatures_map; 00747 00748 for (nsigs=0, sig=uid->signatures; sig; sig = sig->next, nsigs++) { 00749 FB::VariantMap signature_map; 00750 signature_map["keyid"] = nonnull (sig->keyid); 00751 signature_map["algorithm"] = sig->pubkey_algo; 00752 signature_map["algorithm_name"] = nonnull (gpgme_pubkey_algo_name(sig->pubkey_algo)); 00753 signature_map["revoked"] = sig->revoked? true : false; 00754 signature_map["expired"] = sig->expired? true : false; 00755 signature_map["invalid"] = sig->invalid? true : false; 00756 signature_map["exportable"] = sig->exportable? true : false; 00757 signature_map["created"] = sig->timestamp; 00758 signature_map["expires"] = sig->expires; 00759 signature_map["uid"] = nonnull (sig->uid); 00760 signature_map["name"] = nonnull (sig->name); 00761 signature_map["comment"] = nonnull (sig->comment); 00762 signature_map["email"] = nonnull (sig->email); 00763 signatures_map[i_to_str(nsigs)] = signature_map; 00764 } 00765 uid_item_map["signatures"] = signatures_map; 00766 uid_item_map["validity"] = uid->validity == GPGME_VALIDITY_UNKNOWN? "unknown": 00767 uid->validity == GPGME_VALIDITY_UNDEFINED? "undefined": 00768 uid->validity == GPGME_VALIDITY_NEVER? "never": 00769 uid->validity == GPGME_VALIDITY_MARGINAL? "marginal": 00770 uid->validity == GPGME_VALIDITY_FULL? "full": 00771 uid->validity == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]"; 00772 uids_map[i_to_str(nuids)] = uid_item_map; 00773 } 00774 key_map["uids"] = uids_map; 00775 keylist_map[key->subkeys->keyid] = key_map; 00776 gpgme_key_unref (key); 00777 } 00778 00779 if (gpg_err_code (err) != GPG_ERR_EOF) exit(6); 00780 err = gpgme_op_keylist_end (ctx); 00781 if(err != GPG_ERR_NO_ERROR) exit(7); 00782 result = gpgme_op_keylist_result (ctx); 00783 if (result->truncated) 00784 { 00785 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 00786 } 00787 gpgme_release (ctx); 00788 return keylist_map; 00789 } 00790 00798 /* 00799 This method executes webpgPlugin.getKeyList with an empty string and 00800 secret_only=0 which returns all Public Keys in the keyring. 00801 */ 00802 FB::variant webpgPluginAPI::getPublicKeyList() 00803 { 00804 // Retrieve the public keylist 00805 FB::variant public_keylist = webpgPluginAPI::getKeyList("", 0); 00806 00807 // Retrieve a reference to the DOM Window 00808 FB::DOM::WindowPtr window = m_host->getDOMWindow(); 00809 00810 // Check if the DOM Window has an in-built JSON Parser 00811 if (window && window->getJSObject()->HasProperty("JSON")) { 00812 // Convert the VariantMap to a Json::Value object 00813 Json::Value json_value = FB::variantToJsonValue(public_keylist); 00814 00815 // Create a writer that will convert the object to a string 00816 Json::FastWriter writer; 00817 00818 // Create a reference to the browswer JSON object 00819 FB::JSObjectPtr obj = window->getProperty<FB::JSObjectPtr>("JSON"); 00820 00821 return obj->Invoke("parse", FB::variant_list_of(writer.write(json_value))); 00822 } else { 00823 // No browser JSON parser detected, falling back to return of FB::variant 00824 return public_keylist; 00825 } 00826 } 00827 00835 /* 00836 This method executes webpgPlugin.getKeyList with an empty string and 00837 secret_only=1 which returns all keys in the keyring which 00838 the user has the corrisponding secret key. 00839 */ 00840 FB::variant webpgPluginAPI::getPrivateKeyList() 00841 { 00842 // Retrieve the private keylist 00843 FB::variant private_keylist = webpgPluginAPI::getKeyList("", 1); 00844 00845 // Retrieve a reference to the DOM Window 00846 FB::DOM::WindowPtr window = m_host->getDOMWindow(); 00847 00848 // Check if the DOM Window has an in-built JSON Parser 00849 if (window && window->getJSObject()->HasProperty("JSON")) { 00850 // Convert the VariantMap to a Json::Value object 00851 Json::Value json_value = FB::variantToJsonValue(private_keylist); 00852 00853 // Create a writer that will convert the object to a string 00854 Json::FastWriter writer; 00855 00856 // Create a reference to the browswer JSON object 00857 FB::JSObjectPtr obj = window->getProperty<FB::JSObjectPtr>("JSON"); 00858 00859 return obj->Invoke("parse", FB::variant_list_of(writer.write(json_value))); 00860 } else { 00861 // No browser JSON parser detected, falling back to return of FB::variant 00862 return private_keylist; 00863 } 00864 } 00865 00873 /* 00874 This method just calls webpgPlugin.getKeyList with a name/email 00875 as the parameter 00876 */ 00877 FB::variant webpgPluginAPI::getNamedKey(const std::string& name) 00878 { 00879 // Retrieve the keylist as a VariantMap 00880 FB::variant keylist = webpgPluginAPI::getKeyList(name, 0); 00881 00882 // Retrieve a reference to the DOM Window 00883 FB::DOM::WindowPtr window = m_host->getDOMWindow(); 00884 00885 // Check if the DOM Window has an in-built JSON Parser 00886 if (window && window->getJSObject()->HasProperty("JSON")) { 00887 // Convert the VariantMap to a Json::Value object 00888 Json::Value json_value = FB::variantToJsonValue(keylist); 00889 00890 // Create a writer that will convert the object to a string 00891 Json::FastWriter writer; 00892 00893 // Create a reference to the browswer JSON object 00894 FB::JSObjectPtr obj = window->getProperty<FB::JSObjectPtr>("JSON"); 00895 00896 return obj->Invoke("parse", FB::variant_list_of(writer.write(json_value))); 00897 } else { 00898 // No browser JSON parser detected, falling back to return of FB::variant 00899 return keylist; 00900 } 00901 } 00902 00908 bool webpgPluginAPI::gpgconf_detected() { 00909 gpgme_error_t err; 00910 std::string cfg_present; 00911 err = gpgme_engine_check_version (GPGME_PROTOCOL_GPGCONF); 00912 if (err && err != GPG_ERR_NO_ERROR) { 00913 return false; 00914 } 00915 return true; 00916 } 00917 00926 std::string webpgPluginAPI::get_preference(const std::string& preference) 00927 { 00928 gpgme_ctx_t ctx = get_gpgme_ctx(); 00929 gpgme_error_t err; 00930 gpgme_conf_comp_t conf, comp; 00931 gpgme_conf_opt_t opt; 00932 std::string return_value; 00933 00934 err = gpgme_op_conf_load (ctx, &conf); 00935 00936 comp = conf; 00937 while (comp && strcmp (comp->name, "gpg")) 00938 comp = comp->next; 00939 00940 if (comp) { 00941 opt = comp->options; 00942 while (opt && strcmp (opt->name, (char *) preference.c_str())){ 00943 opt = opt->next; 00944 } 00945 00946 if (opt->value) { 00947 return_value = opt->value->value.string; 00948 } else { 00949 return_value = "blank"; 00950 } 00951 } 00952 00953 gpgme_conf_release (conf); 00954 00955 return return_value; 00956 00957 } 00958 00968 FB::variant webpgPluginAPI::gpgSetPreference(const std::string& preference, const std::string& pref_value) 00969 { 00970 gpgme_error_t err; 00971 gpgme_protocol_t proto = GPGME_PROTOCOL_OpenPGP; 00972 err = gpgme_engine_check_version (proto); 00973 if (err != GPG_ERR_NO_ERROR) 00974 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 00975 00976 gpgme_ctx_t ctx = get_gpgme_ctx(); 00977 gpgme_conf_comp_t conf, comp; 00978 FB::variant response; 00979 std::string return_code; 00980 00981 err = gpgme_op_conf_load (ctx, &conf); 00982 if (err != GPG_ERR_NO_ERROR) 00983 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 00984 00985 gpgme_conf_arg_t original_arg, arg; 00986 gpgme_conf_opt_t opt; 00987 00988 if (pref_value.length()) 00989 err = gpgme_conf_arg_new (&arg, GPGME_CONF_STRING, (char *) pref_value.c_str()); 00990 else 00991 err = gpgme_conf_arg_new (&arg, GPGME_CONF_STRING, NULL); 00992 00993 if (err != GPG_ERR_NO_ERROR) 00994 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 00995 00996 comp = conf; 00997 while (comp && strcmp (comp->name, "gpg")) 00998 comp = comp->next; 00999 01000 if (comp) { 01001 opt = comp->options; 01002 01003 while (opt && strcmp (opt->name, (char *) preference.c_str())){ 01004 opt = opt->next; 01005 } 01006 01007 if (!opt) { 01008 return "unable to locate that option in this context"; 01009 } 01010 01011 if (opt->value && pref_value.length()) { 01012 original_arg = opt->value; 01013 } else { 01014 original_arg = opt->value; 01015 return_code = "blank"; 01016 } 01017 01018 /* if the new argument and original argument are the same, return 0, 01019 there is nothing to do. */ 01020 if (pref_value.length() && original_arg && 01021 !strcmp (original_arg->value.string, arg->value.string)) { 01022 return "0"; 01023 } 01024 01025 if (opt) { 01026 if (!strcmp(pref_value.c_str(), "blank") || pref_value.length() < 1) 01027 err = gpgme_conf_opt_change (opt, 0, NULL); 01028 else 01029 err = gpgme_conf_opt_change (opt, 0, arg); 01030 01031 if (err != GPG_ERR_NO_ERROR) 01032 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01033 01034 err = gpgme_op_conf_save (ctx, comp); 01035 if (err != GPG_ERR_NO_ERROR) 01036 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01037 } 01038 } 01039 01040 if (conf) 01041 gpgme_conf_release (conf); 01042 01043 if (ctx) 01044 gpgme_release (ctx); 01045 01046 if (!return_code.length()) 01047 return_code = strdup(original_arg->value.string); 01048 01049 return return_code; 01050 } 01051 01060 FB::variant webpgPluginAPI::gpgGetPreference(const std::string& preference) 01061 { 01062 gpgme_error_t err; 01063 gpgme_protocol_t proto = GPGME_PROTOCOL_OpenPGP; 01064 err = gpgme_engine_check_version (proto); 01065 if (err != GPG_ERR_NO_ERROR) 01066 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01067 01068 gpgme_ctx_t ctx = get_gpgme_ctx(); 01069 gpgme_conf_comp_t conf, comp; 01070 FB::VariantMap response; 01071 response["error"] = false; 01072 01073 err = gpgme_op_conf_load (ctx, &conf); 01074 if (err != GPG_ERR_NO_ERROR) 01075 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01076 01077 gpgme_conf_arg_t arg; 01078 gpgme_conf_opt_t opt; 01079 01080 comp = conf; 01081 while (comp && strcmp (comp->name, "gpg")) 01082 comp = comp->next; 01083 01084 if (comp) { 01085 opt = comp->options; 01086 01087 while (opt && strcmp (opt->name, (char *) preference.c_str())){ 01088 opt = opt->next; 01089 } 01090 01091 if (opt) { 01092 if (opt->value) { 01093 arg = opt->value; 01094 response["value"] = strdup(arg->value.string); 01095 } else { 01096 response["value"] = ""; 01097 } 01098 } else { 01099 response["error"] = true; 01100 response["error_string"] = "unable to locate that option in this context"; 01101 } 01102 } 01103 01104 if (conf) 01105 gpgme_conf_release (conf); 01106 01107 if (ctx) 01108 gpgme_release (ctx); 01109 01110 return response; 01111 } 01112 01124 01138 01139 /* 01140 This method passes a string to encrypt, a list of keys to encrypt to calls 01141 webpgPlugin.gpgEncrypt. This method returns a string of encrypted data. 01142 */ 01143 /* This method accepts 3 parameters, data, enc_to_keyid 01144 and sign [optional; default: 0:NULL:false] 01145 the return value is a string buffer of the result */ 01146 FB::variant webpgPluginAPI::gpgEncrypt(const std::string& data, 01147 const FB::VariantList& enc_to_keyids, bool sign) 01148 { 01149 /* declare variables */ 01150 gpgme_ctx_t ctx = get_gpgme_ctx(); 01151 gpgme_error_t err; 01152 gpgme_data_t in, out; 01153 #ifdef HAVE_W32_SYSTEM 01154 // FIXME: W32 doesn't like the array sized by the contents of the 01155 // enc_to_keyids - for now set to 100 01156 gpgme_key_t key[100]; 01157 #else 01158 gpgme_key_t key[enc_to_keyids.size()]; 01159 #endif 01160 int nrecipients; 01161 FB::variant recipient; 01162 FB::VariantList recpients; 01163 gpgme_encrypt_result_t enc_result; 01164 FB::VariantMap response; 01165 bool unusable_key = false; 01166 01167 err = gpgme_data_new_from_mem (&in, data.c_str(), data.length(), 0); 01168 if (err != GPG_ERR_NO_ERROR) 01169 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01170 01171 err = gpgme_data_set_encoding(in, GPGME_DATA_ENCODING_ARMOR); 01172 if(err != GPG_ERR_NO_ERROR) 01173 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01174 01175 err = gpgme_data_new (&out); 01176 if (err != GPG_ERR_NO_ERROR) 01177 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01178 01179 err = gpgme_data_set_encoding(out, GPGME_DATA_ENCODING_ARMOR); 01180 if(err != GPG_ERR_NO_ERROR) 01181 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01182 01183 for (nrecipients=0; nrecipients < enc_to_keyids.size(); nrecipients++) { 01184 01185 recipient = enc_to_keyids[nrecipients]; 01186 01187 err = gpgme_get_key (ctx, recipient.convert_cast<std::string>().c_str(), &key[nrecipients], 0); 01188 if(err != GPG_ERR_NO_ERROR) 01189 return get_error_map(__func__, gpgme_err_code (err), 01190 gpgme_strerror (err), __LINE__, __FILE__, 01191 recipient.convert_cast<std::string>().c_str()); 01192 01193 // Check if key is unusable/invalid 01194 unusable_key = key[nrecipients]->invalid? true : 01195 key[nrecipients]->expired? true : 01196 key[nrecipients]->revoked? true : 01197 key[nrecipients]->disabled? true : false; 01198 01199 if (unusable_key) { 01200 // Somehow an ususable/invalid key has been passed to the method 01201 std::string keyid = key[nrecipients]->subkeys->fpr; 01202 01203 std::string strerror = key[nrecipients]->invalid? "Invalid key" : 01204 key[nrecipients]->expired? "Key expired" : 01205 key[nrecipients]->revoked? "Key revoked" : 01206 key[nrecipients]->disabled? "Key disabled" : "Unknown error"; 01207 01208 err = key[nrecipients]->invalid? 53 : 01209 key[nrecipients]->expired? 153 : 01210 key[nrecipients]->revoked? 94 : 01211 key[nrecipients]->disabled? 53 : GPG_ERR_UNKNOWN_ERRNO; 01212 01213 return get_error_map(__func__, gpgme_err_code (err), strerror, __LINE__, __FILE__, keyid); 01214 } 01215 01216 } 01217 01218 // NULL terminate the key array 01219 key[enc_to_keyids.size()] = NULL; 01220 01221 if (sign) { 01222 if (enc_to_keyids.size() < 1) { 01223 // NOTE: This doesn't actually work due to an issue with gpgme-1.3.2. 01224 // see: https://bugs.g10code.com/gnupg/issue1440 for details 01225 //err = gpgme_op_encrypt_sign (ctx, NULL, GPGME_ENCRYPT_NO_ENCRYPT_TO, in, out); 01226 return "Signed Symmetric Encryption is not yet implemented"; 01227 } else { 01228 err = gpgme_op_encrypt_sign (ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, in, out); 01229 } 01230 } else { 01231 if (enc_to_keyids.size() < 1) { 01232 // Symmetric encrypt 01233 err = gpgme_op_encrypt (ctx, NULL, GPGME_ENCRYPT_NO_ENCRYPT_TO, in, out); 01234 } else { 01235 err = gpgme_op_encrypt (ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, in, out); 01236 } 01237 } 01238 01239 if (err != GPG_ERR_NO_ERROR) 01240 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01241 01242 if (enc_to_keyids.size() < 1) { 01243 // This was a symmetric operation, and gpgme_op_encrypt does not return 01244 // an error if the passphrase is incorrect, so we need to check the 01245 // returned value for actual substance. 01246 gpgme_data_seek(out, 0, SEEK_SET); 01247 char buf[513]; 01248 gpgme_data_read (out, buf, 512); 01249 int buflen = strlen(buf); 01250 if (buflen < 52) { 01251 gpgme_release (ctx); 01252 gpgme_data_release (in); 01253 gpgme_data_release (out); 01254 FB::VariantMap error_map_obj; 01255 error_map_obj["error"] = true; 01256 error_map_obj["method"] = __func__; 01257 error_map_obj["gpg_error_code"] = "11"; 01258 error_map_obj["error_string"] = "Passphrase did not match"; 01259 error_map_obj["line"] = __LINE__; 01260 error_map_obj["file"] = __FILE__; 01261 return error_map_obj; 01262 } 01263 } 01264 01265 enc_result = gpgme_op_encrypt_result (ctx); 01266 if (enc_result->invalid_recipients) 01267 { 01268 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01269 } 01270 01271 size_t out_size = 0; 01272 std::string out_buf; 01273 out_buf = gpgme_data_release_and_get_mem (out, &out_size); 01274 /* strip the size_t data out of the output buffer */ 01275 out_buf = out_buf.substr(0, out_size); 01276 /* set the output object to NULL since it has 01277 already been released */ 01278 out = NULL; 01279 01280 /* if any of the gpgme objects have not yet 01281 been release, do so now */ 01282 for (nrecipients=0; nrecipients < enc_to_keyids.size(); nrecipients++) 01283 gpgme_key_unref(key[nrecipients]); 01284 01285 if (ctx) 01286 gpgme_release (ctx); 01287 if (in) 01288 gpgme_data_release (in); 01289 if (out) 01290 gpgme_data_release (out); 01291 01292 response["data"] = out_buf; 01293 response["error"] = false; 01294 01295 return response; 01296 } 01297 01309 /* 01310 This method just calls webpgPlugin.gpgEncrypt without any keys 01311 as the parameter, which then uses Symmetric Encryption. 01312 */ 01313 /* This method accepts 2 parameters, data and sign [optional; 01314 default: 0:NULL:false]. 01315 the return value is a string buffer of the result */ 01316 FB::variant webpgPluginAPI::gpgSymmetricEncrypt(const std::string& data, 01317 bool sign) 01318 { 01319 FB::VariantList empty_keys; 01320 return webpgPluginAPI::gpgEncrypt(data, empty_keys, sign); 01321 } 01322 01336 01353 01354 FB::variant webpgPluginAPI::gpgDecryptVerify(const std::string& data, int use_agent) 01355 { 01356 gpgme_ctx_t ctx; 01357 gpgme_error_t err; 01358 gpgme_decrypt_result_t decrypt_result; 01359 gpgme_verify_result_t verify_result; 01360 gpgme_signature_t sig; 01361 gpgme_data_t in, out; 01362 std::string out_buf; 01363 std::string envvar; 01364 FB::VariantMap response; 01365 int nsigs; 01366 int tnsigs = 0; 01367 char buf[513]; 01368 int ret; 01369 01370 char *agent_info = getenv("GPG_AGENT_INFO"); 01371 01372 if (use_agent == 0) { 01373 // Set the GPG_AGENT_INFO to null because the user shouldn't be bothered with for 01374 // a passphrase if we get a chunk of encrypted data by mistake. 01375 setTempGPGOption("batch", ""); 01376 // Set the defined password to be "", if anything else is sent to the 01377 // agent, this will result in a return error of invalid key when 01378 // performing Symmetric decryption (because the passphrase is the 01379 // secret key) 01380 setTempGPGOption("passphrase", "\"\""); 01381 #ifndef HAVE_W32_SYSTEM 01382 #ifndef FB_MACOSX 01383 // Poison the GPG_AGENT_INFO environment variable 01384 envvar = "GPG_AGENT_INFO=INVALID"; 01385 putenv(strdup(envvar.c_str())); 01386 #endif 01387 #endif 01388 // Create our context with the above modifications 01389 ctx = get_gpgme_ctx(); 01390 // Set the passphrase callback to just send "\n", which will 01391 // deal with the case there is no gpg-agent 01392 gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL); 01393 } else { 01394 ctx = get_gpgme_ctx(); 01395 } 01396 01397 err = gpgme_data_new_from_mem (&in, data.c_str(), data.length(), 0); 01398 if (err != GPG_ERR_NO_ERROR) { 01399 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01400 } 01401 01402 err = gpgme_data_new (&out); 01403 if (err != GPG_ERR_NO_ERROR) { 01404 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01405 } 01406 01407 err = gpgme_op_decrypt_verify (ctx, in, out); 01408 01409 decrypt_result = gpgme_op_decrypt_result (ctx); 01410 verify_result = gpgme_op_verify_result (ctx); 01411 01412 if (use_agent == 0) { 01413 // Restore the gpg.conf options 01414 restoreGPGConfig(); 01415 // Restore GPG_AGENT_INFO to its original value 01416 #ifndef HAVE_W32_SYSTEM 01417 #ifndef FB_MACOSX 01418 envvar = "GPG_AGENT_INFO="; 01419 envvar += agent_info; 01420 putenv(strdup(envvar.c_str())); 01421 #endif 01422 #endif 01423 } 01424 01425 if (err != GPG_ERR_NO_ERROR && !verify_result) { 01426 // There was an error returned while decrypting; 01427 // either bad data, or signed only data 01428 if (verify_result && verify_result->signatures) { 01429 if (verify_result->signatures->status != GPG_ERR_NO_ERROR) { 01430 //No valid GPG data to decrypt or signatures to verify; possibly bad armor.\" }"; 01431 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01432 } 01433 } 01434 if (gpg_err_code(err) == GPG_ERR_CANCELED) { 01435 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01436 } 01437 if (gpg_err_code(err) == GPG_ERR_BAD_PASSPHRASE) { 01438 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01439 } 01440 if (gpg_err_source(err) == GPG_ERR_SOURCE_PINENTRY) { 01441 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01442 } 01443 if (gpg_err_source(err) == GPG_ERR_SOURCE_GPGAGENT) { 01444 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01445 } 01446 } 01447 01448 FB::VariantMap signatures; 01449 if (verify_result && verify_result->signatures) { 01450 tnsigs = 0; 01451 for (nsigs=0, sig=verify_result->signatures; sig; sig = sig->next, nsigs++) { 01452 FB::VariantMap signature; 01453 signature["fingerprint"] = nonnull (sig->fpr); 01454 signature["timestamp"] = sig->timestamp; 01455 signature["expiration"] = sig->exp_timestamp; 01456 signature["validity"] = sig->validity == GPGME_VALIDITY_UNKNOWN? "unknown": 01457 sig->validity == GPGME_VALIDITY_UNDEFINED? "undefined": 01458 sig->validity == GPGME_VALIDITY_NEVER? "never": 01459 sig->validity == GPGME_VALIDITY_MARGINAL? "marginal": 01460 sig->validity == GPGME_VALIDITY_FULL? "full": 01461 sig->validity == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]"; 01462 signature["status"] = gpg_err_code (sig->status) == GPG_ERR_NO_ERROR? "GOOD": 01463 gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE? "BAD_SIG": 01464 gpg_err_code (sig->status) == GPG_ERR_NO_PUBKEY? "NO_PUBKEY": 01465 gpg_err_code (sig->status) == GPG_ERR_NO_DATA? "NO_SIGNATURE": 01466 gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED? "GOOD_EXPSIG": 01467 gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED? "GOOD_EXPKEY": "INVALID"; 01468 signatures[i_to_str(nsigs)] = signature; 01469 tnsigs++; 01470 } 01471 } 01472 01473 if (nsigs < 1 || err == 11) { 01474 response["message_type"] = "encrypted_message"; 01475 if (use_agent == 0) { 01476 response["message_event"] = "auto"; 01477 } else { 01478 response["message_event"] = "manual"; 01479 } 01480 } else { 01481 response["message_type"] = "signed_message"; 01482 } 01483 01484 if (err != GPG_ERR_NO_ERROR && tnsigs < 1) { 01485 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01486 } 01487 01488 if (gpgme_err_code (err) == 58 && tnsigs < 1) { 01489 gpgme_data_release (out); 01490 response["data"] = data; 01491 response["message_type"] = "detached_signature"; 01492 } else { 01493 ret = gpgme_data_seek(out, 0, SEEK_SET); 01494 01495 if (ret) 01496 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01497 01498 while ((ret = gpgme_data_read (out, buf, 512)) > 0) 01499 out_buf += buf; 01500 01501 if (ret < 0) 01502 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01503 01504 if (out_buf.length() < 1) { 01505 response["data"] = data; 01506 response["message_type"] = "detached_signature"; 01507 gpgme_data_release (out); 01508 } else { 01509 size_t out_size = 0; 01510 gpgme_data_seek(out, 0, SEEK_SET); 01511 out_buf = gpgme_data_release_and_get_mem (out, &out_size); 01512 01513 /* strip the size_t data out of the output buffer */ 01514 out_buf = out_buf.substr(0, out_size); 01515 response["data"] = out_buf; 01516 } 01517 01518 } 01519 01520 response["signatures"] = signatures; 01521 response["error"] = false; 01522 gpgme_data_release (in); 01523 gpgme_release (ctx); 01524 01525 return response; 01526 } 01527 01536 FB::variant webpgPluginAPI::gpgDecrypt(const std::string& data) 01537 { 01538 return webpgPluginAPI::gpgDecryptVerify(data, 1); 01539 } 01540 01541 FB::variant webpgPluginAPI::gpgVerify(const std::string& data) 01542 { 01543 return webpgPluginAPI::gpgDecryptVerify(data, 0); 01544 } 01545 01557 01578 01579 /* 01580 sign_mode is one of: 01581 0: GPGME_SIG_MODE_NORMAL 01582 1: GPGME_SIG_MODE_DETACH 01583 2: GPGME_SIG_MODE_CLEAR 01584 */ 01585 FB::variant webpgPluginAPI::gpgSignText(const FB::VariantList& signers, const std::string& plain_text, 01586 int sign_mode) 01587 { 01588 gpgme_ctx_t ctx = get_gpgme_ctx(); 01589 gpgme_error_t err; 01590 gpgme_data_t in, out; 01591 gpgme_key_t key; 01592 gpgme_sig_mode_t sig_mode; 01593 gpgme_sign_result_t sign_result; 01594 int nsigners; 01595 FB::variant signer; 01596 FB::VariantMap result; 01597 01598 if (sign_mode == 0) 01599 sig_mode = GPGME_SIG_MODE_NORMAL; 01600 else if (sign_mode == 1) 01601 sig_mode = GPGME_SIG_MODE_DETACH; 01602 else if (sign_mode == 2) 01603 sig_mode = GPGME_SIG_MODE_CLEAR; 01604 01605 for (nsigners=0; nsigners < signers.size(); nsigners++) { 01606 signer = signers[nsigners]; 01607 err = gpgme_op_keylist_start (ctx, signer.convert_cast<std::string>().c_str(), 0); 01608 if (err != GPG_ERR_NO_ERROR) 01609 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01610 01611 err = gpgme_op_keylist_next (ctx, &key); 01612 if (err != GPG_ERR_NO_ERROR) 01613 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01614 01615 err = gpgme_op_keylist_end (ctx); 01616 if (err != GPG_ERR_NO_ERROR) 01617 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01618 01619 err = gpgme_signers_add (ctx, key); 01620 if (err != GPG_ERR_NO_ERROR) 01621 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01622 01623 gpgme_key_unref (key); 01624 01625 } 01626 01627 if (!nsigners > 0) 01628 return get_error_map(__func__, -1, "No signing keys found", __LINE__, __FILE__); 01629 01630 err = gpgme_data_new_from_mem (&in, plain_text.c_str(), plain_text.length(), 0); 01631 if (err != GPG_ERR_NO_ERROR) 01632 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01633 01634 err = gpgme_data_new (&out); 01635 if (err != GPG_ERR_NO_ERROR) 01636 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01637 01638 err = gpgme_op_sign(ctx, in, out, sig_mode); 01639 if (err != GPG_ERR_NO_ERROR) 01640 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01641 01642 sign_result = gpgme_op_sign_result (ctx); 01643 01644 if (!sign_result) 01645 return get_error_map(__func__, gpgme_err_code (err), "The signed result is invalid", __LINE__, __FILE__); 01646 01647 gpgme_data_seek(out, 0, SEEK_SET); 01648 01649 size_t out_size = 0; 01650 std::string out_buf; 01651 out_buf = gpgme_data_release_and_get_mem (out, &out_size); 01652 /* strip the size_t data out of the output buffer */ 01653 out_buf = out_buf.substr(0, out_size); 01654 /* set the output object to NULL since it has 01655 already been released */ 01656 out = NULL; 01657 01658 result["error"] = false; 01659 result["data"] = out_buf; 01660 01661 gpgme_data_release (in); 01662 gpgme_release (ctx); 01663 01664 return result; 01665 01666 } 01667 01681 FB::variant webpgPluginAPI::gpgSignUID(const std::string& keyid, long sign_uid, 01682 const std::string& with_keyid, long local_only, long trust_sign, 01683 long trust_level) 01684 { 01685 gpgme_ctx_t ctx = get_gpgme_ctx(); 01686 gpgme_error_t err; 01687 gpgme_data_t out = NULL; 01688 gpgme_key_t key = NULL; 01689 FB::VariantMap result; 01690 current_uid = i_to_str(sign_uid); 01691 01692 /* set the default key to the with_keyid 01693 gpgSetPreference returns the orginal value (if any) of 01694 the 'default-key' configuration parameter. We will put 01695 this into a variable so we can restore the setting when 01696 our UID Signing operation is complete (or failed) 01697 */ 01698 01699 /* collect the original value so we can restore when done */ 01700 std::string original_value = get_preference("default-key"); 01701 webpgPluginAPI::gpgSetPreference("default-key", 01702 (char *) with_keyid.c_str()); 01703 01704 /* Release the context and create it again to catch the changes */ 01705 gpgme_release (ctx); 01706 ctx = get_gpgme_ctx(); 01707 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 01708 if (err != GPG_ERR_NO_ERROR) 01709 result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01710 01711 err = gpgme_op_keylist_next (ctx, &key); 01712 if (err != GPG_ERR_NO_ERROR) 01713 result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01714 01715 err = gpgme_op_keylist_end (ctx); 01716 if (err != GPG_ERR_NO_ERROR) 01717 result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01718 01719 err = gpgme_data_new (&out); 01720 if (err != GPG_ERR_NO_ERROR) 01721 result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01722 01723 edit_status = "gpgSignUID(keyid='" + keyid + "', sign_uid='" + i_to_str(sign_uid) + 01724 "', with_keyid='" + with_keyid + "', local_only='" + i_to_str(local_only) + "', trust_sign='" + 01725 i_to_str(trust_sign) + "', trust_level='" + i_to_str(trust_level) + "');\n"; 01726 err = gpgme_op_edit (ctx, key, edit_fnc_sign, out, out); 01727 if (err != GPG_ERR_NO_ERROR) { 01728 if (err == GPGME_STATUS_ALREADY_SIGNED) { 01729 result = get_error_map(__func__, err, "The selected UID has already been signed with this key.", __LINE__, __FILE__); 01730 } else if (err == GPGME_STATUS_KEYEXPIRED) { 01731 result = get_error_map(__func__, err, "This key is expired; You cannot sign using an expired key.", __LINE__, __FILE__); 01732 } else if (err == GPGME_STATUS_SIGEXPIRED) { 01733 result = get_error_map(__func__, err, "This key is expired; You cannot sign using an expired key.", __LINE__, __FILE__); 01734 } else { 01735 result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01736 } 01737 } 01738 01739 /* if the original value was not empty, reset it to the previous value */ 01740 if (strcmp ((char *) original_value.c_str(), "0")) { 01741 webpgPluginAPI::gpgSetPreference("default-key", original_value); 01742 } 01743 01744 FB::VariantMap response; 01745 response["error"] = false; 01746 response["result"] = "success"; 01747 01748 gpgme_data_release (out); 01749 gpgme_key_unref (key); 01750 gpgme_release (ctx); 01751 01752 if (result.size()) 01753 return result; 01754 01755 return response; 01756 } 01757 01765 FB::variant webpgPluginAPI::gpgEnableKey(const std::string& keyid) 01766 { 01767 gpgme_ctx_t ctx = get_gpgme_ctx(); 01768 gpgme_error_t err; 01769 gpgme_data_t out = NULL; 01770 gpgme_key_t key = NULL; 01771 FB::VariantMap response; 01772 01773 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 01774 if (err != GPG_ERR_NO_ERROR) 01775 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01776 01777 err = gpgme_op_keylist_next (ctx, &key); 01778 if (err != GPG_ERR_NO_ERROR) 01779 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01780 01781 err = gpgme_op_keylist_end (ctx); 01782 if (err != GPG_ERR_NO_ERROR) 01783 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01784 01785 err = gpgme_data_new (&out); 01786 if (err != GPG_ERR_NO_ERROR) 01787 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01788 01789 edit_status = "gpgEnableKey(keyid='" + keyid + "');\n"; 01790 err = gpgme_op_edit (ctx, key, edit_fnc_enable, out, out); 01791 if (err != GPG_ERR_NO_ERROR) 01792 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01793 01794 gpgme_data_release (out); 01795 gpgme_key_unref (key); 01796 gpgme_release (ctx); 01797 01798 response["error"] = false; 01799 response["result"] = "key enabled"; 01800 01801 return response; 01802 } 01803 01811 FB::variant webpgPluginAPI::gpgDisableKey(const std::string& keyid) 01812 { 01813 gpgme_ctx_t ctx = get_gpgme_ctx(); 01814 gpgme_error_t err; 01815 gpgme_data_t out = NULL; 01816 gpgme_key_t key = NULL; 01817 FB::VariantMap response; 01818 01819 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 01820 if (err != GPG_ERR_NO_ERROR) 01821 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01822 01823 err = gpgme_op_keylist_next (ctx, &key); 01824 if (err != GPG_ERR_NO_ERROR) 01825 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01826 01827 err = gpgme_op_keylist_end (ctx); 01828 if (err != GPG_ERR_NO_ERROR) 01829 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01830 01831 err = gpgme_data_new (&out); 01832 if (err != GPG_ERR_NO_ERROR) 01833 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01834 01835 edit_status = "gpgDisableKey(keyid='" + keyid + "');\n"; 01836 err = gpgme_op_edit (ctx, key, edit_fnc_disable, out, out); 01837 if (err != GPG_ERR_NO_ERROR) 01838 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01839 01840 gpgme_data_release (out); 01841 gpgme_key_unref (key); 01842 gpgme_release (ctx); 01843 01844 response["error"] = false; 01845 response["result"] = "key disabled"; 01846 01847 return response; 01848 01849 } 01850 01860 FB::variant webpgPluginAPI::gpgDeleteUIDSign(const std::string& keyid, 01861 long uid, long signature) 01862 { 01863 gpgme_ctx_t ctx = get_gpgme_ctx(); 01864 gpgme_error_t err; 01865 gpgme_data_t out = NULL; 01866 gpgme_key_t key = NULL; 01867 FB::VariantMap response; 01868 01869 current_uid = i_to_str(uid); 01870 current_sig = i_to_str(signature); 01871 01872 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 01873 if (err != GPG_ERR_NO_ERROR) 01874 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01875 01876 err = gpgme_op_keylist_next (ctx, &key); 01877 if (err != GPG_ERR_NO_ERROR) 01878 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01879 01880 err = gpgme_op_keylist_end (ctx); 01881 if (err != GPG_ERR_NO_ERROR) 01882 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01883 01884 err = gpgme_data_new (&out); 01885 if (err != GPG_ERR_NO_ERROR) 01886 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01887 01888 edit_status = "gpgDeleteUIDSign(keyid='" + keyid + "', uid='" + i_to_str(uid) + "', signature='" + 01889 i_to_str(signature) + "');\n"; 01890 err = gpgme_op_edit (ctx, key, edit_fnc_delsign, out, out); 01891 if (err != GPG_ERR_NO_ERROR) 01892 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 01893 01894 current_uid = "0"; 01895 current_sig = "0"; 01896 01897 gpgme_data_release (out); 01898 gpgme_key_unref (key); 01899 gpgme_release (ctx); 01900 01901 response["error"] = false; 01902 response["result"] = "signature deleted"; 01903 01904 return response; 01905 } 01906 01919 void webpgPluginAPI::progress_cb(void *self, const char *what, int type, int current, int total) 01920 { 01921 if (!strcmp (what, "primegen") && !current && !total 01922 && (type == '.' || type == '+' || type == '!' 01923 || type == '^' || type == '<' || type == '>')) { 01924 webpgPluginAPI* API = (webpgPluginAPI*) self; 01925 API->FireEvent("onkeygenprogress", FB::variant_list_of(type)); 01926 } 01927 if (!strcmp (what, "complete")) { 01928 webpgPluginAPI* API = (webpgPluginAPI*) self; 01929 API->FireEvent("onkeygencomplete", FB::variant_list_of("complete")); 01930 } 01931 } 01932 01960 std::string webpgPluginAPI::gpgGenKeyWorker(const std::string& key_type, const std::string& key_length, 01961 const std::string& subkey_type, const std::string& subkey_length, const std::string& name_real, 01962 const std::string& name_comment, const std::string& name_email, const std::string& expire_date, 01963 const std::string& passphrase, void* APIObj, 01964 void(*cb_status)( 01965 void *self, 01966 const char *what, 01967 int type, 01968 int current, 01969 int total 01970 ) 01971 ) 01972 { 01973 01974 gpgme_ctx_t ctx = get_gpgme_ctx(); 01975 gpgme_error_t err; 01976 std::string params = "<GnupgKeyParms format=\"internal\">\n" 01977 "Key-Type: " + key_type + "\n" 01978 "Key-Length: " + key_length + "\n" 01979 "Subkey-Type: " + subkey_type + "\n" 01980 "Subkey-Length: " + subkey_length + "\n" 01981 "Name-Real: " + name_real + "\n"; 01982 if (name_comment.length() > 0) { 01983 params += "Name-Comment: " + name_comment + "\n"; 01984 } 01985 if (name_email.length() > 0) { 01986 params += "Name-Email: " + name_email + "\n"; 01987 } 01988 if (expire_date.length() > 0) { 01989 params += "Expire-Date: " + expire_date + "\n"; 01990 } else { 01991 params += "Expire-Date: 0\n"; 01992 } 01993 if (passphrase.length() > 0) { 01994 params += "Passphrase: " + passphrase + "\n"; 01995 } 01996 params += "</GnupgKeyParms>\n"; 01997 const char *parms = params.c_str(); 01998 01999 gpgme_genkey_result_t result; 02000 02001 gpgme_set_progress_cb (ctx, cb_status, APIObj); 02002 02003 err = gpgme_op_genkey (ctx, parms, NULL, NULL); 02004 if (err) 02005 return "Error with genkey start" + err; 02006 02007 result = gpgme_op_genkey_result (ctx); 02008 02009 if (!result) 02010 { 02011 #ifdef DEBUG 02012 fprintf (stderr, "%s:%d: gpgme_op_genkey_result returns NULL\n", 02013 __FILE__, __LINE__); 02014 #endif 02015 return "error with result"; 02016 } 02017 02018 #ifdef DEBUG 02019 printf ("Generated key: %s (%s)\n", result->fpr ? result->fpr : "none", 02020 result->primary ? (result->sub ? "primary, sub" : "primary") 02021 : (result->sub ? "sub" : "none")); 02022 #endif 02023 02024 gpgme_release (ctx); 02025 const char* status = (char *) "complete"; 02026 cb_status(APIObj, status, 33, 33, 33); 02027 return "done"; 02028 } 02029 02054 FB::variant webpgPluginAPI::gpgGenSubKeyWorker(const std::string& keyid, const std::string& subkey_type, 02055 const std::string& subkey_length, const std::string& subkey_expire, bool sign_flag, 02056 bool enc_flag, bool auth_flag, void* APIObj, 02057 void(*cb_status)( 02058 void *self, 02059 const char *what, 02060 int type, 02061 int current, 02062 int total 02063 ) 02064 ) 02065 { 02066 02067 // Set the option expert so we can access all of the subkey types 02068 setTempGPGOption("expert", ""); 02069 02070 gpgme_ctx_t ctx = get_gpgme_ctx(); 02071 gpgme_error_t err; 02072 gpgme_data_t out = NULL; 02073 gpgme_key_t key = NULL; 02074 FB::VariantMap response; 02075 02076 gen_subkey_type = subkey_type; 02077 gen_subkey_length = subkey_length; 02078 gen_subkey_expire = subkey_expire; 02079 gen_sign_flag = sign_flag; 02080 gen_enc_flag = enc_flag; 02081 gen_auth_flag = auth_flag; 02082 02083 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 02084 if (err != GPG_ERR_NO_ERROR) 02085 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02086 02087 err = gpgme_op_keylist_next (ctx, &key); 02088 if (err != GPG_ERR_NO_ERROR) 02089 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02090 02091 err = gpgme_op_keylist_end (ctx); 02092 if (err != GPG_ERR_NO_ERROR) 02093 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02094 02095 err = gpgme_data_new (&out); 02096 if (err != GPG_ERR_NO_ERROR) 02097 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02098 02099 gpgme_set_progress_cb (ctx, cb_status, APIObj); 02100 02101 edit_status = "gpgGenSubKeyWorker(keyid='" + keyid + "', subkey_type='" + subkey_type + 02102 "', subkey_length='" + subkey_length + "', subkey_expire='" + subkey_expire + "', sign_flag='" + 02103 i_to_str(sign_flag) + "', enc_flag='" + i_to_str(enc_flag) + "', auth_flag='" + 02104 i_to_str(auth_flag) + "');\n"; 02105 err = gpgme_op_edit (ctx, key, edit_fnc_add_subkey, out, out); 02106 02107 if (err != GPG_ERR_NO_ERROR) { 02108 if (gpg_err_code(err) == GPG_ERR_CANCELED) 02109 this->FireEvent("onkeygencomplete", FB::variant_list_of("failed: cancelled")); 02110 else if (gpg_err_code(err) == GPG_ERR_BAD_PASSPHRASE) 02111 this->FireEvent("onkeygencomplete", FB::variant_list_of("failed: bad passphrase")); 02112 02113 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02114 } 02115 02116 gpgme_data_release (out); 02117 gpgme_key_unref (key); 02118 gpgme_release (ctx); 02119 02120 // Restore the options to normal 02121 restoreGPGConfig(); 02122 02123 const char* status = (char *) "complete"; 02124 cb_status(APIObj, status, 33, 33, 33); 02125 return "done"; 02126 } 02127 02135 void webpgPluginAPI::threaded_gpgGenKey(genKeyParams params) 02136 { 02137 std::string result = webpgPluginAPI::gpgGenKeyWorker(params.key_type, params.key_length, 02138 params.subkey_type, params.subkey_length, params.name_real, 02139 params.name_comment, params.name_email, params.expire_date, 02140 params.passphrase, this, &webpgPluginAPI::progress_cb 02141 ); 02142 02143 } 02144 02152 void webpgPluginAPI::threaded_gpgGenSubKey(genSubKeyParams params) 02153 { 02154 FB::variant result = webpgPluginAPI::gpgGenSubKeyWorker(params.keyid, params.subkey_type, 02155 params.subkey_length, params.subkey_expire, params.sign_flag, params.enc_flag, 02156 params.auth_flag, this, &webpgPluginAPI::progress_cb 02157 ); 02158 02159 } 02160 02179 std::string webpgPluginAPI::gpgGenKey(const std::string& key_type, 02180 const std::string& key_length, const std::string& subkey_type, 02181 const std::string& subkey_length, const std::string& name_real, 02182 const std::string& name_comment, const std::string& name_email, 02183 const std::string& expire_date, const std::string& passphrase) 02184 { 02185 02186 genKeyParams params; 02187 02188 params.key_type = key_type; 02189 params.key_length = key_length; 02190 params.subkey_type = subkey_type; 02191 params.subkey_length = subkey_length; 02192 params.name_real = name_real; 02193 params.name_comment = name_comment; 02194 params.name_email = name_email; 02195 params.expire_date = expire_date; 02196 params.passphrase = passphrase; 02197 02198 boost::thread genkey_thread( 02199 boost::bind( 02200 &webpgPluginAPI::genKeyThreadCaller, 02201 this, params) 02202 ); 02203 02204 return "queued"; 02205 } 02206 02214 FB::variant webpgPluginAPI::gpgImportKey(const std::string& ascii_key) 02215 { 02216 gpgme_ctx_t ctx = get_gpgme_ctx(); 02217 gpgme_error_t err; 02218 gpgme_data_t key_buf; 02219 gpgme_import_result_t result; 02220 02221 err = gpgme_data_new_from_mem (&key_buf, ascii_key.c_str(), ascii_key.length(), 1); 02222 02223 err = gpgme_op_import (ctx, key_buf); 02224 02225 result = gpgme_op_import_result (ctx); 02226 gpgme_data_release (key_buf); 02227 02228 FB::VariantMap status; 02229 02230 status["considered"] = result->considered; 02231 status["no_user_id"] = result->no_user_id; 02232 status["imported"] = result->imported; 02233 status["imported_rsa"] = result->imported_rsa; 02234 status["new_user_ids"] = result->new_user_ids; 02235 status["new_sub_keys"] = result->new_sub_keys; 02236 status["new_signatures"] = result->new_signatures; 02237 status["new_revocations"] = result->new_revocations; 02238 status["secret_read"] = result->secret_read; 02239 status["secret_imported"] = result->secret_imported; 02240 status["secret_unchanged"] = result->secret_unchanged; 02241 status["not_imported"] = result->not_imported; 02242 02243 FB::VariantMap imports_map; 02244 int nimports = 0; 02245 gpgme_import_status_t import; 02246 for (nimports=0, import=result->imports; import; import = import->next, nimports++) { 02247 FB::VariantMap import_item_map; 02248 import_item_map["fingerprint"] = nonnull (import->fpr); 02249 import_item_map["result"] = gpgme_strerror(import->result); 02250 import_item_map["status"] = import->status; 02251 import_item_map["new_key"] = import->status & GPGME_IMPORT_NEW? true : false; 02252 import_item_map["new_uid"] = import->status & GPGME_IMPORT_UID? true : false; 02253 import_item_map["new_sig"] = import->status & GPGME_IMPORT_SIG? true : false; 02254 import_item_map["new_subkey"] = import->status & GPGME_IMPORT_SUBKEY? true : false; 02255 import_item_map["new_secret"] = import->status & GPGME_IMPORT_SECRET? true : false; 02256 imports_map[i_to_str(nimports)] = import_item_map; 02257 } 02258 status["imports"] = imports_map; 02259 gpgme_release (ctx); 02260 02261 return status; 02262 } 02263 02271 FB::variant webpgPluginAPI::gpgDeleteKey(const std::string& keyid, int allow_secret) 02272 { 02273 gpgme_ctx_t ctx = get_gpgme_ctx(); 02274 gpgme_error_t err; 02275 gpgme_key_t key = NULL; 02276 FB::VariantMap response; 02277 02278 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 02279 if (err != GPG_ERR_NO_ERROR) 02280 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02281 02282 err = gpgme_op_keylist_next (ctx, &key); 02283 if (err != GPG_ERR_NO_ERROR) 02284 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02285 02286 err = gpgme_op_keylist_end (ctx); 02287 if (err != GPG_ERR_NO_ERROR) 02288 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02289 02290 err = gpgme_op_delete(ctx, key, allow_secret); 02291 if (err != GPG_ERR_NO_ERROR) 02292 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02293 02294 gpgme_key_unref (key); 02295 gpgme_release (ctx); 02296 02297 response["error"] = false; 02298 response["result"] = "Key deleted"; 02299 02300 return response; 02301 } 02302 02303 /* 02304 This method executes webpgPlugin.gpgDeleteKey with the allow_secret=0, 02305 which allows it to only delete public Public Keys from the keyring. 02306 */ 02314 FB::variant webpgPluginAPI::gpgDeletePublicKey(const std::string& keyid) 02315 { 02316 return webpgPluginAPI::gpgDeleteKey(keyid, 0); 02317 } 02318 02326 FB::variant webpgPluginAPI::gpgDeletePrivateKey(const std::string& keyid) 02327 { 02328 return webpgPluginAPI::gpgDeleteKey(keyid, 1); 02329 } 02330 02339 FB::variant webpgPluginAPI::gpgDeletePrivateSubKey(const std::string& keyid, int key_idx) 02340 { 02341 gpgme_ctx_t ctx = get_gpgme_ctx(); 02342 gpgme_error_t err; 02343 gpgme_data_t out = NULL; 02344 gpgme_key_t key = NULL; 02345 FB::VariantMap response; 02346 02347 key_index = i_to_str(key_idx); 02348 02349 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 02350 if (err != GPG_ERR_NO_ERROR) 02351 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02352 02353 err = gpgme_op_keylist_next (ctx, &key); 02354 if (err != GPG_ERR_NO_ERROR) 02355 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02356 02357 err = gpgme_op_keylist_end (ctx); 02358 if (err != GPG_ERR_NO_ERROR) 02359 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02360 02361 err = gpgme_data_new (&out); 02362 if (err != GPG_ERR_NO_ERROR) 02363 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02364 02365 edit_status = "gpgDeletePrivateSubkey(keyid='" + keyid + "', key_idx='" + i_to_str(key_idx) + 02366 "');\n"; 02367 err = gpgme_op_edit (ctx, key, edit_fnc_delete_subkey, out, out); 02368 if (err != GPG_ERR_NO_ERROR) 02369 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02370 02371 02372 key_index = ""; 02373 02374 gpgme_data_release (out); 02375 gpgme_key_unref (key); 02376 gpgme_release (ctx); 02377 02378 response["error"] = false; 02379 response["edit_status"] = edit_status; 02380 response["result"] = "Subkey Delete"; 02381 02382 return response; 02383 } 02384 02400 FB::variant webpgPluginAPI::gpgGenSubKey(const std::string& keyid, 02401 const std::string& subkey_type, const std::string& subkey_length, 02402 const std::string& subkey_expire, bool sign_flag, bool enc_flag, bool auth_flag) 02403 { 02404 02405 genSubKeyParams params; 02406 02407 params.keyid = keyid; 02408 params.subkey_type = subkey_type; 02409 params.subkey_length = subkey_length; 02410 params.subkey_expire = subkey_expire; 02411 params.sign_flag = sign_flag; 02412 params.enc_flag = enc_flag; 02413 params.auth_flag = auth_flag; 02414 02415 boost::thread genkey_thread( 02416 boost::bind( 02417 &webpgPluginAPI::genSubKeyThreadCaller, 02418 this, params) 02419 ); 02420 02421 return "queued"; 02422 } 02423 02432 FB::variant webpgPluginAPI::gpgSetKeyTrust(const std::string& keyid, long trust_level) 02433 { 02434 gpgme_ctx_t ctx = get_gpgme_ctx(); 02435 gpgme_error_t err; 02436 gpgme_data_t out = NULL; 02437 gpgme_key_t key = NULL; 02438 FB::VariantMap response; 02439 trust_assignment = i_to_str(trust_level); 02440 02441 if (trust_level < 1) { 02442 response["error"] = true; 02443 response["result"] = "Valid trust assignment values are 1 through 5"; 02444 return response; 02445 } 02446 02447 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 02448 if (err != GPG_ERR_NO_ERROR) 02449 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02450 02451 err = gpgme_op_keylist_next (ctx, &key); 02452 if (err != GPG_ERR_NO_ERROR) 02453 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02454 02455 err = gpgme_op_keylist_end (ctx); 02456 if (err != GPG_ERR_NO_ERROR) 02457 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02458 02459 err = gpgme_data_new (&out); 02460 if (err != GPG_ERR_NO_ERROR) 02461 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02462 02463 edit_status = "gpgSetKeyTrust(keyid='" + keyid + "', trust_level='" + i_to_str(trust_level) + "');\n"; 02464 err = gpgme_op_edit (ctx, key, edit_fnc_assign_trust, out, out); 02465 if (err != GPG_ERR_NO_ERROR) 02466 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02467 02468 trust_assignment = "0"; 02469 02470 gpgme_data_release (out); 02471 gpgme_key_unref (key); 02472 gpgme_release (ctx); 02473 02474 response["error"] = false; 02475 response["result"] = "trust value assigned"; 02476 02477 return response; 02478 } 02479 02491 FB::variant webpgPluginAPI::gpgAddUID(const std::string& keyid, const std::string& name, 02492 const std::string& email, const std::string& comment) 02493 { 02494 gpgme_ctx_t ctx = get_gpgme_ctx(); 02495 gpgme_error_t err; 02496 gpgme_data_t out = NULL; 02497 gpgme_key_t key = NULL; 02498 FB::VariantMap response; 02499 genuid_name = name; 02500 genuid_email = email; 02501 genuid_comment = comment; 02502 02503 if (isdigit(name.c_str()[0])) { 02504 response["error"] = true; 02505 response["result"] = "UID names cannot start with a digit..."; 02506 return response; 02507 } 02508 02509 if (strlen (name.c_str()) < 5) { 02510 response["error"] = true; 02511 response["result"] = "UID's must be at least 5 chars long..."; 02512 return response; 02513 } 02514 02515 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 02516 if (err != GPG_ERR_NO_ERROR) 02517 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02518 02519 err = gpgme_op_keylist_next (ctx, &key); 02520 if (err != GPG_ERR_NO_ERROR) 02521 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02522 02523 err = gpgme_op_keylist_end (ctx); 02524 if (err != GPG_ERR_NO_ERROR) 02525 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02526 02527 err = gpgme_data_new (&out); 02528 if (err != GPG_ERR_NO_ERROR) 02529 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02530 02531 edit_status = "gpgAddUID(keyid='" + keyid + "', name='" + name + "', email='" + email + 02532 "', comment='" + comment + "');\n"; 02533 err = gpgme_op_edit (ctx, key, edit_fnc_add_uid, out, out); 02534 if (err != GPG_ERR_NO_ERROR) 02535 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02536 02537 response["name"] = genuid_name; 02538 response["email"] = genuid_email; 02539 response["comment"] = genuid_comment; 02540 02541 genuid_name = ""; 02542 genuid_email = ""; 02543 genuid_comment = ""; 02544 02545 gpgme_data_release (out); 02546 gpgme_key_unref (key); 02547 gpgme_release (ctx); 02548 02549 response["error"] = false; 02550 response["edit_status"] = edit_status; 02551 response["result"] = "UID added"; 02552 02553 return response; 02554 } 02555 02564 FB::variant webpgPluginAPI::gpgDeleteUID(const std::string& keyid, long uid_idx) 02565 { 02566 gpgme_ctx_t ctx = get_gpgme_ctx(); 02567 gpgme_error_t err; 02568 gpgme_data_t out = NULL; 02569 gpgme_key_t key = NULL; 02570 FB::VariantMap response; 02571 02572 if (uid_idx < 1) { 02573 response["error"] = true; 02574 response["result"] = "UID index is always above zero, something is amiss..."; 02575 return response; 02576 } 02577 02578 current_uid = i_to_str(uid_idx); 02579 02580 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 02581 if (err != GPG_ERR_NO_ERROR) 02582 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02583 02584 err = gpgme_op_keylist_next (ctx, &key); 02585 if (err != GPG_ERR_NO_ERROR) 02586 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02587 02588 err = gpgme_op_keylist_end (ctx); 02589 if (err != GPG_ERR_NO_ERROR) 02590 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02591 02592 err = gpgme_data_new (&out); 02593 if (err != GPG_ERR_NO_ERROR) 02594 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02595 02596 edit_status = "gpgDeleteUID(keyid='" + keyid + "', uid_idx='" + i_to_str(uid_idx) + "');\n"; 02597 err = gpgme_op_edit (ctx, key, edit_fnc_delete_uid, out, out); 02598 if (err != GPG_ERR_NO_ERROR) 02599 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02600 02601 02602 current_uid = "0"; 02603 02604 gpgme_data_release (out); 02605 gpgme_key_unref (key); 02606 gpgme_release (ctx); 02607 02608 response["error"] = false; 02609 response["edit_status"] = edit_status; 02610 response["result"] = "UID deleted"; 02611 02612 return response; 02613 } 02614 02623 FB::variant webpgPluginAPI::gpgSetPrimaryUID(const std::string& keyid, long uid_idx) 02624 { 02625 gpgme_ctx_t ctx = get_gpgme_ctx(); 02626 gpgme_error_t err; 02627 gpgme_data_t out = NULL; 02628 gpgme_key_t key = NULL; 02629 FB::VariantMap response; 02630 02631 if (uid_idx < 1) { 02632 response["error"] = true; 02633 response["result"] = "UID index is always above zero, something is amiss..."; 02634 return response; 02635 } 02636 02637 current_uid = i_to_str(uid_idx); 02638 02639 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 02640 if (err != GPG_ERR_NO_ERROR) 02641 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02642 02643 err = gpgme_op_keylist_next (ctx, &key); 02644 if (err != GPG_ERR_NO_ERROR) 02645 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02646 02647 err = gpgme_op_keylist_end (ctx); 02648 if (err != GPG_ERR_NO_ERROR) 02649 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02650 02651 err = gpgme_data_new (&out); 02652 if (err != GPG_ERR_NO_ERROR) 02653 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02654 02655 edit_status = "gpgSetPrimaryUID(keyid='" + keyid + "', uid_idx='" + i_to_str(uid_idx) + "');\n"; 02656 err = gpgme_op_edit (ctx, key, edit_fnc_set_primary_uid, out, out); 02657 if (err != GPG_ERR_NO_ERROR) 02658 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02659 02660 02661 current_uid = "0"; 02662 02663 gpgme_data_release (out); 02664 gpgme_key_unref (key); 02665 gpgme_release (ctx); 02666 02667 response["error"] = false; 02668 response["edit_status"] = edit_status; 02669 response["result"] = "Primary UID changed"; 02670 02671 return response; 02672 } 02673 02683 FB::variant webpgPluginAPI::gpgSetKeyExpire(const std::string& keyid, long key_idx, long expire) 02684 { 02685 gpgme_ctx_t ctx = get_gpgme_ctx(); 02686 gpgme_error_t err; 02687 gpgme_data_t out = NULL; 02688 gpgme_key_t key = NULL; 02689 FB::VariantMap response; 02690 02691 key_index = i_to_str(key_idx); 02692 expiration = i_to_str(expire); 02693 02694 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 02695 if (err != GPG_ERR_NO_ERROR) 02696 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02697 02698 err = gpgme_op_keylist_next (ctx, &key); 02699 if (err != GPG_ERR_NO_ERROR) 02700 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02701 02702 err = gpgme_op_keylist_end (ctx); 02703 if (err != GPG_ERR_NO_ERROR) 02704 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02705 02706 err = gpgme_data_new (&out); 02707 if (err != GPG_ERR_NO_ERROR) 02708 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02709 02710 edit_status = "gpgSetKeyExpire(keyid='" + keyid + "', key_idx='" + i_to_str(key_idx) + 02711 "', expire='" + i_to_str(expire) + "');\n"; 02712 err = gpgme_op_edit (ctx, key, edit_fnc_set_key_expire, out, out); 02713 if (err != GPG_ERR_NO_ERROR) 02714 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02715 02716 02717 key_index = ""; 02718 expiration = ""; 02719 02720 gpgme_data_release (out); 02721 gpgme_key_unref (key); 02722 gpgme_release (ctx); 02723 02724 response["error"] = false; 02725 response["edit_status"] = edit_status; 02726 response["result"] = "Expiration changed"; 02727 02728 return response; 02729 } 02730 02739 FB::variant webpgPluginAPI::gpgSetPubkeyExpire(const std::string& keyid, long expire) 02740 { 02741 return webpgPluginAPI::gpgSetKeyExpire(keyid, 0, expire); 02742 } 02743 02753 FB::variant webpgPluginAPI::gpgSetSubkeyExpire(const std::string& keyid, long key_idx, long expire) 02754 { 02755 return webpgPluginAPI::gpgSetKeyExpire(keyid, key_idx, expire); 02756 } 02757 02766 02780 02781 FB::variant webpgPluginAPI::gpgExportPublicKey(const std::string& keyid) 02782 { 02783 gpgme_ctx_t ctx = get_gpgme_ctx(); 02784 gpgme_error_t err; 02785 gpgme_data_t out = NULL; 02786 FB::variant keydata; 02787 FB::VariantMap response; 02788 02789 err = gpgme_data_new (&out); 02790 if (err != GPG_ERR_NO_ERROR) 02791 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02792 02793 err = gpgme_op_export (ctx, keyid.c_str(), 0, out); 02794 if (err != GPG_ERR_NO_ERROR) 02795 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02796 02797 gpgme_data_seek(out, 0, SEEK_SET); 02798 02799 size_t out_size = 0; 02800 std::string out_buf; 02801 out_buf = gpgme_data_release_and_get_mem (out, &out_size); 02802 /* strip the size_t data out of the output buffer */ 02803 out_buf = out_buf.substr(0, out_size); 02804 /* set the output object to NULL since it has 02805 already been released */ 02806 out = NULL; 02807 02808 gpgme_release (ctx); 02809 02810 response["error"] = false; 02811 response["result"] = out_buf; 02812 02813 return response; 02814 } 02815 02830 FB::variant webpgPluginAPI::gpgRevokeItem(const std::string& keyid, const std::string& item, int key_idx, 02831 int uid_idx, int sig_idx, int reason, const std::string& desc) 02832 { 02833 02834 gpgme_ctx_t ctx = get_gpgme_ctx(); 02835 gpgme_error_t err; 02836 gpgme_data_t out = NULL; 02837 gpgme_key_t key = NULL; 02838 FB::VariantMap response; 02839 02840 key_index = i_to_str(key_idx); 02841 current_uid = i_to_str(uid_idx); 02842 current_sig = i_to_str(sig_idx); 02843 revitem = item.c_str(); 02844 reason_index = i_to_str(reason); 02845 description = desc.c_str(); 02846 02847 02848 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 02849 if (err != GPG_ERR_NO_ERROR) 02850 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02851 02852 err = gpgme_op_keylist_next (ctx, &key); 02853 if (err != GPG_ERR_NO_ERROR) 02854 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02855 02856 err = gpgme_op_keylist_end (ctx); 02857 if (err != GPG_ERR_NO_ERROR) 02858 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02859 02860 err = gpgme_data_new (&out); 02861 if (err != GPG_ERR_NO_ERROR) 02862 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02863 02864 edit_status = "gpgRevokeItem(keyid='" + keyid + "', item='" + item + "', key_idx='" + 02865 i_to_str(key_idx) + "', uid_idx='" + i_to_str(uid_idx) + "', sig_idx='" + i_to_str(sig_idx) + 02866 "', reason='" + i_to_str(reason) + "', desc='" + desc + "');\n"; 02867 err = gpgme_op_edit (ctx, key, edit_fnc_revoke_item, out, out); 02868 if (err != GPG_ERR_NO_ERROR) 02869 return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02870 02871 02872 key_index = ""; 02873 reason_index = ""; 02874 current_uid = ""; 02875 02876 gpgme_data_release (out); 02877 gpgme_key_unref (key); 02878 gpgme_release (ctx); 02879 02880 response["error"] = false; 02881 response["edit_status"] = edit_status; 02882 response["result"] = "Item Revoked"; 02883 02884 return response; 02885 } 02886 02898 FB::variant webpgPluginAPI::gpgRevokeKey(const std::string& keyid, int key_idx, int reason, 02899 const std::string &desc) 02900 { 02901 return webpgPluginAPI::gpgRevokeItem(keyid, "revkey", key_idx, 0, 0, reason, desc); 02902 } 02903 02915 FB::variant webpgPluginAPI::gpgRevokeUID(const std::string& keyid, int uid_idx, int reason, 02916 const std::string &desc) 02917 { 02918 return webpgPluginAPI::gpgRevokeItem(keyid, "revuid", 0, uid_idx, 0, reason, desc); 02919 } 02920 02933 FB::variant webpgPluginAPI::gpgRevokeSignature(const std::string& keyid, int uid_idx, int sig_idx, 02934 int reason, const std::string &desc) 02935 { 02936 return webpgPluginAPI::gpgRevokeItem(keyid, "revsig", 0, uid_idx, sig_idx, reason, desc); 02937 } 02938 02946 FB::variant webpgPluginAPI::gpgChangePassphrase(const std::string& keyid) 02947 { 02948 gpgme_ctx_t ctx = get_gpgme_ctx(); 02949 gpgme_error_t err; 02950 gpgme_data_t out = NULL; 02951 gpgme_key_t key = NULL; 02952 FB::VariantMap result; 02953 02954 err = gpgme_op_keylist_start (ctx, keyid.c_str(), 0); 02955 if (err != GPG_ERR_NO_ERROR) 02956 result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02957 02958 err = gpgme_op_keylist_next (ctx, &key); 02959 if (err != GPG_ERR_NO_ERROR) 02960 result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02961 02962 err = gpgme_op_keylist_end (ctx); 02963 if (err != GPG_ERR_NO_ERROR) 02964 result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02965 02966 err = gpgme_data_new (&out); 02967 if (err != GPG_ERR_NO_ERROR) 02968 result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02969 02970 edit_status = "gpgChangePassphrase(keyid='" + keyid + "');\n"; 02971 err = gpgme_op_edit (ctx, key, edit_fnc_change_passphrase, out, out); 02972 if (err != GPG_ERR_NO_ERROR) 02973 result = get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__); 02974 02975 FB::VariantMap response; 02976 if (!key->secret) { 02977 response["error"] = true; 02978 response["result"] = "no secret"; 02979 } else { 02980 response["error"] = false; 02981 response["result"] = "success"; 02982 } 02983 02984 gpgme_data_release (out); 02985 gpgme_key_unref (key); 02986 gpgme_release (ctx); 02987 02988 if (result.size()) 02989 return result; 02990 02991 return response; 02992 } 02993 02999 // Read-only property version 03000 std::string webpgPluginAPI::get_version() 03001 { 03002 return FBSTRING_PLUGIN_VERSION; 03003 } 03004