├── README.md ├── includes └── hooks │ └── namecheapssl_sync.php └── modules ├── addons └── namecheap_ssl │ ├── client_templates │ └── notice.tpl │ ├── namecheap_ssl.php │ └── templates │ ├── default.php │ ├── list.php │ ├── log.php │ ├── settings.php │ └── sync.php └── servers └── namecheapssl ├── lang └── English.php ├── namecheapapi.php ├── namecheaplog.php ├── namecheapssl.php ├── no_approver.tpl ├── reissue_notice.tpl ├── show_validation_file_contents.tpl └── viewdetails.tpl /README.md: -------------------------------------------------------------------------------- 1 | ## Namecheap.com WHMCS SSL Module 2 | 3 | #### Update for WHMCS Namecheap SSL Plugin Users: 4 | 5 | The latest version is stable and works seamlessly with WHMCS 6.x.x, 7.x.x, 8.x.x. 6 | Further development of the WHMCS Namecheap SSL Plugin has stopped because user uptake is low. 7 | If you experience any problems with plugin performance, [Contact Us](https://www.namecheap.com/support/live-chat/ssl/). 8 | You can also find more user info [Here](https://www.namecheap.com/support/knowledgebase/subcategory.aspx/2196/whmcs-module-for-ssl). 9 | 10 | ##### Updated on May 18 2018 to version 1.6.7 11 | - Security changes: escaped all variables in SQL queries and templates 12 | - Fixed bug with duplicate configuration email after addon reactivation 13 | - Fixed bug with revoke function 14 | 15 | ##### Updated on September 7, 2017, to version 1.6.6 for WHMCS 7.x 16 | - Minor fixes according to changes in API 17 | - mysql_ functions removed, support of MySQLi extension added 18 | 19 | ##### Updated on March 28, 2016 to version 1.6.5 for WHMCS 6.x 20 | 21 | - Fixed bug with approver emails for Symantec OV and EV certificates 22 | - Added notification about latin characters to the first certificate activation page 23 | - Job/Title set as an obligatory field for Symantec certificates 24 | 25 | ##### Updated on November, 27 2015 to Version 1.6.4 for WHMCS 6.x 26 | 27 | - Removed email and HTTP validation for Symantec OV and EV certificates 28 | - Added product due date synchronization offset in settings section of addon 29 | - Simplified domain validation choice for Symantec DV certificates reissue 30 | 31 | ##### Updated on December 15, 2014 to Version 1.6.2 for WHMCS 5. 32 | **Important information:** Previous versions of WHMCS SSL Module contained a bug that could potentially affect clients that resell Multi-domain SSL certificates using WHMCS module. Please check details of the bug and how it might have affected you in the following [knowledgebase article](https://www.namecheap.com/support/knowledgebase/article.aspx/9444/2196/whmcs-ssl-module-bug). 33 | 34 | This bug has been fixed in version 1.6.2 35 | 36 | Other changes: 37 | 38 | - Fixed default number of addon domains for Comodo EV Multi Domain SSL and Multi Domain SSL to 3. 39 | - Fixed approver email resending for GeoTrust DV certificates 40 | - Fixed Organization fields for Comodo EV Multi Domain SSL. 41 | - Fixed issues with Job Title field: Added Job Title to Module Settings and made it required field for Thawte, Symantec and EV GeoTrust certificates. 42 | - Added 15 seconds timeout was implemented for uploading certificate types. 43 | - Added “SourceOfCall” parameter to API calls to Namecheap. 44 | 45 | [Release Notes](https://github.com/namecheap/ssl-whmcs/wiki/Changelog) 46 | 47 | ##### Addon version vs Module version 48 | 49 | Module version is the version of whole current release while "Addon version" is the version of addon file itself. 50 | The version specified in addon settings is version of addon file: 51 | 52 | ![Add-on version](http://files.namecheap.com/images/googlecode/addonversion.jpg) 53 | 54 | In order to check the version of module please open /modules/servers/namecheapssl/namecheapssl.php file on your server: 55 | 56 | ![Module version](http://files.namecheap.com/images/googlecode/moduleversion.png) 57 | 58 | ##### Before you begin 59 | 60 | Namecheap.com SSL module for WHMCS is an open-source plugin that is distributed free of charge. This module allows you to automate SSL Certificate sales with the Namecheap platform. 61 | 62 | **Important:** 63 | 64 | If you have not previously performed the WHMCS "Further Security Steps," please follow the instructions from the WHMCS documentation at http://docs.whmcs.com/Further_Security_Steps to change your WHMCS admin folder name or password-protect the admin directory. These steps mitigate the risk of external cron file abuse from outside your server. 65 | 66 | 67 | ##### Pre-requisites 68 | 69 | - Access to WHMCS admin area. 70 | - An understanding of [Namecheap’s environments](https://www.namecheap.com/support/api/intro.aspx). 71 | - Namecheap account with API access enabled on the desired environment. 72 | 73 | ##### List of supported SSL certificates: 74 | 75 | You will be allowed to resell all of our SSL products: 76 | 77 | **RapidSSL Cerificates:** 78 | 79 | - RapidSSL 80 | - RapidSSL Wildcard 81 | 82 | **GeoTrust Cerificates:** 83 | 84 | - GeoTrust QuickSSL 85 | - GeoTrust QuickSSL Premium 86 | - GeoTrust True BusinessID with EV 87 | - GeoTrust TrueBusinessID 88 | - GeoTrust TrueBusinessID WildCard 89 | - GeoTrust TrueBusinessID Multi Domain 90 | - GeoTrust TrueBusinessID with EV Multi Domain 91 | 92 | **Comodo Certificates:** 93 | 94 | - Comodo PositiveSSL 95 | - Comodo PositiveSSL Wildcard 96 | - Comodo InstantSSL 97 | - Comodo InstantSSL Pro 98 | - Comodo PremiumSSL 99 | - Comodo PremiumSSL Wildcard 100 | - Comodo EssentialSSL 101 | - Comodo EssentialSSL Wildcard 102 | - Comodo EV SSL 103 | - Comodo EV SGC SSL 104 | - Comodo Unified Communications 105 | - Comodo PositiveSSL Multi Domain 106 | 107 | **Symantec Certificates:** 108 | 109 | - Symantec Secure Site 110 | - Symantec Secure Site Pro 111 | - Symantec Secure Site EV 112 | - Symantec Secure Site Pro EV 113 | 114 | **Thawte Certificates:** 115 | 116 | - SSL 123 117 | - Web Server 118 | - Web Server EV 119 | - Supercert 120 | 121 | *** 122 | **Important Note:** You may find ComodoSSL in the list of SSLs during setting up products in WHMCS. ComodoSSL is a test product, it is included in the list of products, but it is not fully supported yet. Please do not set up ComodoSSL Products. 123 | *** 124 | 125 | ##### Sandbox and Production Environments 126 | 127 | Namecheap has a production as well as a test server environment. The test server environment is called Sandbox. We urge you to test the module in our [sandbox environment](http://www.sandbox.namecheap.com), before pointing it to production. It uses same calls as our production environment except that you will not receive actual SSL product in the end of the process and will not be charged real money. Difference between setting product for Sandbox and for production will be described in "Setting up products and pricings" section. 128 | 129 | #####List of certificates supported in Sandbox: 130 | 131 | All of our certificates are supported in sandbox: 132 | 133 | **RapidSSL Cerificates:** 134 | 135 | - RapidSSL 136 | - RapidSSL Wildcard 137 | 138 | **GeoTrust Cerificates:** 139 | 140 | - GeoTrust QuickSSL 141 | - GeoTrust QuickSSL Premium 142 | - GeoTrust True BusinessID with EV 143 | - GeoTrust TrueBusinessID 144 | - GeoTrust TrueBusinessID WildCard 145 | - GeoTrust TrueBusinessID Multi Domain 146 | - GeoTrust TrueBusinessID with EV Multi Domain 147 | 148 | **Symantec Certificates:** 149 | 150 | - Symantec Secure Site 151 | - Symantec Secure Site Pro 152 | - Symantec Secure Site EV 153 | - Symantec Secure Site Pro EV 154 | 155 | **Thawte Certificates:** 156 | 157 | - SSL 123 158 | - Web Server 159 | - Web Server EV 160 | 161 | **Comodo Certificates:** 162 | 163 | - Comodo PositiveSSL 164 | - Comodo PositiveSSL Wildcard 165 | - Comodo InstantSSL 166 | - Comodo InstantSSL Pro 167 | - Comodo PremiumSSL 168 | - Comodo PremiumSSL Wildcard 169 | - Comodo EssentialSSL 170 | - Comodo EssentialSSL Wildcard 171 | - Comodo Unified Communications 172 | - Comodo PositiveSSL Multi Domain 173 | 174 | *** 175 | **Important Note:** Please note that activation of Comodo OV and EV certificates will not lead to receiving test certificate itself, only DCV email will be sent. 176 | *** 177 | 178 | ##### Download and installation 179 | 180 | Installation of our SSLmodule is very simple and takes just a few minutes: 181 | 182 | 1. Download and extract attached archive. It can be downloaded here: https://github.com/namecheap/ssl-whmcs/archive/master.zip. Copy the contents to the root folder of whmcs (folder structure will remain the same). 183 | 184 | 2. Go to 'Setup >Addon Modules' in your WHMCS Admin area and activate the addon. Then go here: 185 | 186 | ![SSL Module Add-on](http://files.namecheap.com/images/googlecode/ssl-module-addon-installation.png) 187 | 188 | The SSL Module Addon installation is now complete. 189 | 190 | *** 191 | **Important Note:** 192 | If you receive any errors or cannot access addon please set up access permissions to addon for everyone as on screenshot: 193 | 194 | ![Access Rights](http://files.namecheap.com/images/googlecode/Access%20Rights.png) 195 | *** 196 | 197 | ##### Setting up products and pricings 198 | 199 | To setup an SSL certificate product, please follow the steps below: 200 | 201 | 1. Create a new product within your WHMCS. 202 | 203 | 2. Ensure the welcome email is set to "None" in the dropdown menu on the Details tab, as the module sends its own email. 204 | 205 | 3. In this version, the module billing cycles and SSL validity period are configured via standard WHMCS “Products/Services” settings. To access this, go to the Pricing tab and select Payment Type to Recurring. Now disable “One Time/Monthly”, “Quarterly” and “Semi-Annualy” billing cycles since they are not applicable to SSL Certificates. Finally, specify prices for remaining billing cycles. “Annually” corresponds to 1 year of SSL certificate validity (i.e. the SSL will be registered for 1 year). Biennially and triennially refer to 2 and 3 years respectively. 206 | 207 | ![Product Settings](http://files.namecheap.com/images/googlecode/Product-Settings.png) 208 | 209 | 4. On the Module Settings tab, choose "Namecheapssl" from Module Name dropdown menu. 210 | 211 | 5. Enter your API credentials. If you wish to test this module in sandbox environment, make sure to enter your sandbox username, sandbox API key in the corresponding text fields. Also, be sure to check the “Test Mode” box. 212 | 213 | 6. Choose the certificate type from the drop-down menu. 214 | 215 | 7. If you have a special “Promotion Code”, type it into the corresponding text field. 216 | 217 | 8. If “Use existing SSL from account” option is checked we will try to use an existing SSL certificate of this type from your Namecheap account first. If there is no SSL available that can be used, a new certificate will be purchased. 218 | 219 | 9. The purpose of the next set of fields is to customize the Technical Contact Details for any purchased SSL Certificates (fields are shown on a screens shot below). By default, Namecheap Contact details are used (email address sslsupport@namecheap.com). Using a custom Technical Contact Details is useful for resellers who wish to appear as an independent business entity to their customers. Depending on whether you want to use custom Technical Contact Details or not, perform the corresponding action: 220 | 221 | - In order to use Default Technical Email leave ALL of the fields below empty. 222 | - If you wish to use Custom Technical Email fill in ALL of the fields below. 223 | 224 | ![Customizing TechnicalContacts](http://files.namecheap.com/images/googlecode/Customizing-TechnicalContacts.png) 225 | 226 | Note: Our ability to provide support to customers who use custom Technical Contact Fields is limited. In case custom technical contact details are used, we cannot perform reissues, resending of approver email/ certificate, or cancellation/revocation of GeoTrust and Symantec SSL Certificates. However, since you possess control over technical contact, you can access GeoTrust/Symantec Live Account and perform these required actions yourself. 227 | 228 | For control of GeoTrust SSLs, please visit: https://products.geotrust.com/orders/orderinformation/authentication.do 229 | 230 | For control of Thawte SSLs, please visit: https://products.thawte.com/orders/orderinformation/authentication.do 231 | 232 | For control of Symantec SSLs, please visit: https://products.verisign.com/orders/orderinformation/authentication.do 233 | 234 | ##### Order Process 235 | 236 | The product will appear in the order process as a regular product which can be added to the cart. No configuration is performed before purchase. Once a certificate is purchased, paid for, and activated, the user is sent an email containing a link which takes them to configure the certificate in the client area. Once all details have been provided, the configuration data is sent to the Certificate Authority for validation. No manual intervention is required from you. 237 | 238 | You have an option to resend an email containing a link to the certificate configuration page to the client. This page is also accessible from the client area (My Products & Services -> Product Details -> View Certificate Details). Options to resend approver email and email with the certificate issued are also available in the client area. 239 | 240 | ##### Welcome/Configuration Email 241 | 242 | On its first launch, Namecheap SSL module automatically creates a configuration email template (see “SSL Certificate Configuration Required” in section "Product Messages" of Email Templates in Setup). It contains link to activation process inside your client area for a specific SSL certificate. 243 | 244 | Sending of SSL Configuration Email is controlled by the following parameters: 245 | 246 | Type of product setup behavior in Module Settings tab: 247 | 248 | ![Module Settings](http://files.namecheap.com/images/googlecode/Module-Settings.png) 249 | 250 | 1. Configuration email is always sent for options “Automatically setup the product as soon as an order is placed” and “Automatically setup the product as soon as the first payment is received”. If you select “Automatically setup the product as soon as an order is placed”, a configuration email will only be sent if the order is placed from the client area. The module itself will run only if you place the order from client area as well. 251 | 252 | 2. If the options “Automatically setup the product when you manually accept a pending order” or “Do not automatically setup this product” are selected, then sending of the Configuration Email will depend on the box “Send Welcome Email”: 253 | 254 | ![Welcome Email Setting](http://files.namecheap.com/images/googlecode/Welcome-Email-Setting.png) 255 | 256 | You can modify content of the configuration email at any time. 257 | 258 | ##### Activation from WHMCS 259 | 260 | In order to activate a certificate purchased from you, your client needs to access list of your services and click on ‘View Details’ button next to ordered certificate. 261 | 262 | ![View Certificate Details](http://files.namecheap.com/images/googlecode/View-Certificate-Details.png) 263 | 264 | After that your client needs to click ‘View certificate details’ and ‘Configure certificate’. 265 | 266 | He will see window with SSL activation fields: 267 | 268 | ![Configuring SSL Certificate](http://files.namecheap.com/images/googlecode/Configuring-SSL-Certificate.png) 269 | 270 | At this stage your client needs to input CSR code (obtained from web-server), select web-server type and fill in valid admin contact info. 271 | 272 | Basically admin contact info is to be pre-filled from user's WHMCS profile. 273 | 274 | Then your customer clicks 'Proceed' and gets to next step. 275 | 276 | In case CSR code is ok, your client will see the list of available DCV options on the next page.Those DCV options are basically HTTP-based validation or approval email. Your client may select any of emails there to receive Domain Control Validation email on that address or select HTTP-based DCV. In case HTTP-based DCV radiobutton is selected no email is to be sent for validation, however your customer will need to submit a specific file to root folder of his domain. Name and contents of file will be shown after he clicks ‘Submit’ and activation data gets transmitted to Certificate Authority. Also the file contents can be checked in customer’s area by viewing information of certificate that is being activated. 277 | 278 | Further activation process is between you or your customer and Certificate Authority. You are to receive approval email (for most certificates except Symantec OV and EV certs) and to approve it. After that certificate is to be sent to you (within 10-15 mins) or some docs request is to be sent to you for OV or EV certs. 279 | 280 | *** 281 | **Important Note:** 282 | Language variables containing strings with instructions to HTTP-based validation and with file contents are stored in /modules/servers/namecheapssl/lang/English.php. If you are using other language you need to create /modules/servers/namecheapssl/lang/%yourlanguage%.php and change values of the following variables to corresponding phrases in your language: $MOD_LANG['ncssl_http_based_validation'] ,$MOD_LANG['ncssl_show_validation_file_contents'] , $MOD_LANG['ncssl_custom_phrase_sslcertapproveremaildetails'],$MOD_LANG['ncssl_custom_phrase_sslconfigcompletedetails'] 283 | *** 284 | 285 | ##### Debugging and Addon functions 286 | 287 | Our Namecheap SSL Module addon has the following functions: 288 | 289 | - Log 290 | - Link/Re-Link WHMCS cert ID to NC Cert ID 291 | - Certificate list 292 | 293 | Log 294 | 295 | During setting up product you may check ‘Debug mode’ box in order to have your actions with module logged : 296 | 297 | ![Enabling Log](http://files.namecheap.com/images/googlecode/Enabling-Log.png) 298 | 299 | This will allow you to check log of actions performed by module in addons section in WHMCS: 300 | 301 | There you will find all of the actions performed by your customer with namecheapssl products, all hook actions and all API calls and responses. This is very convenient for investigation of possible issues. 302 | 303 | Each action will have WHMCS service ID of certificate that was viewed/activated/reissued from WHMCS user area so you will be able to track actions of your customers. 304 | 305 | ** Link/Re-Link WHMCS Cert ID to NC Cert ID** 306 | 307 | This feature allows connecting WHMCS certificate record to existing Namecheap certificate. 308 | 309 | For this you will need to input WHMCS invoice ID given after order placement to corresponding box and then to input certID of an existing certificate within your NC account (can be found next to certificate in list of SSLs at Namecheap). 310 | 311 | After clicking ‘Sync’ details for specific certificate in your WHMCS will be taken from Namecheap. 312 | 313 | **Certificate List** 314 | 315 | In this section you may see all of the certificates ordered via this WHMCS from all of the NC accounts associated with it. 316 | 317 | You will see the following fields in the lists: 318 | 319 | ![Certificate list](http://files.namecheap.com/images/googlecode/Certificate-list.png) 320 | 321 | ##### Reissue and renewal 322 | 323 | Reissue and renewal are 2 different actions with SSL certificate. 324 | 325 | After the certificate gets issued, it's status becomes ‘active’ and you will see the following screen while viewing it’s info: 326 | 327 | ![Reissuing Cerificate](http://files.namecheap.com/images/googlecode/Reissuing-Cerificate.png) 328 | 329 | There you may download certificate in zip archive in corresponding format for your web-server or reissue the certificate. 330 | 331 | **Reissue** 332 | 333 | Reissue is the process of having certificate regenerated with Certificate Authority if needed. For example, if your client has lost your Private Key. For that he needs to view details of your certificate from list of certificates in WHMCS user area and click ‘Reissue Certificate’ button: 334 | 335 | Further process will be very similar to activation – your customer will need to paste CSR for the same domain name and select approval email. Reissuing a certificate will change its Namecheap Certificate ID. A new certificate record will be added to your Namecheap account. 336 | 337 | **Due date and reissue state synchronization** 338 | 339 | All changes done in WHMCS are synchronized with your Namecheap account automatically once a day (when WHMCS cron runs). Also you can perform manual synchronization any time by clicking ‘Synchronize with Namecheap’. This will set WHMCS due dates and reissue states in sync with Namecheap admin area when needed: 340 | 341 | ![Sync duedate reissuestatus](http://files.namecheap.com/images/googlecode/Sync-duedate-reissuestatus.png) 342 | 343 | **Renewal** is pretty much the same as purchasing new certificate with Namecheap. Renewal functionality is fully integrated into the module. As long as you have “Payment Type” set to “Recurring” when creating a product, invoices for renewals will be generated automatically. Once paid, renewal SSLs will be created automatically as well. Please keep in mind that after the renewal SSL is created, it still requires activation using [CSR](http://namecheap.simplekb.com/kb.show?show=article&articleid=817&categoryid=71). 344 | 345 | ##### Multi-Domain Certificates 346 | 347 | **General information about product** 348 | 349 | Recently Multi-Domain Certificates were added to Namecheap’s product list. These certificates are quite popular among customers, but require some additional configurations. during Multidomain certificates can be divided into 2 categories – old single domain products that now support additional domains as a configurable addon, and new multi-domain products that come with a predefined number of domains included in the product by default (more domains can be included additionally as well). Therefore number of domains included by default differs across the products. See the table for details: 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 |
ProviderProduct nameDefault number of domains 
(domain from CSR is counted here)
Maximum number of domainsMaximum number of domains that should be used 
in configurable options
ComodoPositiveSSL Multi-domain310097
ComodoMulti Domain SSL310097
ComodoEV Multi Domain310097
ComodoUnified Communications310097
GeotrustQuickSSL Premium14-
GeotrustTrue Business ID with EV Multi-domain52520
GeotrustTrue Business ID Multi-domain52520
ThawteSSL Web Server12524
ThawteSSL Web Server with EV12524
ThawteSSGC Supercerts12524
SymantecSecure Site Pro with EV12524
SymantecSecure Site with EV12524
SymantecSecure Site12524
SymantecSecure Site Pro12524
459 | 460 | 461 | ##### Setting up Multi-Domain Certificates 462 | 463 | First of all, you need to set up product as described in ‘Setting up products and pricings’ section. After product is set up the default number of addon domains (from table above) will be available during activation. In order to give your customers ability to order additional domains you need to set up configurable options for each multi-domain certificate you set up. It would not take much time. 464 | 465 | 1. Go to configurable options and click on ‘Create a new group’ there. 466 | 467 | ![setting up multi domain](http://files.namecheap.com/images/googlecode/setting-up-multi-domain.png) 468 | 469 | 2. Fill in the name of your group (We recommend mentioning product name there) and select a product you wish to associate the configurable option with. 470 | 471 | ![configurable option groups](http://files.namecheap.com/images/googlecode/configurable-option-groups.png) 472 | 473 | 3. Click ‘Add new configurable option’ button. 474 | 475 | ![adding configurable options](http://files.namecheap.com/images/googlecode/adding-configurable-options.png) 476 | 477 | 4. Option Name. This field consists of two parts, the first one is internal and the other one is Visible to clients. Option name must contain ‘san|’ element. The text input after “|” will be displayed in your clients’ shopping cart. We recommend to specify default number of addon domains that are already included in certificate (For example – “san|Addon domains ( 3 domains are included by default)” for PositiveSSL MultiDomain. 478 | 479 | 5. Select ‘Quantity’ as Option Type from dropdown menu. Click ‘Save changes’. 480 | 481 | 6. Type 0 in ‘Minimum Quantity Required’ and the value from the last column of the table above as ‘Maximum Allowed’. For example, if you are setting up PositiveSSL Multi Domain, please input 97 as maximum. 482 | 483 | 7. Use any name (it will not be shown anywhere) in the box next to ‘Add Option:’ and click ‘Save changes’. 484 | 485 | 8. At this point you will see the table for pricing similar to one you’ve filled in during setting up product. Please fill in pricing for each additional domain for different terms. 486 | 487 | 9. Click ‘Save changes’ 488 | 489 | ![adding configurable options](http://files.namecheap.com/images/googlecode/adding-configurable-options.png) 490 | 491 | That’s it. Now if your customer orders a multi-domain certificate he will be able to add some additional domains to his order. 492 | 493 | *** 494 | **Important Note:** Please mention the default number of domains provided with Multi-Domain Certificates in product name or product description – this will guarantee your customers that even if they do not order any additional domains, they will have some of them added by default. 495 | *** 496 | 497 | ##### QuickSSL Premium multi-domain setup 498 | As you could see from the table above, QuickSSLs Premium are also multi-domain product from now on. However they have certain specifics. 499 | 500 | - You have 2 options during purchasing QuickSSL Premium – default single-domain option or option with 4 additional subdomains. 501 | - You may only add subdomains of different levels as addons – different domains will return error. 502 | - Price remains the same in case you activate QuickSSL Premium with 1 or 4 additional subdomains. 503 | 504 | Configurable option for QuickSSL Premium is a bit different. Please follow the next steps in order to configure it. 505 | 506 | ![quickssl configurable options](http://files.namecheap.com/images/googlecode/quickssl-configurable-options.png) 507 | 508 | 1. Please select Option type as ‘Dropdown’. 509 | 510 | 2. Please set name as ‘san|Addon Subdomains’ (or, as for other Multi-Domain Certificates, any other phrase after ‘|’. 3. Fill the field below ‘Options’ with “0|No addon subdomains” (or any other phrase after ‘|’ on your demand. “0” is the keyword meaning that selecting this option will create no fields for client during activation. 511 | 512 | 4. Click ‘Save Changes’. 513 | 514 | 5. Fill the new field with ‘1|4 addon subdomains’ (or any other phrase after ‘|’ on your demand). “1” is the keyword meaning that selecting this option will create 4 fields for addon subdomains for client during activation. 515 | 516 | 6. Click ‘Save changes’. 517 | 518 | Example of configurable options table: 519 | 520 | ![quickssl configurable options example](http://files.namecheap.com/images/googlecode/quickssl-configurable-options-example.png) 521 | 522 | ##### Managing addon domains after purchase is made 523 | 524 | Your client as well as you will be able to add more domains to a certificate after order is complete. 525 | 526 | This can be done either from user and admin areas. 527 | 528 | In order to do that in admin area, your customer needs to mouse over ‘Management Actions’ and select ‘Upgrade/Downgrade Options’. 529 | 530 | ![managing add ons after purchase](http://files.namecheap.com/images/googlecode/managing-add-ons-after-purchase.png) 531 | 532 | There your customer can increase number of addon domains. An attempt to decrease that number will cause error. A new hook was implemented in client area tracking attempts to decrease number of addon domains. 533 | 534 | *** 535 | **Important Note:** The number of addon domains can be changed from client area only after invoice for order is paid. 536 | *** 537 | 538 | In order to change number of addon domains in WHMCS admin area, you need to access product page and manually input the new number of addon domains. 539 | 540 | Please note that in case you decrease or increase this number here, you need to invoice/refund your client manually. 541 | 542 | ![editing add ons](http://files.namecheap.com/images/googlecode/editing-add-ons.png) 543 | 544 | *** 545 | **Important Note:** In case you or your client increases number of addon domains for a certificate your Namecheap account will be charged for every extra addon domain used during activation/reissue. 546 | *** 547 | 548 | For example, if your customer has ordered 2 more domains before reissue or you have manually increased number of addon domains by 2, your Namecheap account will be charged for 2 addon domains after reissue is complete from WHMCS client area. 549 | 550 | ##### Activation of Multi-Domain Certificates 551 | 552 | Activation process is similar to activation of single-domain certificates. Below the CSR box you will see fields for additional domains (or subdomains in case of QuickSSL Premium). 553 | 554 | It is not strongly required to fill in all the Addon Domain field during the first activation. Duplicate records are not allowed (including duplicates in CSR’s common name and addon domain fields). 555 | 556 | Below is an example of first configuration page for PositiveSSL Multi Domain with 5 addon domains ordered (1 domain from CSR + 2 addon domains by default + 5 addon domains ordered separately). 557 | 558 | ![multi domain activation](http://files.namecheap.com/images/googlecode/multi-domain-activation.png) 559 | 560 | For example, if he selects “admin@” as approver email having “domain.com” as common name in CSR and “secure.domain.com” and “domain2.com” as addon domains, the approvals will be sent to admin@domain.com, admin@secure.domain.com and admin@domain2.com. 561 | 562 | If your customer wishes to change email for one of the domains, he should contact you, and you in turn need to contact us via live chat or ticket system to have emails changed. 563 | 564 | Such approver email selection flow on second configuration page is caused by certain limitations in WHMCS core. 565 | 566 | **Revocation** 567 | 568 | In this version, revocation functionality has been added. WHMCS end users can request revocation of their reissued certificates. A new button appears on the Certificate Details page if there are any reissued certificates on record: 569 | 570 | ![Revoke Cerificate](http://files.namecheap.com/images/googlecode/Revoke-Certificate.png) 571 | 572 | Also, this button will be shown in the admin area for specific services. 573 | With different Certificate Authorities, clicking this button will lead to different behaviors. 574 | 575 | **Comodo Case** 576 | 577 | Comodo certificates are revoked immedidately after the button is clicked. Once it has been clicked, the button will disappear from the client and admin areas, and certificate is marked ‘Revoked’ on the Namecheap side. 578 | 579 | **RapidSSL/GeoTrust/Symantec/Thawte Case** 580 | 581 | Revocation functionality for these Certificate Authorities is different from Comodo’s. Revocation approval via email is required. The revocation approval will be sent to the technical email address specified in the order. In addition, there are three groups of RapidSSL/ GeoTrust /Symantec/ Thawte certificates that show different behavior upon clicking the ‘Revoke old certificates’ button based on the issuance dates. 582 | 583 | **1. Certificates issued before 6/16/2014** 584 | 585 | These certificates cannot be revoked right away. Upon clicking the ‘Revoke Old Certificates’ button the following message will be shown: 586 | “Revocation of reissued certificates associated with this order is unavailable right away due to limitations from Symantec. Please contact support for revocation of your reissued certificates.” 587 | You, as WHMCS admin, will need to revoke the certificate from End User Portal. 588 | 589 | Please read the following article to learn how to revoke certificates using End User Portal: https://www.namecheap.com/support/knowledgebase/article.aspx/9346/38/revocation-of-symantecgeotrustthawterapidssl-certificates 590 | 591 | **2. Certificates issued after 6/16/2014 that have technical email unfilled in module settings of the product (therefore sslsupport@namecheap.com is used)** 592 | 593 | Upon clicking the ‘Revoke Old Certificates’ button the following message will be shown: 594 | “The revocation process has been initiated. The revocation will be processed manually between us and Symantec. It will be completed within 1-2 hours.“ 595 | 596 | The revocation approval will be sent to our email address, and our team will process it for you within 1-2 hours if there are no unpredicted circumstances. 597 | 598 | **3. Certificates issued after 6/16/2014 that have your technical email specified in module settings of product** 599 | 600 | Upon clicking the ‘Revoke Old Certificates’ button the following message will be shown: 601 | “Your revocation request is being processed manually by admin. Revocation will be completed as soon as possible.” 602 | 603 | You, as WHMCS admin, will need to check your technical email and approve the revocation request manually. We recommend you check technical email inbox on a regular basis. 604 | 605 | **Important Note:** Due to limitations on Symantec’s side, the GeoTrust/RapidSSL/Symantec/Thawte certificates described in cases 2 and 3 can be revoked only if there is only one reissued certificate record for a specific certificate. Attempting to revoke certificates that have 2 or more reissued records will cause the following message upon clicking the ‘Revoke Old Certificates’ button: 606 | “Revocation of multiple instances of reissued certificates is temporarily unavailable due to technical restrictions on the Certificate Authority’s side. Please contact support for further assistance.” 607 | 608 | You will need to revoke the certificate using End User Home or to contact Namecheap SSL Support for revocation. 609 | 610 | ##### FAQ 611 | 612 | **Q:** I cancel certificate and nothing happens 613 | 614 | **A:** Cancellation is being performed only in your WHMCS, but not in our system. Please submit a cancellation request with our SSL support team for certificate to be revoked and refunded 615 | 616 | **Q:** Does your module have multi-language support? 617 | 618 | **A:** Yes, multi-language is fully integrated with WHMCS so you may change the default language of your WHMCS and language will be changed for fields used in module as well. Please note that you will need to create a custom %yourlanguage%.php file in lang directory at modules/servers/namecheapssl/lang for some fields to be translated as well. You may use default English.php as translation template. 619 | 620 | **Q:** Getting “ 2010167 Parameter Years is Missing” error while accepting order. 621 | 622 | **A:** This error usually occurs when Pricing is set up improperly for your SSL product. Please doublecheck that Payment type is set to ‘Recurring’ and there is ‘-1’ input in ‘Monhtly, Quarterly, and Semi-Anually’ fields to disable possibility of ordering SSL for terms less than a year as SSL certificates can only be ordered and issued for a whole number of years only. 623 | 624 | **Q:** I am receiving ''['" or any other strange characters instead or error messages while activation of my renewal certificate 625 | 626 | **A:** This is a known bug, our developers are currently investigating it. In case you face this issue please email details to sslsupport@namecheap.com and kindly purchase and activate renewal certificate manually from Namecheap if renewal is urgent. After purchasing certificate manually you will need to sync the IDs using ‘Link/Re-Link WHMCS Cert ID to NC Cert ID’ addon function. 627 | 628 | 629 | 630 | 631 | -------------------------------------------------------------------------------- /includes/hooks/namecheapssl_sync.php: -------------------------------------------------------------------------------- 1 | 1, "PageSize" => $iPageSize); 45 | 46 | try{ 47 | $response = $api->request("namecheap.ssl.getList", $requestParams); 48 | $result = $api->parseResponse($response); 49 | }catch(Exception $e){ 50 | echo $e->getMessage(); 51 | return; 52 | //exit(); 53 | } 54 | 55 | if ($result){ 56 | $iTotalPages = (int) ceil($result['Paging']['TotalItems']/$iPageSize); 57 | } 58 | 59 | for($i=1;$i<=$iTotalPages;$i++){ 60 | if (1!=$i){ 61 | try{ 62 | $requestParams = array("Page" => $i, "PageSize" => $iPageSize); 63 | $response = $api->request("namecheap.ssl.getList", $requestParams); 64 | $result = $api->parseResponse($response); 65 | }catch(Exception $e){ 66 | echo $e->getMessage(); 67 | return; 68 | //exit(); 69 | } 70 | } 71 | 72 | 73 | foreach ($result["SSLListResult"]["SSL"] as $aCertInfo){ 74 | 75 | if ('active'==$aCertInfo['@attributes']['Status'] || 'replaced'==$aCertInfo['@attributes']['Status']){ 76 | 77 | 78 | // synchronize expire date 79 | list($month, $day, $year) = explode("/", $aCertInfo['@attributes']['ExpireDate']); 80 | 81 | // 82 | $res = NcSql::q("SELECT h.id FROM `tblhosting` h INNER JOIN `tblsslorders` s ON s.serviceid=h.id WHERE s.remoteid='".(int)$aCertInfo['@attributes']['CertificateID']."' AND h.`nextduedate` != '".NcSql::e("$year-$month-$day")."'"); 83 | 84 | if (NcSql::numRows($res)){ 85 | $iHostingId = array_shift(NcSql::fetchArray($res)); 86 | 87 | $duedate = "$year-$month-$day"; 88 | if($sync_date_offset){ 89 | $duedate = date('Y-m-d',strtotime($duedate . "-$sync_date_offset days")); 90 | } 91 | 92 | $sql = "update `tblhosting` 93 | set `nextduedate` = '".NcSql::e($duedate)."', 94 | `nextinvoicedate` = '". NcSql::e($duedate)."' 95 | where `id` = '".(int)$iHostingId."'"; 96 | NcSql::q($sql); 97 | namecheapssl_log('hook.sync', 'sync_hook_updated_duedate', array("$duedate"),$iHostingId); 98 | } 99 | 100 | // sync domain 101 | if(!empty($aCertInfo['@attributes']['HostName']) && 'active'==$aCertInfo['@attributes']['Status']){ 102 | $domain = NcSql::e($aCertInfo['@attributes']['HostName']); 103 | $res = NcSql::q("SELECT h.id FROM `tblhosting` h INNER JOIN `tblsslorders` s ON s.serviceid=h.id WHERE s.remoteid='{$aCertInfo['@attributes']['CertificateID']}' AND h.`domain` != '$domain'"); 104 | if (NcSql::numRows($res)){ 105 | $iHostingId = array_shift(NcSql::fetchArray($res)); 106 | $sql = "update `tblhosting` 107 | set `domain` = '$domain' 108 | where `id` = '".(int)$iHostingId."'"; 109 | NcSql::q($sql); 110 | namecheapssl_log('hook.sync', 'sync_hook_updated_domain', array($domain),$iHostingId); 111 | } 112 | } 113 | 114 | 115 | } 116 | 117 | 118 | if ('replaced'==$aCertInfo['@attributes']['Status']){ 119 | 120 | // synchronize reissue state 121 | $sql ="SELECT * FROM tblsslorders WHERE remoteid='".(int)$aCertInfo['@attributes']['CertificateID']."'"; 122 | $r = NcSql::q($sql); 123 | if (NcSql::numRows($r)){ 124 | $aWhmcsCert = NcSql::fetchAssoc($r); 125 | // get replaced certificate info 126 | try{ 127 | $replaced_cert_request_params = array('CertificateID' => (int)$aWhmcsCert['remoteid']); 128 | $replaced_cert_response = $api->request("namecheap.ssl.getInfo", $replaced_cert_request_params); 129 | $replaced_cert_result = $api->parseResponse($replaced_cert_response); 130 | 131 | if (!empty($replaced_cert_result["SSLGetInfoResult"]["@attributes"]["ReplacedBy"])){ 132 | 133 | $replacedBy = (int)$replaced_cert_result["SSLGetInfoResult"]["@attributes"]["ReplacedBy"]; 134 | if(0==$replacedBy){ 135 | echo 'Wrong "replaced by" attribute: ' . $replaced_cert_result["SSLGetInfoResult"]["@attributes"]["ReplacedBy"]; 136 | return; 137 | //exit(); 138 | } 139 | 140 | $sql = "UPDATE tblsslorders SET remoteid='$replacedBy' WHERE remoteid='".(int)$aCertInfo['@attributes']['CertificateID']."'"; 141 | NcSql::q($sql); 142 | 143 | $sql = "UPDATE mod_namecheapssl SET certificate_id='$replacedBy' WHERE certificate_id='".(int)$aCertInfo['@attributes']['CertificateID']."'"; 144 | NcSql::q($sql); 145 | 146 | namecheapssl_log('hook.sync', 'sync_hook_updated_remoteid', array($aCertInfo['@attributes']['CertificateID'], $replacedBy),$aWhmcsCert['serviceid']); 147 | 148 | } 149 | 150 | }catch(Exception $e){ 151 | echo $e->getMessage(); 152 | return; 153 | } 154 | 155 | } 156 | 157 | } 158 | 159 | 160 | } 161 | 162 | } 163 | 164 | 165 | } 166 | 167 | 168 | function Namecheapssl_hook_report(){ 169 | 170 | // create html for report 171 | $dateEnd = date('Y-m-d H:i:00'); 172 | $dateStart = date('Y-m-d H:i:59', mktime(date('H'), date('i'), date('s'), date('n'), date('d')-1)); 173 | 174 | 175 | $query = "SELECT log.*,c.email FROM mod_namecheapssl_log log LEFT JOIN tblclients AS c ON (log.userid=c.id AND user='client') WHERE log.date BETWEEN '". NcSql::e($dateStart)."' AND '". NcSql::e($dateEnd)."' AND `debug`=0 "; 176 | 177 | $r = NcSql::q($query); 178 | 179 | if(NcSql::numRows($r)){ 180 | 181 | $html = "Namecheap SSL Module Cron Job Report for $dateStart-$dateEnd

"; 182 | while($row= NcSql::fetchAssoc($r)){ 183 | $html .= "{$row['date']}; {$row['description']}; " . ('client' == $row['user'] ? ' User(client): ' . $row['email'] : ' Admin user: ' . $row['user']) . "({$row['userid']});" . ( !empty($row['serviceid']) ? "Service id: {$row['serviceid']}; " : '') ; 184 | $html .= '
'; 185 | 186 | } 187 | 188 | sendAdminNotification('system', "SSL Actions Report", $html); 189 | 190 | } 191 | 192 | 193 | } 194 | 195 | 196 | 197 | function Namecheapssl_hook_prevent_san_reduction($params){ 198 | 199 | if(!empty($params['filename']) && !empty($params['type']) && $params['filename']=='upgrade' && $params['type']=='configoptions'){ 200 | if(!empty($params['configoptions'])&&!empty($params['id'])){ 201 | 202 | $r = NcSql::q('SELECT tblproducts.servertype FROM tblproducts JOIN tblhosting ON tblhosting.packageid=tblproducts.id WHERE tblhosting.id='.(int)$params['id']); 203 | if(!$r){return;} 204 | $row = NcSql::fetchAssoc($r); 205 | if('namecheapssl'!==$row['servertype']){ 206 | return; 207 | } 208 | // so, it's definitely an upgrade page for namecheapssl product 209 | 210 | foreach($params['configoptions'] as $configid=>$newvalue){ 211 | 212 | 213 | // check if options is san and related to namecheap module product 214 | $r = NcSql::q("SELECT * FROM tblproductconfigoptions WHERE id=".(int)$configid.""); 215 | $row = NcSql::fetchAssoc($r); 216 | if(substr($row['optionname'],0,3)==='san'){ 217 | 218 | // it's a san option; we need to check old value 219 | $r = NcSql::q("SELECT qty FROM tblhostingconfigoptions WHERE relid=".(int)$params['id'] . " AND configid=".(int)$configid); 220 | $row = NcSql::fetchAssoc($r); 221 | 222 | $qty = $row['qty']; 223 | 224 | // this is it 225 | if($newvalue<$qty){ 226 | $location = $params['systemurl'] . '?m=namecheap_ssl&san_reduction'; 227 | header("Location: $location"); 228 | exit(); 229 | } 230 | 231 | } 232 | } 233 | } 234 | } 235 | 236 | } 237 | 238 | 239 | if (function_exists('add_hook')){ 240 | add_hook("DailyCronJob", 11, "Namecheapssl_hook_sync"); 241 | add_hook("DailyCronJob", 12, "Namecheapssl_hook_report"); 242 | add_hook("ClientAreaPage", 10, 'Namecheapssl_hook_prevent_san_reduction'); 243 | } 244 | 245 | ?> 246 | -------------------------------------------------------------------------------- /modules/addons/namecheap_ssl/client_templates/notice.tpl: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | {$notice} 5 |
6 |
7 | {if $back_to_service_id} 8 | 9 | {/if} 10 | 11 |
12 | -------------------------------------------------------------------------------- /modules/addons/namecheap_ssl/namecheap_ssl.php: -------------------------------------------------------------------------------- 1 | "Namecheap SSL Module Addon", 30 | "description" => "This addon performs several important operations related to Namecheap SSL Module. 1) It performs necessary installation/update procedures during Namecheap SSL Module installation/update. 2) It logs details of all SSL certificate reissues. 3) It performs full logging of all API calls for the products with activated \"debug mode\" option.", 31 | "version" => "1.42", 32 | "author" => "Namecheap", 33 | "language" => "english", 34 | "fields" => array( 35 | "log_items_per_page" => array ("FriendlyName" => "Number of Log entries per page", "Type" => "text", "Size" => "2", "Description" => "items", "Default" => "50", ), 36 | ) 37 | ); 38 | return $configarray; 39 | } 40 | 41 | function namecheap_ssl_activate() { 42 | 43 | 44 | // 1. Create configuration email template 45 | if (!NcSql::numRows(sprintf("SELECT id FROM tblemailtemplates WHERE name='%s'",'SSL Certificate Configuration Required'))) { 46 | full_query("INSERT INTO `tblemailtemplates` (`type` ,`name` ,`subject` ,`message` ,`fromname` ,`fromemail` ,`disabled` ,`custom` ,`language` ,`copyto` ,`plaintext` )VALUES ('product', 'SSL Certificate Configuration Required', 'SSL Certificate Configuration Required', '

Dear {\$client_name},

Thank you for your order for an SSL Certificate. Before you can use your certificate, it requires configuration which can be done at the URL below.

{\$ssl_configuration_link}

Instructions are provided throughout the process but if you experience any problems or have any questions, please open a ticket for assistance.

{\$signature}

', '', '', '', '', '', '', '0')"); 47 | } 48 | 49 | // 2.Create auxiliary module table 50 | $queryString = " CREATE TABLE IF NOT EXISTS `mod_namecheapssl` ( 51 | `id` INT AUTO_INCREMENT , 52 | `user_id` INT , 53 | `certificate_id` INT , 54 | `type` VARCHAR( 255 ) , 55 | `status` VARCHAR( 255 ) , 56 | `creation_date` VARCHAR( 10 ) , 57 | `period` INT( 1 ) , 58 | `expiry_date` VARCHAR( 10 ) , 59 | `domain` VARCHAR( 255 ), 60 | `parse_csr` TEXT, 61 | `admin_email` VARCHAR( 255 ), 62 | PRIMARY KEY ( `id` ) 63 | ) ENGINE = MYISAM "; 64 | NcSql::q($queryString); 65 | 66 | 67 | // 2. Create auxiliary module log table 68 | NcSql::q("CREATE TABLE IF NOT EXISTS `mod_namecheapssl_log` ( 69 | `id` INT(10) NOT NULL AUTO_INCREMENT, 70 | `date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', 71 | `action` VARCHAR(255) NOT NULL DEFAULT '', 72 | `description` TEXT NOT NULL, 73 | `user` TEXT NOT NULL, 74 | `userid` INT(10) NOT NULL, 75 | `ipaddr` TEXT NOT NULL, 76 | PRIMARY KEY (`id`) 77 | ) 78 | COLLATE='utf8_general_ci' 79 | ENGINE=MyISAM"); 80 | 81 | // 2. Update existing auxiliary table: add reissue functionality 82 | if (!NcSql::sqlNumRows("SHOW COLUMNS FROM `mod_namecheapssl` LIKE 'reissue'")){ 83 | NcSql::q("ALTER TABLE `mod_namecheapssl` ADD COLUMN `reissue` TINYINT(1) NULL DEFAULT '0' AFTER `admin_email`"); 84 | } 85 | 86 | // 3. Add reissue invitation letter 87 | if (!NcSql::sqlNumRows("SELECT id FROM tblemailtemplates WHERE name='SSL Certificate Reissue Invitation'")){ 88 | NcSql::q("INSERT INTO `tblemailtemplates` (`type` ,`name` ,`subject` ,`message` ,`fromname` ,`fromemail` ,`disabled` ,`custom` ,`language` ,`copyto` ,`plaintext` )VALUES ('product', 89 | 'SSL Certificate Reissue Invitation', 90 | 'SSL Certificate Reissue Invitation', 91 | '

Dear {\$client_name},

A reissue request has been initiated by an administrator for the following: {\$ssl_certificate_id}. In order to reissue the certificate please go through a configuration process at the URL below.

{\$ssl_configuration_link}

Instructions are provided throughout the process but if you experience any problems or have any questions, please open a ticket for assistance.

{\$signature}

', 92 | '', '', '', '', '', '', '0')"); 93 | } 94 | 95 | 96 | namecheap_ssl_check_upgrades(); 97 | 98 | return array( 99 | 'status'=>'success', 100 | 'description'=>'' 101 | ); 102 | 103 | 104 | # Return Result 105 | // return array('status'=>'success','description'=>'This is an demo module only. In a real module you might instruct a user how to get started with it here...'); 106 | // return array('status'=>'error','description'=>'You can use the error status return to indicate there was a problem activating the module'); 107 | 108 | 109 | } 110 | 111 | function namecheap_ssl_deactivate() { 112 | return array('status'=>'success','description'=>''); 113 | //return array('status'=>'error','description'=>'If an error occurs you can return an error message for display here'); 114 | //return array('status'=>'info','description'=>'If you want to give an info message to a user you can return it here'); 115 | } 116 | 117 | 118 | function namecheap_ssl_upgrade($vars) { 119 | 120 | namecheap_ssl_check_upgrades(); 121 | 122 | } 123 | 124 | 125 | function namecheap_ssl_check_upgrades(){ 126 | 127 | // v 1.1 128 | if (!NcSql::sqlNumRows("SHOW COLUMNS FROM `mod_namecheapssl_log` LIKE 'debug'")){ 129 | NcSql::q("ALTER TABLE `mod_namecheapssl_log` ADD COLUMN `debug` TINYINT(1) NOT NULL DEFAULT '0' AFTER `id`"); 130 | NcSql::q("ALTER TABLE `mod_namecheapssl_log` CHANGE COLUMN `user` `user` VARCHAR(255) NOT NULL AFTER `description`, ADD INDEX `debug` (`debug`), ADD INDEX `date` (`date`), ADD INDEX `action` (`action`), ADD INDEX `user` (`user`), ADD INDEX `userid` (`userid`)"); 131 | NcSql::q("ALTER TABLE `mod_namecheapssl_log` ADD COLUMN `parentid` INT(10) NOT NULL DEFAULT '0' AFTER `id`"); 132 | NcSql::q("ALTER TABLE `mod_namecheapssl_log` ADD COLUMN `serviceid` INT(10) NOT NULL DEFAULT '0' AFTER `parentid`"); 133 | } 134 | 135 | // v 1.2 136 | if (!NcSql::sqlNumRows("SHOW COLUMNS FROM `mod_namecheapssl` LIKE 'file_name'")){ 137 | NcSql::q("ALTER TABLE `mod_namecheapssl` DROP COLUMN `status`, DROP COLUMN `creation_date`, DROP COLUMN `expiry_date`, DROP COLUMN `domain`, DROP COLUMN `parse_csr`"); 138 | NcSql::q("ALTER TABLE `mod_namecheapssl` ADD COLUMN `file_name` VARCHAR(255) NULL AFTER `reissue`, ADD COLUMN `file_content` VARCHAR(255) NULL AFTER `file_name`"); 139 | } 140 | 141 | // v 1.3 142 | // check updates only 143 | 144 | // v 1.4 145 | // 146 | if (!NcSql::sqlNumRows("SHOW COLUMNS FROM `mod_namecheapssl` LIKE 'configdata_copy'")){ 147 | NcSql::q("ALTER TABLE `mod_namecheapssl` ADD COLUMN `configdata_copy` TEXT NULL DEFAULT NULL AFTER `file_content`"); 148 | NcSql::q("ALTER TABLE `mod_namecheapssl` ADD COLUMN `revoke_data` TEXT NULL DEFAULT NULL AFTER `configdata_copy`;"); 149 | } 150 | 151 | 152 | // v 1.41 153 | // 154 | if (!NcSql::sqlNumRows("SHOW TABLES LIKE 'mod_namecheapssl_settings'")){ 155 | NcSql::q("CREATE TABLE `mod_namecheapssl_settings` ( 156 | `name` VARCHAR(50) NOT NULL, 157 | `value` VARCHAR(255) NOT NULL 158 | ) 159 | ENGINE=MyISAM"); 160 | } 161 | 162 | 163 | } 164 | 165 | 166 | 167 | function namecheap_ssl_output($vars) { 168 | 169 | if (!empty($_REQUEST['action'])){ 170 | $action = $_REQUEST['action']; 171 | }else{ 172 | $action = 'default'; 173 | } 174 | 175 | 176 | 177 | global $_LANG; 178 | namecheapssl_initlang(); 179 | 180 | 181 | 182 | $view = array( 183 | 'global' => array( 184 | 'mod_url' => '?module=namecheap_ssl', 185 | 'module' => 'namecheap_ssl' 186 | ) 187 | ); 188 | 189 | 190 | if ('log'==$action){ 191 | 192 | // prepare data for actions filters 193 | // actions 194 | $view['filter_action_options'] = NcSql::sql2set_column("SELECT DISTINCT action FROM mod_namecheapssl_log"); 195 | 196 | // detect selected action 197 | if(!empty($_REQUEST['filter_action']) && in_array($_REQUEST['filter_action'],$view['filter_action_options'])){ 198 | $view['filter_action_value'] = $_REQUEST['filter_action']; 199 | }else{ 200 | $view['filter_action_value'] = ''; 201 | } 202 | 203 | 204 | 205 | // 206 | $view['filter_date_from_value'] = empty($_REQUEST['filter_date_from']) ? '' : $_REQUEST['filter_date_from']; 207 | $view['filter_date_to_value'] = empty($_REQUEST['filter_date_to']) ? '' : $_REQUEST['filter_date_to']; 208 | 209 | $view['filter_user_value'] = empty($_REQUEST['filter_user']) ? '' : $_REQUEST['filter_user']; 210 | 211 | 212 | // prepare query for page items 213 | $iOffset = empty($vars['log_items_per_page'])?50:(int)$vars['log_items_per_page']; 214 | $page = !empty($_REQUEST['page']) ? (int)$_REQUEST['page'] : 1; 215 | $iLimit = $page <= 1 ? 0 : ($page -1) * $iOffset; 216 | 217 | // create WHERE for sql query 218 | $sqlWhereArray = array(); 219 | // action value 220 | if(!empty($view['filter_action_value'])){ 221 | $sqlWhereArray[] = sprintf(" action='%s' " , NcSql::e($view['filter_action_value'])); 222 | } 223 | // date from value 224 | if(!empty($view['filter_date_from_value'])){ 225 | 226 | $sqlWhereArray[] = sprintf("date>='%s'",toMySQLDate($view['filter_date_from_value'])); 227 | } 228 | // date to value 229 | if(!empty($view['filter_date_to_value'])){ 230 | $sqlWhereArray[] = sprintf("date<='%s'",toMySQLDate($view['filter_date_to_value']).' 23:59:59'); 231 | } 232 | // admin / client filter 233 | if(!empty($view['filter_user_value'])){ 234 | if(false !== strpos($view['filter_user_value'], '@')){ 235 | $sqlWhereArray[] = sprintf("c.email = '%s'", NcSql::e($view['filter_user_value'])); 236 | }else{ 237 | $sqlWhereArray[] = sprintf("log.user LIKE '%s%%'", NcSql::e($view['filter_user_value'])); 238 | } 239 | } 240 | 241 | if(!empty($sqlWhereArray)){ 242 | $sqlWhere = ' WHERE ' . implode(' AND ', $sqlWhereArray); 243 | }else{ 244 | $sqlWhere = ''; 245 | } 246 | 247 | 248 | $sql = "SELECT log.*,c.email FROM mod_namecheapssl_log log LEFT JOIN tblclients AS c ON (log.userid=c.id AND user='client') $sqlWhere ORDER BY log.id DESC LIMIT $iLimit,$iOffset"; 249 | 250 | 251 | $view['log_items'] = NcSql::sql2set($sql); 252 | 253 | // query for count 254 | $sql = "SELECT COUNT(log.id) FROM mod_namecheapssl_log log LEFT JOIN tblclients AS c ON (log.userid=c.id AND user='client') $sqlWhere" ; 255 | $iCountOfLogItems = NcSql::sql2cell($sql); 256 | $iCountOfPages = (int)ceil($iCountOfLogItems/$iOffset); 257 | 258 | 259 | $view['log_items_count'] = $iCountOfLogItems; 260 | $view['log_items_count_of_pages'] = $iCountOfPages; 261 | $view['log_items_current_page'] = $page <= 1 ? 1:$page; 262 | 263 | } 264 | else if ('sync'==$action){ 265 | 266 | if(!empty($_REQUEST['hostingid'])){ 267 | 268 | $view['hostingid'] = (int)$_REQUEST['hostingid']; 269 | 270 | // search product 271 | $row = NcSql::sql2row('SELECT orderid, tblhosting.domain, tblproducts.name AS productname FROM tblhosting JOIN tblproducts ON tblhosting.packageid=tblproducts.id WHERE tblhosting.id='.(int)$_REQUEST['hostingid']); 272 | 273 | // check san certificate 274 | // get config options 275 | $certHasSanOption = false; 276 | $r = NcSql::q('SELECT tblproductconfigoptions.optionname FROM tblproductconfigoptions JOIN tblhostingconfigoptions ON (tblhostingconfigoptions.configid=tblproductconfigoptions.id) WHERE tblhostingconfigoptions.relid='.(int)$_REQUEST['hostingid']); 277 | $optionNames = array(); 278 | while($optionsRow=NcSql::fetchAssoc($r)){ 279 | $optionNames[] = $optionsRow['optionname']; 280 | if( 'san' == substr($optionsRow['optionname'],0,3)){ 281 | $certHasSanOption = true; 282 | } 283 | } 284 | 285 | 286 | $view['cert_has_san_option'] = $certHasSanOption; 287 | 288 | 289 | if(false==$row || $certHasSanOption){ 290 | $view['found'] = false; 291 | }else{ 292 | 293 | // select nc remote id 294 | $ssl_order = NcSql::sql2row('SELECT * FROM tblsslorders WHERE serviceid='.(int)$_REQUEST['hostingid']); 295 | 296 | if(false==$ssl_order){ 297 | $view['found'] = false; 298 | }else{ 299 | 300 | $view['found'] = true; 301 | $view['hosting'] = array( 302 | 'hostingid'=>$_REQUEST['hostingid'], 303 | 'orderid'=>$row['orderid'], 304 | 'domain'=>$row['domain'], 305 | 'productname'=>$row['productname'], 306 | 307 | 'ssl_order_remoteid'=>$ssl_order['remoteid'], 308 | 'ssl_order_certtype'=>$ssl_order['certtype'], 309 | 'ssl_order_id'=>$ssl_order['id'] 310 | 311 | ); 312 | 313 | if(isset($_REQUEST['message']) && 'updated'==$_REQUEST['message']){ 314 | $view['updated'] = true; 315 | }else{ 316 | $view['updated'] = false; 317 | } 318 | 319 | 320 | // final level verification 321 | // assign remote id 322 | if(!empty($_POST['remoteid'])&&!empty($_POST['ssl_order_id'])){ 323 | // two mysql queries 324 | 325 | // update whmcs native table 326 | NcSql::q('UPDATE tblsslorders SET remoteid='.(int)$_POST['remoteid'].' WHERE id='.(int)$_POST['ssl_order_id']); 327 | 328 | // update custom module table 329 | NcSql::q('UPDATE mod_namecheapssl SET certificate_id='.(int)$_POST['remoteid'].' WHERE id='.(int)$_POST['ssl_order_id']); 330 | 331 | // redirect 332 | $query_string = '?module=namecheap_ssl&action=sync&hostingid='.$_REQUEST['hostingid'].'&message=updated'; 333 | 334 | 335 | namecheapssl_log('addon.sync', 'addon_updated_remoteid', array($ssl_order['remoteid'], $_POST['remoteid']),$ssl_order['serviceid']); 336 | 337 | header('Location: ' . $query_string); 338 | exit(); 339 | 340 | } 341 | 342 | } 343 | } 344 | 345 | }else{ 346 | $view['hostingid'] = ''; 347 | } 348 | 349 | } 350 | else if ('list'==$action) 351 | { 352 | 353 | $users = array(); 354 | 355 | // production certs 356 | $userList = NcSql::sql2set("SELECT DISTINCT configoption1 AS user, configoption2 AS password, 'production' AS acc FROM tblproducts WHERE configoption9='' AND configoption1!='' AND configoption2!='' AND servertype='namecheapssl'"); 357 | foreach($userList as $row){ 358 | $view['userlist'][] = array( 359 | 'user'=>$row['user'], 360 | 'acc'=>'production' 361 | ); 362 | $users['production'][$row['user']] = $row; 363 | } 364 | 365 | // sandbox users 366 | $userList = NcSql::sql2set("SELECT DISTINCT configoption3 AS user, configoption4 AS password, 'sandbox' AS acc FROM tblproducts WHERE configoption9='on' AND configoption3!='' AND configoption4!='' AND servertype='namecheapssl'"); 367 | foreach($userList as $row){ 368 | $view['userlist'][] = array( 369 | 'user'=>$row['user'], 370 | 'acc'=>'sandbox' 371 | ); 372 | $users['sandbox'][$row['user']] = $row; 373 | } 374 | 375 | 376 | if(!empty($_REQUEST['user'])&&!empty($_REQUEST['acc'])){ 377 | 378 | 379 | if('sandbox'!=$_REQUEST['acc']&&'production'!=$_REQUEST['acc']){ 380 | echo 'unknown user'; 381 | exit(); 382 | } 383 | 384 | if(!empty($users[$_REQUEST['acc']][$_REQUEST['user']])){ 385 | $user = $users[$_REQUEST['acc']][$_REQUEST['user']]['user']; 386 | $password = $users[$_REQUEST['acc']][$_REQUEST['user']]['password']; 387 | }else{ 388 | echo 'unknown user'; 389 | exit(); 390 | } 391 | 392 | 393 | $view['user'] = array('user'=>$user,'acc'=>$_REQUEST['acc']); 394 | 395 | 396 | $itemsOnPage = 20; 397 | 398 | $page = empty($_REQUEST['page']) ? 1 : $_REQUEST['page']; 399 | $view['current_page'] = $page; 400 | 401 | $requestParams = array("Page" => $page, "PageSize" => $itemsOnPage); 402 | 403 | 404 | 405 | $api = new NamecheapApi($user, $password, $_REQUEST['acc']=='sandbox'); 406 | 407 | try{ 408 | $response = $api->request("namecheap.ssl.getList", $requestParams); 409 | $result = $api->parseResponse($response); 410 | 411 | if(!empty($result['SSLListResult']['SSL'])){ 412 | 413 | $items = array(); 414 | foreach ($result['SSLListResult']['SSL'] as $k=>$item){ 415 | 416 | // get whmcs product 417 | $items[$k]['namecheap'] = $item['@attributes']; 418 | 419 | $query = sprintf("SELECT serviceid,status FROM tblsslorders WHERE module='namecheapssl' AND remoteid='%s'", (int)$item['@attributes']['CertificateID']); 420 | $items[$k]['whmcs'] = NcSql::sql2row($query); 421 | 422 | } 423 | 424 | 425 | $view['items'] = $items; 426 | } 427 | 428 | $view['pages'] = array(); 429 | for($i=1;$i<=ceil($result['Paging']['TotalItems']/$itemsOnPage);++$i){ 430 | $view['pages'][] = $i; 431 | } 432 | 433 | 434 | }catch(Exception $e){ 435 | $view['globals']['error'] = $e->getMessage(); 436 | } 437 | 438 | 439 | } 440 | 441 | } 442 | else if ('settings'==$action) 443 | { 444 | 445 | // message 446 | $view['message'] = ''; 447 | if(!empty($_REQUEST['message']) && 'updated' == $_REQUEST['message']){ 448 | $view['message'] = $_LANG['ncssl_addon_changes_saved_success']; 449 | } 450 | 451 | // prepare information for view 452 | $view['settings'] = NcSql::sql2set_keyval("SELECT name,value FROM mod_namecheapssl_settings"); 453 | 454 | 455 | $view['control_options'] = array( 456 | 'sync_date_offset' => array( 457 | 0 => '0', 458 | 5 => '5', 459 | 15 => '15', 460 | 30 => '30' 461 | ) 462 | ); 463 | 464 | // process incoming data 465 | if(isset($_REQUEST['settings'])){ 466 | 467 | foreach($_REQUEST['settings'] as $name=>$value){ 468 | NcSql::q(sprintf("DELETE FROM mod_namecheapssl_settings WHERE name='%s'", NcSql::e($name))); 469 | NcSql::q(sprintf("INSERT INTO mod_namecheapssl_settings SET name='%s', value='%s'", NcSql::e($name),NcSql::e($value))); 470 | } 471 | 472 | // redirect 473 | $query_string = '?module=namecheap_ssl&action=settings&message=updated'; 474 | 475 | namecheapssl_log('addon.settings', 'addon_updated_settings'); 476 | 477 | 478 | header('Location: ' . $query_string); 479 | exit(); 480 | 481 | 482 | } 483 | 484 | } 485 | else 486 | { 487 | $action = 'default'; 488 | } 489 | 490 | 491 | $view['global']['mod_action_url'] = $view['global']['mod_url'] . '&action=' . $action; 492 | $view['global']['action'] = $action; 493 | 494 | include dirname(__FILE__) . '/templates/' . $action . '.php'; 495 | 496 | 497 | } 498 | 499 | function namecheap_ssl_clientarea($vars){ 500 | 501 | 502 | global $_LANG; 503 | namecheapssl_initlang(); 504 | 505 | 506 | $vars = array(); 507 | 508 | if(isset($_REQUEST['san_reduction'])){ 509 | $vars['notice'] = $_LANG['ncssl_addon_sun_reduction_notice']; 510 | } 511 | 512 | if(!empty($_REQUEST['revoke_message'])){ 513 | $vars['notice'] = $_LANG['ncssl_error_revoke_'.(int)$_REQUEST['revoke_message']]; 514 | } 515 | 516 | if(!empty($_REQUEST['serviceid'])){ 517 | $vars['back_to_service_id'] = (int)$_REQUEST['serviceid']; 518 | } 519 | 520 | 521 | return array( 522 | 523 | 'pagetitle' => 'Namecheap SSL Addon Module', 524 | 'breadcrumb' => array('index.php?m=namecheap_ssl'=>'Namecheap SSL Addon Module'), 525 | 'templatefile' => 'client_templates/notice', 526 | 'requirelogin' => true, 527 | 'vars' => $vars 528 | 529 | ); 530 | 531 | } 532 | -------------------------------------------------------------------------------- /modules/addons/namecheap_ssl/templates/default.php: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /modules/addons/namecheap_ssl/templates/list.php: -------------------------------------------------------------------------------- 1 | : 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
-
40 | 41 | : 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /modules/addons/namecheap_ssl/templates/log.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
, 18 | : 19 | 24 |
25 | 26 |
27 | 28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 41 |   42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
Service ID
-------------------------------------------------------------------------------- /modules/addons/namecheap_ssl/templates/settings.php: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 18 | 19 | 20 |
11 | 16 | 17 |
21 | 22 |

23 | 24 |

25 | 26 |
-------------------------------------------------------------------------------- /modules/addons/namecheap_ssl/templates/sync.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 | 34 | View Order 35 |
36 | :
37 | :
38 | :
39 | : 40 | 41 |
42 | : 43 | 44 | 45 | 46 |
47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /modules/servers/namecheapssl/lang/English.php: -------------------------------------------------------------------------------- 1 |
%filename%

with contents

%contents%

and put it to the following location on your hosting server: http(s)://example.com/.well-known/pki-validation/. It may take some time for file to be automatically validated and cert to be issued by Certificate Authority'; 163 | $_MOD_LANG['ncssl_download_certificate'] = "Download certificate"; 164 | 165 | 166 | $_MOD_LANG['ncssl_custom_phrase_sslcertapproveremaildetails'] = 'Please select any of emails if you wish to proceed with email-based validation. An approval email will be sent to selected address by Certificate Authority after activation.'; 167 | $_MOD_LANG['ncssl_custom_phrase_sslcertapproveremaildetails_http_based'] = '

If you select \'HTTP based validation\' option, you will need to place a certain file into a specific location of your server. Name and contents of the file will be provided at the last step of the activation process. No emails will be sent for Domain Control Validation.'; 168 | 169 | $_MOD_LANG['ncssl_custom_phrase_sslcertapproveremaildetails_san'] = 'Please select local part of emails you wish to receive your approval emails to. This local part will be used to send approval emails for all domains and subdomains.

For example, if \'admin@\' is selected as approver having main domain specified as \'domain.com\' and addon domain is \'sub.domain1.com\' , the approver emails will be sent to admin@domain.com and admin@sub.domain1.com.'; 170 | 171 | $_MOD_LANG['ncssl_custom_phrase_sslcertapproveremaildetails_san_http_based'] = '

If you select \'HTTP based validation\' option, you will need to place a certain file into a specific locations of servers for all of the domains specified while activation. Name and contents of the file will be provided at the last step of the activation process. No emails will be sent for Domain Control Validation.'; 172 | 173 | 174 | $_MOD_LANG['ncssl_san_items_title'] = 'Enter additional domains'; 175 | 176 | $_MOD_LANG['ncssl_san_items_item'] = 'Addon Domain '; 177 | $_MOD_LANG['ncssl_san_items_item_quick_ssl_premium'] = 'Addon Subdomain '; 178 | 179 | $_MOD_LANG['ncssl_san_csr_note'] = ' Domains included in SAN sections in CSR will be ignored! Please input addon domains in fields below the box for CSR. Please do not input main domain as addon domain. It is taken from CSR. Please make sure you do not use duplicates.'; 180 | 181 | $_MOD_LANG['ncssl_reissue_notice_step1'] = 'The following contact information will be used for reissue of your certificate:'; 182 | $_MOD_LANG['ncssl_reissue_notice_step2'] = 'The following information will be used for reissue of your certificate:'; 183 | 184 | $_MOD_LANG['ncssl_revoke_confirmation_text'] = 'Are you sure that you want to revoke the old certificates associated with this order? This will not affect latest active certificate, only the old reissued certificates will be revoked.'; 185 | $_MOD_LANG['ncssl_revoke_button'] = 'Revoke old certificates'; 186 | $_MOD_LANG['ncssl_revoke_button_description'] = 'Recommended before new reissue'; 187 | 188 | $_MOD_LANG['ncssl_error_2011166'] = 'Invalid domain name. Please use the domain name used during initial activation: '; 189 | 190 | 191 | $_MOD_LANG['ncssl_error_revoke_1'] = 'Revocation of reissued certificates associated with this order is unavailable right away due to limitations from Symantec. Please contact support for revocation of your reissued certificates'; 192 | $_MOD_LANG['ncssl_error_revoke_2'] = 'Your revocation request is being processed manually by admin. Revocation will be completed as soon as possible'; 193 | $_MOD_LANG['ncssl_error_revoke_3'] = 'Your revocation request is being processed manually. Revocation will be completed as soon as possible'; 194 | $_MOD_LANG['ncssl_error_revoke_4'] = 'Revocation of multiple instances of reissued certificates is temporary unavailable due to technical restrictions at Certificate Authority’s side. Please contact support for further assistance.'; 195 | 196 | 197 | $_MOD_LANG['ncssl_back_to_service'] = '« Back to the service'; 198 | 199 | $_MOD_LANG['ncsssl_jobtitle_required_for_symantec'] = 'Job Title is required'; 200 | 201 | 202 | $_MOD_LANG['ncssl_symantec_approver_email_notice'] = 'Approval email is not required for this type of certificate'; 203 | 204 | 205 | $_MOD_LANG['ncssl_latin_characters_notice'] = 'Only Latin characters can be used in the Admin information'; 206 | -------------------------------------------------------------------------------- /modules/servers/namecheapssl/namecheapapi.php: -------------------------------------------------------------------------------- 1 | _apiUser = $apiUser; 49 | $this->_apiKey = $apiKey; 50 | 51 | $this->setTestMode($testMode); 52 | 53 | $this->_debugMode = (bool)$debugMode; 54 | } 55 | 56 | /** 57 | * parseResponse 58 | * @param string $response 59 | * @return array 60 | */ 61 | public function parseResponse($response) 62 | { 63 | 64 | if (false === ($xml = simplexml_load_string($response))) { 65 | throw new NamecheapApiException("Unable to parse response"); 66 | } 67 | $result = $this->_xml2Array($xml); 68 | 69 | if(empty($result['@attributes']['Status']) || !isset($result['Server'])){ 70 | throw new NamecheapApiException("Response error. It is not look like normal api response. Please try again"); 71 | } 72 | 73 | 74 | if ("ERROR" == $result['@attributes']['Status']) { 75 | $errors = isset($result['Errors']['Error'][0]) ? $result['Errors']['Error'] : array($result['Errors']['Error']); 76 | 77 | $err = $errors[count($errors) - 1]; 78 | $err_msg = sprintf("[%s] %s", $err['@attributes']['Number'], $err['@value']) ; 79 | throw new NamecheapApiException($err_msg, $err['@attributes']['Number']); 80 | } 81 | 82 | 83 | 84 | return $result['CommandResponse']; 85 | } 86 | 87 | /** 88 | * request 89 | * @param string $command 90 | * @param array $params 91 | * @return string 92 | */ 93 | public function request($command, array $params) 94 | { 95 | $result = false; 96 | $curl_error = false; 97 | 98 | $this->_requestUrl = $this->_getApiUrl($command, $params); 99 | $this->_requestParams = $this->_getApiParams($command, $params); 100 | 101 | 102 | if ($this->_debugMode){ 103 | $logRequestParams = $this->_requestParams; 104 | if(!empty($logRequestParams['ApiKey'])){ 105 | $logRequestParams['ApiKey'] = '***'; 106 | } 107 | $this->_lastLogRecordId = namecheapssl_save_debug_info("REQUEST:\n".date('Y-m-d H:i:s')."\ncommand:".$command."\nparams:"."\n" . var_export($logRequestParams,true)."\n",$command); 108 | } 109 | 110 | 111 | if (extension_loaded("curl") && ($ch = curl_init()) !== false) 112 | { 113 | curl_setopt($ch, CURLOPT_URL, $this->_requestUrl); 114 | curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1); 115 | 116 | // we set peer verification of namecheap server to false - else the process will fail 117 | // if the host server doesnt have an accurate ca bundle. 118 | // Can turn this on, when you place an up to date ca bundle at your host server. 119 | 120 | if ($command == 'namecheap.ssl.activate' || strtolower($command) == 'namecheap.ssl.parsecsr' || strtolower($command) == 'namecheap.ssl.reissue') { 121 | curl_setopt($ch, CURLOPT_POST, 1); 122 | curl_setopt($ch, CURLOPT_POSTFIELDS, $this->_requestParams); 123 | } 124 | 125 | 126 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 127 | curl_setopt($ch, CURLOPT_HEADER, 0); 128 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 129 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 130 | $this->_response = curl_exec($ch); 131 | $curl_error = curl_error($ch); 132 | curl_close($ch); 133 | 134 | if($curl_error){ 135 | if($this->_debugMode){ 136 | namecheapssl_save_debug_info('Curl error: ' . $curl_error . ". Unable to request data from " . $this->_requestUrl,$command,true,$this->_lastLogRecordId); 137 | } 138 | throw new NamecheapApiException('Curl error: ' . $curl_error); 139 | } 140 | 141 | }else{ 142 | $message = "Unable to request data, curl extention is not loaded"; 143 | if($this->_debugMode){ 144 | namecheapssl_save_debug_info($message,$command,true,$this->_lastLogRecordId); 145 | } 146 | throw new NamecheapApiException($message); 147 | } 148 | /*else{ 149 | $this->_response = @file_get_contents($this->_requestUrl); 150 | if (!$this->_response) { 151 | $message = "Unable to request data from (file_get_contents used)" . $this->_requestUrl; 152 | if($this->_debugMode){ 153 | namecheapssl_save_debug_info($message,$command,true,$this->_lastLogRecordId); 154 | } 155 | throw new NamecheapApiException($message); 156 | } 157 | }*/ 158 | 159 | 160 | if ($this->_debugMode){ 161 | namecheapssl_save_debug_info("RESPONSE:\n".date('Y-m-d H:i:s')."\n".$this->_response."\n",$command,true,$this->_lastLogRecordId); 162 | } 163 | 164 | 165 | return $this->_response; 166 | } 167 | 168 | /** 169 | * setTestMode 170 | * @param boolean $flag 171 | */ 172 | public function setTestMode($flag) 173 | { 174 | $this->_testMode = (bool)$flag; 175 | } 176 | 177 | // private methods 178 | 179 | /** 180 | * formatPhone 181 | * @param string $phone 182 | * @return string 183 | */ 184 | private function _formatPhone($phone) 185 | { 186 | /** 187 | * Namecheap API phone format requirement is +NNN.NNNNNNNNNN 188 | */ 189 | 190 | $arg = $phone; 191 | 192 | // strip all non-digit characters 193 | $phone = preg_replace('/[^\d]/', '', $phone); 194 | 195 | // check country code 196 | $phone_code = ""; 197 | foreach (self::$_phoneCountryCodes as $v) { 198 | if (preg_match("/^$v\d+$/", $phone)) { 199 | $phone_code = $v; 200 | break; 201 | } 202 | } 203 | if (!$phone_code) { 204 | return $arg; 205 | } 206 | 207 | // add '+' and dot to result phone number 208 | $phone = preg_replace("/^$phone_code/", "+{$phone_code}.", $phone); 209 | return $phone; 210 | } 211 | 212 | /** 213 | * _getApiUrl 214 | * @param string $command 215 | * @param array $params 216 | * @return string 217 | */ 218 | private function _getApiUrl($command, array $params) 219 | { 220 | 221 | $isPost = false; 222 | if ($command == 'namecheap.ssl.activate' || strtolower($command) == 'namecheap.ssl.parsecsr' || strtolower($command) == 'namecheap.ssl.reissue') { 223 | $isPost = true; 224 | } 225 | 226 | if (!$isPost) { 227 | return ($this->_testMode ? self::$testUrl : self::$url) . '?' . 'SourceOfCall=WHMCS&' . http_build_query($this->_getApiParams($command, $params),'','&'); 228 | } else { 229 | return ($this->_testMode ? self::$testUrl : self::$url) . '?SourceOfCall=WHMCS'; 230 | } 231 | } 232 | 233 | /** 234 | * _getApiParams 235 | * @param string $command 236 | * @param array $params 237 | * @return string 238 | */ 239 | private function _getApiParams($command, array $params) 240 | { 241 | $params['Command'] = $command; 242 | $params['ApiUser'] = $this->_apiUser; 243 | $params['ApiKey'] = $this->_apiKey; 244 | 245 | if (!array_key_exists('UserName', $params) || !strlen($params['UserName'])) { 246 | $params['UserName'] = $params['ApiUser']; 247 | } 248 | if (!array_key_exists('ClientIp', $params)) { 249 | $params['ClientIp'] = $this->_getClientIp(); 250 | } 251 | 252 | // format phone/fax fields 253 | foreach ($params as $k => &$v) { 254 | if (preg_match('/(Phone|Fax)/i', $k)) { 255 | $v = trim($v); 256 | if(!empty($v)){ 257 | $v = $this->_formatPhone($v); 258 | } 259 | } 260 | } 261 | 262 | return $params; 263 | } 264 | 265 | /** 266 | * _getClientIp 267 | * @return string 268 | */ 269 | private function _getClientIp() 270 | { 271 | $clientip = $_SERVER['REMOTE_ADDR']; 272 | return $clientip ? $clientip : "10.11.12.13"; 273 | } 274 | 275 | /** 276 | * _xml2Array 277 | * @param string $xml 278 | * @return array 279 | */ 280 | private function _xml2Array($xml) 281 | { 282 | if (!($xml instanceof SimpleXMLElement)) { 283 | throw new NamecheapApiException("Not a SimpleXMLElement object"); 284 | } 285 | $result = array(); 286 | foreach ($xml->attributes() as $attrName => $attr) { 287 | $result['@attributes'][$attrName] = (string)$attr; 288 | } 289 | foreach ($xml->children() as $childName => $child) { 290 | if (array_key_exists($childName, $result)) { 291 | if (!is_array($result[$childName]) || !isset($result[$childName][1])) { 292 | $result[$childName] = array($result[$childName]); 293 | } 294 | $result[$childName][] = $this->_xml2Array($child); 295 | } else { 296 | $result[$childName] = $this->_xml2Array($child); 297 | } 298 | } 299 | $value = trim((string)$xml); 300 | if (array_keys($result)) { 301 | if ($value) { 302 | $result['@value'] = $value; 303 | } 304 | } else { 305 | $result = $value; 306 | } 307 | return $result; 308 | } 309 | 310 | /** 311 | * 312 | * @param string $xmlResponse 313 | * @return integer 314 | */ 315 | public function getGmtTS($response) 316 | { 317 | $gmt = 0; 318 | if (preg_match("/(-|\+)+([0-9:]+)<\/GMTTimeDifference>/", $response, $matches)) { 319 | $gmt = $matches[2]; 320 | $gmtsign = preg_replace("/-+/", "-", $matches[1]); 321 | $gmtsign = $gmtsign == '-' ? -1 : 1; 322 | list($gmth, $gmtm) = explode(":", $gmt); 323 | $gmt = $gmtsign*(($gmth*3600)+($gmtm*60)); 324 | } 325 | return $gmt; 326 | } 327 | 328 | public function getLastUrl() { 329 | return $this->_requestUrl; 330 | } 331 | public function getLastParams() { 332 | return $this->_requestParams; 333 | } 334 | public function getLastResponse() { 335 | return $this->_response; 336 | } 337 | } 338 | } 339 | 340 | 341 | if (!class_exists('NcSql')){ 342 | class NcSql{ 343 | 344 | protected static $_link; 345 | 346 | public static function getLink(){ 347 | 348 | $backtrace = debug_backtrace(); 349 | 350 | if(!empty(self::$_link)) return self::$_link; 351 | include(dirname(__FILE__).'/../../../configuration.php'); 352 | self::$_link = mysqli_connect($db_host, $db_username, $db_password, $db_name); 353 | return self::$_link; 354 | } 355 | 356 | public static function q($sql){ 357 | //echo $sql.'
'; 358 | $r = mysqli_query(self::getLink(), $sql); 359 | return $r; 360 | } 361 | 362 | public static function e($sql){ 363 | return mysqli_escape_string(self::getLink(),$sql); 364 | } 365 | 366 | public static function fetchAssoc($r){ 367 | return mysqli_fetch_assoc($r); 368 | } 369 | 370 | public static function fetchArray($r){ 371 | return mysqli_fetch_array($r); 372 | } 373 | 374 | public static function numRows($r){ 375 | return mysqli_num_rows($r); 376 | } 377 | 378 | public static function insertId(){ 379 | return mysqli_insert_id(self::getLink()); 380 | } 381 | 382 | public static function sql2set($sql){ 383 | $r = self::q($sql); 384 | if(!$r){ 385 | return false; 386 | } 387 | $row = array(); 388 | while ($row=mysqli_fetch_assoc($r)){ 389 | $result[]=$row; 390 | } 391 | return $result; 392 | } 393 | 394 | public static function sql2set_column($sql){ 395 | 396 | $data = self::sql2set($sql); 397 | $set = array(); 398 | if(!empty($data)){ 399 | 400 | $aKey = array_slice(array_keys($data[0]), 0, 1); 401 | $columnName = $aKey[0]; 402 | 403 | foreach($data as $v){ 404 | $set[] = $v[$columnName]; 405 | } 406 | 407 | } 408 | return $set; 409 | } 410 | 411 | public static function sql2row($sql){ 412 | $r = self::q($sql); 413 | if(!$r){ 414 | return false; 415 | } 416 | return mysqli_fetch_assoc($r); 417 | } 418 | 419 | public static function sqlNumRows($sql){ 420 | $r = self::q($sql); 421 | if(!$r){ 422 | return false; 423 | } 424 | return mysqli_num_rows($r); 425 | } 426 | 427 | public static function sql2set_keyval($sql){ 428 | $data = self::sql2set($sql); 429 | $set = array(); 430 | if(!empty($data)){ 431 | 432 | list($firstKey,$secondKey) = array_slice(array_keys($data[0]), 0, 2); 433 | foreach($data as $v){ 434 | $set[$v[$firstKey]] = $v[$secondKey]; 435 | } 436 | } 437 | return $set; 438 | } 439 | 440 | public static function sql2cell($sql){ 441 | $r = self::q($sql); 442 | if(!$r){ 443 | return false; 444 | } 445 | $row = mysqli_fetch_assoc($r); 446 | return array_shift($row); 447 | } 448 | 449 | public static function insert($table,$array){ 450 | self::q("INSERT INTO $table SET " . self::array2queryPart($array)); 451 | return mysqli_insert_id(self::getLink()); 452 | } 453 | 454 | public static function wrapInQuotes($string){ 455 | $arr = explode(',',$string); 456 | foreach($arr as $k=>$v){ 457 | $v = self::e($v); 458 | $arr[$k] = "'$v'"; 459 | } 460 | return implode(',',$arr); 461 | } 462 | 463 | public static function array2queryPart($array,$delimiter=','){ 464 | $s = ''; 465 | foreach($array as $k=>$v){ 466 | $s .= $k . "='".self::e($v)."'".$delimiter; 467 | } 468 | $s = substr_replace($s,'',strrpos($s,$delimiter)); 469 | return $s; 470 | } 471 | 472 | } 473 | } 474 | 475 | 476 | if (!class_exists('NcRevokeManager')){ 477 | 478 | class NcRevokeManager{ 479 | 480 | protected $_localCertInfo; 481 | protected $_params; 482 | 483 | public function __construct(NcLocalCertInfo $localCertInfo, array $params) { 484 | $this->_localCertInfo = $localCertInfo; 485 | $this->_params = $params; 486 | } 487 | 488 | public function showButton(){ 489 | 490 | if(!$this->_localCertInfo->getRemoteId()){ 491 | return false; 492 | } 493 | 494 | 495 | if(!$this->_localCertInfo->loadServerTypes()){ 496 | return false; 497 | } 498 | 499 | 500 | /*if('COMODO'!=$this->_localCertInfo->getProvider()){ 501 | return false; 502 | }*/ 503 | 504 | 505 | if(!$this->getRevokeInfoWasLoaded()){ 506 | 507 | 508 | // load revoke info 509 | $certsFromList = $this->loadRevokeInfo(); 510 | if(false===$certsFromList){ 511 | return false; 512 | } 513 | 514 | 515 | foreach($certsFromList as $item){ 516 | $this->addRemoteIdForRevocation($item['CertificateID']); 517 | } 518 | 519 | $this->setRevokeInfoWasLoaded(); 520 | 521 | } 522 | 523 | return $this->hasRemoteIdForRevocation(); 524 | 525 | } 526 | 527 | 528 | protected function loadRevokeInfo(){ 529 | 530 | // 1.1. Get info 531 | $remoteCertInfo = _namecheapssl_getCertificateInfo($this->_params, $this->_localCertInfo->getRemoteId()); 532 | if(!$remoteCertInfo){ 533 | return false; 534 | } 535 | 536 | 537 | $providerOrderId = $remoteCertInfo['SSLGetInfoResult']['Provider']['OrderID']; 538 | 539 | 540 | // 1.2. Check list, search the same provider order id 541 | $certsFromList = _namecheapssl_searchCertificateInfoInList($this->_params, 542 | array( 543 | 'Status' => 'replaced', 544 | 'ProviderOrderID' => $providerOrderId 545 | )); 546 | 547 | if(false===$certsFromList){ 548 | return false; 549 | } 550 | 551 | return $certsFromList; 552 | 553 | } 554 | 555 | 556 | public function hasRemoteIdForRevocation(){ 557 | $revokeData = $this->_localCertInfo->getRevokeData(); 558 | 559 | if(empty($revokeData['certs'])){ 560 | return false; 561 | } 562 | 563 | foreach($revokeData['certs'] as $item){ 564 | if(false===$item){ 565 | return true; 566 | } 567 | } 568 | 569 | } 570 | 571 | 572 | protected function getRevokeInfoWasLoaded(){ 573 | $revokeData = $this->_localCertInfo->getRevokeData(); 574 | return isset($revokeData['loaded']); 575 | } 576 | 577 | 578 | protected function setRevokeInfoWasLoaded(){ 579 | $revokeData = $this->_localCertInfo->getRevokeData(); 580 | $revokeData['loaded'] = true; 581 | $this->_localCertInfo->setRevokeData($revokeData); 582 | } 583 | 584 | 585 | public function addRemoteIdForRevocation($remoteId){ 586 | $revokeData = $this->_localCertInfo->getRevokeData(); 587 | $revokeData['certs'][$remoteId] = false; 588 | $this->_localCertInfo->setRevokeData($revokeData); 589 | } 590 | 591 | 592 | public function setRemoteIdRevoked($remoteId){ 593 | $revokeData = $this->_localCertInfo->getRevokeData(); 594 | $revokeData['certs'][$remoteId] = true; 595 | $this->_localCertInfo->setRevokeData($revokeData); 596 | } 597 | 598 | public function getRemoteIdForRevocation(){ 599 | 600 | $revokeData = $this->_localCertInfo->getRevokeData(); 601 | $ids = array(); 602 | 603 | if(empty($revokeData['certs'])){ 604 | return $ids; 605 | } 606 | 607 | foreach($revokeData['certs'] as $remoteId=>$bRevoked){ 608 | if(false===$bRevoked){ 609 | $ids[] = $remoteId; 610 | } 611 | } 612 | 613 | return $ids; 614 | 615 | } 616 | 617 | 618 | } 619 | 620 | 621 | 622 | } 623 | 624 | 625 | if (!class_exists('NcLocalCertInfo')){ 626 | 627 | class NcLocalCertInfo{ 628 | 629 | const EXCEPTION_SSL_LIST_IS_EMPTY = 'SSL types list is empty'; 630 | 631 | const CERTIFICATE_VALIDATION_TYPE_EV = 'ev'; 632 | const CERTIFICATE_VALIDATION_TYPE_OV = 'ov'; 633 | const CERTIFICATE_VALIDATION_TYPE_DOMAIN = 'domain'; 634 | 635 | 636 | const PROVIDER_COMODO = 'COMODO'; 637 | const PROVIDER_GEOTRUST = 'GEOTRUST'; 638 | const PROVIDER_VERISIGN = 'VERISIGN'; 639 | const PROVIDER_THAWTE = 'THAWTE'; 640 | 641 | 642 | protected $_nativeRow; 643 | protected $_customRow; 644 | 645 | protected static $_namecheapSSLTypesAdvanced; 646 | 647 | public function __construct($serviceId) { 648 | $this->_nativeRow = NcSql::sql2row(" SELECT * FROM tblsslorders WHERE serviceid='".(int)$serviceId."' "); 649 | if($this->_nativeRow){ 650 | $this->_customRow = NcSql::sql2row(" SELECT * FROM mod_namecheapssl WHERE id='" . (int)$this->_nativeRow['id'] . "' "); 651 | } 652 | } 653 | 654 | public function getType(){ 655 | return $this->_nativeRow['certtype']; 656 | } 657 | 658 | public function getRemoteId(){ 659 | return $this->_nativeRow['remoteid']; 660 | } 661 | 662 | public function inReissueState(){ 663 | return (bool)$this->_customRow['reissue']; 664 | } 665 | 666 | public function hasFileName(){ 667 | return !empty($this->_customRow['file_name']); 668 | } 669 | 670 | public function getConfigData($backuped=false){ 671 | 672 | $configdata = $backuped ? $this->_customRow['configdata_copy'] : $this->_nativeRow['configdata']; 673 | 674 | $result = unserialize($configdata); 675 | if(false==$result){ 676 | $result = unserialize(str_replace("\n", "\r\n", $configdata)); 677 | } 678 | return $result; 679 | 680 | } 681 | 682 | 683 | public function getRevokeData(){ 684 | $revokeData = array(); 685 | if(!empty($this->_customRow['revoke_data'])){ 686 | $revokeData = unserialize($this->_customRow['revoke_data']); 687 | } 688 | return $revokeData; 689 | } 690 | 691 | public function setRevokeData($revokeData){ 692 | 693 | $serializedRevokeData = serialize($revokeData); 694 | $this->_customRow['revoke_data'] = $serializedRevokeData; 695 | 696 | $sql = "UPDATE mod_namecheapssl SET revoke_data='".NcSql::e($serializedRevokeData)."' WHERE id='" . (int)$this->_customRow['id'] . "'"; 697 | NcSql::q($sql); 698 | 699 | } 700 | 701 | 702 | public function loadServerTypes(){ 703 | self::$_namecheapSSLTypesAdvanced = namecheapssl_getSslTypes(true); 704 | if(!self::$_namecheapSSLTypesAdvanced){ 705 | return false; 706 | }else{ 707 | return true; 708 | } 709 | } 710 | 711 | public function getProvider(){ 712 | 713 | if(empty(self::$_namecheapSSLTypesAdvanced)){ 714 | throw new NamecheapApiException(self::EXCEPTION_SSL_LIST_IS_EMPTY); 715 | } 716 | 717 | foreach(self::$_namecheapSSLTypesAdvanced as $info){ 718 | if( strtolower($info['Type']) == strtolower($this->_nativeRow['certtype']) ){ 719 | return strtoupper($info['Provider']); 720 | } 721 | } 722 | 723 | } 724 | 725 | 726 | public function getValidationType(){ 727 | if(empty(self::$_namecheapSSLTypesAdvanced)){ 728 | throw new NamecheapApiException(self::EXCEPTION_SSL_LIST_IS_EMPTY); 729 | } 730 | 731 | foreach(self::$_namecheapSSLTypesAdvanced as $info){ 732 | if( strtolower($info['Type']) == strtolower($this->_nativeRow['certtype']) ){ 733 | $type = strtolower($info['ValidationType']); 734 | if('org'=== substr($type, 0,3)){ 735 | return self::CERTIFICATE_VALIDATION_TYPE_OV; 736 | } 737 | if('ext'=== substr($type, 0,3)){ 738 | return self::CERTIFICATE_VALIDATION_TYPE_EV; 739 | } 740 | return self::CERTIFICATE_VALIDATION_TYPE_DOMAIN; 741 | } 742 | } 743 | } 744 | 745 | 746 | public function backupConfigData(){ 747 | if(empty($this->_customRow['configdata_copy'])){ 748 | $sql = "UPDATE mod_namecheapssl SET configdata_copy='".NcSql::e($this->_nativeRow['configdata'])."' WHERE id='" . (int)$this->_customRow['id'] . "'"; 749 | NcSql::q($sql); 750 | $this->_customRow['configdata_copy'] = $this->_nativeRow['configdata']; 751 | } 752 | } 753 | 754 | public function clearBackupedConfigData(){ 755 | $sql = "UPDATE mod_namecheapssl SET configdata_copy='' WHERE id='" . (int)$this->_customRow['id'] . "'"; 756 | NcSql::q($sql); 757 | } 758 | 759 | 760 | 761 | } 762 | 763 | } 764 | 765 | 766 | /** 767 | * NamecheapApiException 768 | */ 769 | if (!class_exists("NamecheapApiException")) { 770 | class NamecheapApiException extends Exception {} 771 | } 772 | 773 | -------------------------------------------------------------------------------- /modules/servers/namecheapssl/namecheaplog.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /modules/servers/namecheapssl/reissue_notice.tpl: -------------------------------------------------------------------------------- 1 |

2 | {$LANG.ncssl_client_reissue_notice_1} {$link} 3 |

4 |

5 | {$LANG.ncssl_client_reissue_notice_2} 6 |

7 | -------------------------------------------------------------------------------- /modules/servers/namecheapssl/show_validation_file_contents.tpl: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 |
8 | 9 |

{$phrase}

10 | -------------------------------------------------------------------------------- /modules/servers/namecheapssl/viewdetails.tpl: -------------------------------------------------------------------------------- 1 | {if $domain neq ''} 2 |

{$LANG.ncssl_certificate_details_for} {$domain}

3 | {else} 4 |

{$LANG.ncssl_certificate_details}

5 | {/if} 6 | 7 | {*if $status eq 'not_exists'} 8 | {$LANG.ncssl_no_certificate_exists} 9 | {/if*} 10 | 11 | {if $status neq 'not_exists'} 12 | 13 | 14 | 15 | 16 | {if !$httpBasedValidation}{/if} 17 | 18 | {if $sansCount} 19 | 20 | 21 | {/if} 22 |
{$LANG.ncssl_domain}{$domain}
{$LANG.ncssl_status}{$status}
{$LANG.ncssl_type}{$type}
{$LANG.ncssl_approver_email}{$approverEmail}
{$LANG.ncssl_admin_email}{$adminEmail}
{$LANG.ncssl_admin_viewdetails_count_of_sans}{$sansCount}
{$LANG.ncssl_admin_viewdetails_sans} {$sans}
23 |
24 | {/if} 25 | {if $status eq 'newpurchase' or $status eq 'newrenewal' or $status eq 'not_exists' or ($status eq 'inprogress' and $renewal)} 26 |
27 | 28 | {* *} 29 | 30 |
31 | {elseif $status eq 'active'} 32 | {*
33 | 34 | 35 | 36 | 37 |
*} 38 |
39 | 40 | 41 | 42 | 43 |
44 | {* elseif $status neq 'active' and $status neq 'cancelled' *} 45 | {elseif ($status eq 'inprogress' or $status eq 'purchased')} 46 | 47 | {if empty($httpBasedValidation)} 48 |
49 | 50 | 51 | 52 | 53 |
54 | 55 | {else} 56 |
57 | 58 | 59 | 60 | 61 |
62 | {/if} 63 | 64 | {/if} 65 | 66 | {if $status eq 'active'} 67 |
68 |
69 | 70 | 71 | 72 | 73 |
74 |
75 | 76 | {if $showRevokeButton} 77 |
78 |
79 | 80 | 81 | 82 | 83 | {$LANG.ncssl_revoke_button_description} 84 |
85 |
86 | {/if} 87 | 88 | {/if} 89 | --------------------------------------------------------------------------------