Improve display of S/MIME certificates
parent
511aa63a34
commit
7ebdac5525
|
@ -1,6 +1,6 @@
|
|||
/* NSData+SMIME.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2017 Inverse inc.
|
||||
* Copyright (C) 2017-2018 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -33,6 +33,7 @@
|
|||
- (NGMimeMessage *) messageFromEncryptedDataAndCertificate: (NSData *) theCertificate;
|
||||
- (NSData *) convertPKCS12ToPEMUsingPassword: (NSString *) thePassword;
|
||||
- (NSData *) convertPKCS7ToPEM;
|
||||
- (NSDictionary *) certificateDescription;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* NSData+SMIME.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2017 Inverse inc.
|
||||
* Copyright (C) 2017-2018 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
|
@ -36,6 +37,7 @@
|
|||
#include <openssl/pem.h>
|
||||
#endif
|
||||
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import "NSData+SMIME.h"
|
||||
|
||||
@implementation NSData (SOGoMailSMIME)
|
||||
|
@ -457,4 +459,60 @@
|
|||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract usefull information from PEM certificate
|
||||
*/
|
||||
- (NSDictionary *) certificateDescription
|
||||
{
|
||||
BIO *pemBio;
|
||||
NSDictionary *data;
|
||||
X509 *x;
|
||||
|
||||
data = nil;
|
||||
OpenSSL_add_all_algorithms();
|
||||
pemBio = BIO_new_mem_buf((void *) [self bytes], [self length]);
|
||||
x = PEM_read_bio_X509(pemBio, NULL, 0, NULL);
|
||||
|
||||
if (x)
|
||||
{
|
||||
BIO *buf;
|
||||
char p[1024];
|
||||
NSString *subject, *issuer;
|
||||
|
||||
memset(p, 0, 1024);
|
||||
buf = BIO_new(BIO_s_mem());
|
||||
X509_NAME_print_ex(buf, X509_get_subject_name(x), 0,
|
||||
ASN1_STRFLGS_ESC_CTRL | XN_FLAG_SEP_MULTILINE | XN_FLAG_FN_LN);
|
||||
BIO_read(buf, p, 1024);
|
||||
subject = [NSString stringWithUTF8String: p];
|
||||
BIO_free(buf);
|
||||
|
||||
memset(p, 0, 1024);
|
||||
buf = BIO_new(BIO_s_mem());
|
||||
X509_NAME_print_ex(buf, X509_get_issuer_name(x), 0,
|
||||
ASN1_STRFLGS_ESC_CTRL | XN_FLAG_SEP_MULTILINE | XN_FLAG_FN_LN);
|
||||
BIO_read(buf, p, 1024);
|
||||
issuer = [NSString stringWithUTF8String: p];
|
||||
BIO_free(buf);
|
||||
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[subject componentsFromMultilineDN], @"subject",
|
||||
[issuer componentsFromMultilineDN], @"issuer",
|
||||
nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
int err = ERR_get_error();
|
||||
const char* sslError;
|
||||
NSString *error;
|
||||
|
||||
ERR_load_crypto_strings();
|
||||
sslError = ERR_reason_error_string(err);
|
||||
error = [NSString stringWithUTF8String: sslError];
|
||||
NSLog(@"FATAL: failed to read certificate: %@", error);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
"You cannot (un)subscribe to a folder that you own!" = "You cannot (un)subscribe to a folder that you own!";
|
||||
|
||||
/* SMIME Certificate field */
|
||||
"S/MIME Certificate" = "S/MIME Certificate";
|
||||
"Subject Name" = "Subject Name";
|
||||
"Issuer" = "Issuer";
|
||||
"countryName" = "Country";
|
||||
|
|
|
@ -239,6 +239,12 @@
|
|||
"Unable to subscribe to that folder!"
|
||||
= "Unable to subscribe to that folder.";
|
||||
|
||||
/* security */
|
||||
"Security" = "Security";
|
||||
"Uninstall" = "Uninstall";
|
||||
"Error reading the card certificate." = "Error reading the card certificate.";
|
||||
"No certificate associated to card." = "No certificate associated to card.";
|
||||
|
||||
/* acls */
|
||||
"Access rights to" = "Access rights to";
|
||||
"For user" = "For user";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* UIxContactActions.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2010-2016 Inverse inc.
|
||||
* Copyright (C) 2010-2018 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
|
||||
|
@ -30,6 +31,8 @@
|
|||
|
||||
#import <Contacts/SOGoContactGCSEntry.h>
|
||||
|
||||
#import <Mailer/NSData+SMIME.h>
|
||||
|
||||
#import <SOGoUI/SOGoDirectAction.h>
|
||||
|
||||
@interface NGVCard (SOGoActionCategory)
|
||||
|
@ -147,4 +150,46 @@
|
|||
return response;
|
||||
}
|
||||
|
||||
- (WOResponse *) certificateAction
|
||||
{
|
||||
NSData *pkcs7;
|
||||
NSDictionary *data;
|
||||
WOResponse *response;
|
||||
|
||||
pkcs7 = [[[self clientObject] vCard] certificate];
|
||||
|
||||
if (pkcs7)
|
||||
{
|
||||
data = [[pkcs7 convertPKCS7ToPEM] certificateDescription];
|
||||
if (data)
|
||||
{
|
||||
response = [self responseWithStatus: 200 andJSONRepresentation: data];
|
||||
}
|
||||
else
|
||||
{
|
||||
data = [NSDictionary
|
||||
dictionaryWithObject: [self labelForKey: @"Error reading the card certificate."]
|
||||
forKey: @"message"];
|
||||
response = [self responseWithStatus: 500 andJSONRepresentation: data];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data = [NSDictionary
|
||||
dictionaryWithObject: [self labelForKey: @"No certificate associated to card."]
|
||||
forKey: @"message"];
|
||||
response = [self responseWithStatus: 404 andJSONRepresentation: data];
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
- (WOResponse *) removeCertificateAction
|
||||
{
|
||||
[[[self clientObject] vCard] setCertificate: nil];
|
||||
|
||||
return [self responseWith204];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -252,6 +252,7 @@
|
|||
* @apiSuccess (Success 200) {String[]} allCategories All available categories
|
||||
* @apiSuccess (Success 200) {Object[]} [categories] Categories assigned to the card
|
||||
* @apiSuccess (Success 200) {String} categories.value Category name
|
||||
* @apiSuccess (Success 200) {Number} hasCertificate 1 if contact has a mail certificate
|
||||
* @apiSuccess (Success 200) {Object[]} [addresses] Postal addresses
|
||||
* @apiSuccess (Success 200) {String} addresses.type Type (e.g., home or work)
|
||||
* @apiSuccess (Success 200) {String} addresses.postoffice Post office box
|
||||
|
@ -330,6 +331,10 @@
|
|||
[data setObject: [values subarrayWithRange: NSMakeRange(1, [values count] - 1)] forKey: @"orgs"];
|
||||
}
|
||||
|
||||
o = [card certificate];
|
||||
if ([o length])
|
||||
[data setObject: [NSNumber numberWithBool: YES] forKey: @"hasCertificate"];
|
||||
|
||||
o = [card birthday];
|
||||
if (o)
|
||||
[data setObject: [o descriptionWithCalendarFormat: @"%Y-%m-%d"]
|
||||
|
|
|
@ -234,6 +234,16 @@
|
|||
actionClass = "UIxContactActions";
|
||||
actionName = "raw";
|
||||
};
|
||||
certificate = {
|
||||
protectedBy = "View";
|
||||
actionClass = "UIxContactActions";
|
||||
actionName = "certificate";
|
||||
};
|
||||
removeCertificate = {
|
||||
protectedBy = "Change Images And Files";
|
||||
actionClass = "UIxContactActions";
|
||||
actionName = "removeCertificate";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -249,6 +249,9 @@
|
|||
/* Encrypted message notification */
|
||||
"This message is encrypted" = "This message is encrypted";
|
||||
|
||||
/* Encrypted message but no certificate */
|
||||
"This message can't be decrypted. Please make sure you have uploaded your S/MIME certificate from the mail preferences module." = "This message can't be decrypted. Please make sure you have uploaded your S/MIME certificate from the mail preferences module.";
|
||||
|
||||
/* OpenSSL certificate error - unknown issuer */
|
||||
"certificate verify error" = "Unable to verify message signature";
|
||||
|
||||
|
|
|
@ -208,60 +208,25 @@
|
|||
|
||||
if (pem)
|
||||
{
|
||||
BIO *pemBio;
|
||||
X509 *x;
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
ERR_load_crypto_strings();
|
||||
pemBio = BIO_new_mem_buf((void *) [pem bytes], [pem length]);
|
||||
x = PEM_read_bio_X509(pemBio, NULL, 0, NULL);
|
||||
if (x)
|
||||
data = [pem certificateDescription];
|
||||
if (data)
|
||||
{
|
||||
BIO *buf;
|
||||
char p[1024];
|
||||
NSString *subject, *issuer;
|
||||
|
||||
memset(p, 0, 1024);
|
||||
buf = BIO_new(BIO_s_mem());
|
||||
X509_NAME_print_ex(buf, X509_get_subject_name(x), 0,
|
||||
ASN1_STRFLGS_ESC_CTRL | XN_FLAG_SEP_MULTILINE | XN_FLAG_FN_LN);
|
||||
BIO_read(buf, p, 1024);
|
||||
subject = [NSString stringWithUTF8String: p];
|
||||
BIO_free(buf);
|
||||
|
||||
memset(p, 0, 1024);
|
||||
buf = BIO_new(BIO_s_mem());
|
||||
X509_NAME_print_ex(buf, X509_get_issuer_name(x), 0,
|
||||
ASN1_STRFLGS_ESC_CTRL | XN_FLAG_SEP_MULTILINE | XN_FLAG_FN_LN);
|
||||
BIO_read(buf, p, 1024);
|
||||
issuer = [NSString stringWithUTF8String: p];
|
||||
BIO_free(buf);
|
||||
|
||||
data = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[subject componentsFromMultilineDN], @"subject",
|
||||
[issuer componentsFromMultilineDN], @"issuer",
|
||||
nil];
|
||||
response = [self responseWithStatus: 200
|
||||
andJSONRepresentation: data];
|
||||
response = [self responseWithStatus: 200 andJSONRepresentation: data];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"FATAL: failed to read certificate.");
|
||||
data = [NSDictionary
|
||||
dictionaryWithObject: [self labelForKey: @"Error reading the certificate. Please install a new certificate."]
|
||||
forKey: @"message"];
|
||||
response = [self responseWithStatus: 500
|
||||
andJSONRepresentation: data];
|
||||
response = [self responseWithStatus: 500 andJSONRepresentation: data];
|
||||
}
|
||||
|
||||
BIO_free(pemBio);
|
||||
X509_free(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = [self responseWithStatus: 404
|
||||
andJSONRepresentation: [NSDictionary dictionaryWithObject: [self labelForKey: @"No certificate associated to account."]
|
||||
forKey: @"message"]];
|
||||
data = [NSDictionary
|
||||
dictionaryWithObject: [self labelForKey: @"No certificate associated to account."]
|
||||
forKey: @"message"];
|
||||
response = [self responseWithStatus: 404 andJSONRepresentation: data];
|
||||
}
|
||||
|
||||
return response;
|
||||
|
|
|
@ -206,7 +206,6 @@
|
|||
"Please specify a valid reply-to address." = "Please specify a valid reply-to address.";
|
||||
"Specify a hostname other than the local host" = "Specify a hostname other than the local host";
|
||||
|
||||
"S/MIME Certificate" = "S/MIME Certificate";
|
||||
"No certificate installed" = "No certificate installed";
|
||||
"The SSL certificate must use the PKCS#12 (PFX) format." = "The SSL certificate must use the PKCS#12 (PFX) format.";
|
||||
"Uninstall" = "Uninstall";
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant"
|
||||
xmlns:label="OGo:label">
|
||||
xmlns:label="OGo:label"
|
||||
xmlns:rsrc="OGo:url">
|
||||
|
||||
<div layout="column" class="layout-fill sg-reversible">
|
||||
<md-card style="overflow: hidden">
|
||||
|
@ -131,6 +132,48 @@
|
|||
</md-autocomplete>
|
||||
</md-chips>
|
||||
|
||||
<!-- S/MIME certificate -->
|
||||
<div class="section" ng-if="editor.card.hasCertificate">
|
||||
<div class="pseudo-input-container">
|
||||
<label class="pseudo-input-label"><var:string label:value="Security"/></label>
|
||||
<sg-block-toggle class="sg-no-print" layout="column">
|
||||
<md-list-item class="sg-button-toggle">
|
||||
<p class="md-flex">
|
||||
<md-icon rsrc:md-svg-src="img/certificate.svg"><!-- certificate --></md-icon>
|
||||
{{::'S/MIME Certificate' | loc}}
|
||||
</p>
|
||||
<md-button class="md-warn"
|
||||
ng-click="editor.card.$removeCertificate()">
|
||||
<var:string label:value="Uninstall"/>
|
||||
</md-button>
|
||||
<md-icon class="sg-icon-toggle">expand_more</md-icon>
|
||||
</md-list-item>
|
||||
<div class="sg-block-toggle">
|
||||
<div class="md-margin" md-whiteframe="3">
|
||||
<div class="md-padding" layout="row" layout-wrap="layout-wrap">
|
||||
<div flex="50" flex-xs="100">
|
||||
<div class="md-subhead md-default-theme md-fg md-primary"
|
||||
ng-bind="::'Subject Name' | loc"><!-- Subject Name --></div>
|
||||
<div ng-repeat="field in editor.certificate.subject">
|
||||
<div class="pseudo-input-label" ng-bind="field[0] | loc"><!-- label --></div>
|
||||
<div class="pseudo-input-field md-body-1" ng-bind="field[1]"><!-- value --></div>
|
||||
</div>
|
||||
</div>
|
||||
<div flex="50" flex-xs="100">
|
||||
<div class="md-subhead md-default-theme md-fg md-primary"
|
||||
ng-bind="::'Issuer' | loc"><!-- Issuer --></div>
|
||||
<div ng-repeat="field in editor.certificate.issuer">
|
||||
<div class="pseudo-input-label" ng-bind="field[0] | loc"><!-- label --></div>
|
||||
<div class="pseudo-input-field md-body-1" ng-bind="field[1]"><!-- value --></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</sg-block-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- emails -->
|
||||
<div class="section">
|
||||
<div class="attr" ng-repeat="email in editor.card.emails">
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant"
|
||||
xmlns:label="OGo:label">
|
||||
xmlns:label="OGo:label"
|
||||
xmlns:rsrc="OGo:url">
|
||||
|
||||
<div class="sg-reversible" ng-class="{ 'sg-flip': editor.showRawSource }">
|
||||
<div class="sg-face" layout="column" layout-fill="layout-fill">
|
||||
|
@ -102,6 +103,44 @@
|
|||
</md-list>
|
||||
</div>
|
||||
|
||||
<!-- S/MIME certificate -->
|
||||
<div class="section" ng-if="editor.card.hasCertificate">
|
||||
<div class="pseudo-input-container">
|
||||
<label class="pseudo-input-label"><var:string label:value="Security"/></label>
|
||||
<sg-block-toggle class="sg-no-print" layout="column">
|
||||
<md-list-item class="sg-button-toggle">
|
||||
<p class="md-flex">
|
||||
<md-icon rsrc:md-svg-src="img/certificate.svg"><!-- certificate --></md-icon>
|
||||
{{::'S/MIME Certificate' | loc}}
|
||||
</p>
|
||||
<md-icon class="sg-icon-toggle">expand_more</md-icon>
|
||||
</md-list-item>
|
||||
<div class="sg-block-toggle">
|
||||
<div class="md-margin" md-whiteframe="3">
|
||||
<div class="md-padding" layout="row" layout-wrap="layout-wrap">
|
||||
<div flex="50" flex-xs="100">
|
||||
<div class="md-subhead md-default-theme md-fg md-primary"
|
||||
ng-bind="::'Subject Name' | loc"><!-- Subject Name --></div>
|
||||
<div ng-repeat="field in editor.certificate.subject">
|
||||
<div class="pseudo-input-label" ng-bind="field[0] | loc"><!-- label --></div>
|
||||
<div class="pseudo-input-field md-body-1" ng-bind="field[1]"><!-- value --></div>
|
||||
</div>
|
||||
</div>
|
||||
<div flex="50" flex-xs="100">
|
||||
<div class="md-subhead md-default-theme md-fg md-primary"
|
||||
ng-bind="::'Issuer' | loc"><!-- Issuer --></div>
|
||||
<div ng-repeat="field in editor.certificate.issuer">
|
||||
<div class="pseudo-input-label" ng-bind="field[0] | loc"><!-- label --></div>
|
||||
<div class="pseudo-input-field md-body-1" ng-bind="field[1]"><!-- value --></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</sg-block-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section" ng-show="editor.card.emails.length > 0">
|
||||
<div class="pseudo-input-container" ng-repeat="email in editor.card.emails">
|
||||
<label class="pseudo-input-label"><var:entity const:name="nbsp"/>{{email.type.capitalize() | loc}}</label>
|
||||
|
|
|
@ -211,10 +211,10 @@
|
|||
<md-divider><!-- divider --></md-divider>
|
||||
<md-list-item class="sg-button-toggle">
|
||||
<div>
|
||||
<md-icon ng-hide="::viewer.message.$smime.validSignature"
|
||||
<md-icon ng-hide="::viewer.message.$smime.valid"
|
||||
class="md-warn"
|
||||
rsrc:md-svg-src="img/certificate-off.svg"><!-- certificate --></md-icon>
|
||||
<md-icon ng-show="::viewer.message.$smime.validSignature"
|
||||
<md-icon ng-show="::viewer.message.$smime.valid"
|
||||
class="md-accent"
|
||||
rsrc:md-svg-src="img/certificate.svg"><!-- certificate --></md-icon>
|
||||
</div>
|
||||
|
@ -249,10 +249,13 @@
|
|||
<div class="sg-no-print" layout="column"
|
||||
ng-show="viewer.message.$smime.isEncrypted">
|
||||
<md-divider><!-- divider --></md-divider>
|
||||
<div layout="row" layout-align="start center">
|
||||
<md-icon>lock_outline</md-icon>
|
||||
<md-list-item>
|
||||
<div>
|
||||
<md-icon ng-show="::viewer.message.$smime.valid">lock_outline</md-icon>
|
||||
<md-icon ng-hide="::viewer.message.$smime.valid" class="md-warn">lock_outline</md-icon>
|
||||
</div>
|
||||
<p class="md-padding md-flex" ng-bind-html="::viewer.message.$smime.message"><!-- message --></p>
|
||||
</div>
|
||||
</md-list-item>
|
||||
</div>
|
||||
|
||||
<!-- Load external images -->
|
||||
|
|
|
@ -187,9 +187,9 @@
|
|||
<!-- S/MIME Certificate -->
|
||||
<sg-block-toggle class="sg-no-print" layout="column">
|
||||
<md-list-item class="sg-button-toggle">
|
||||
<md-icon rsrc:md-svg-src="img/certificate.svg"><!-- certificate --></md-icon>
|
||||
<p class="md-flex">
|
||||
<var:string label:value="S/MIME Certificate"/>
|
||||
<md-icon rsrc:md-svg-src="img/certificate.svg"><!-- certificate --></md-icon>
|
||||
{{::'S/MIME Certificate' | loc}}
|
||||
</p>
|
||||
<md-button class="md-warn"
|
||||
ng-click="$AccountDialogController.removeCertificate()">
|
||||
|
|
|
@ -38,10 +38,11 @@
|
|||
* @desc The factory we'll use to register with Angular.
|
||||
* @returns the Card constructor
|
||||
*/
|
||||
Card.$factory = ['$timeout', 'sgSettings', 'sgCard_STATUS', 'Resource', 'Preferences', function($timeout, Settings, Card_STATUS, Resource, Preferences) {
|
||||
Card.$factory = ['$q', '$timeout', 'sgSettings', 'sgCard_STATUS', 'Resource', 'Preferences', function($q, $timeout, Settings, Card_STATUS, Resource, Preferences) {
|
||||
angular.extend(Card, {
|
||||
STATUS: Card_STATUS,
|
||||
$$resource: new Resource(Settings.activeUser('folderURL') + 'Contacts', Settings.activeUser()),
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
$Preferences: Preferences
|
||||
});
|
||||
|
@ -485,6 +486,44 @@
|
|||
return this.refs.length - 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $certificate
|
||||
* @memberof Account.prototype
|
||||
* @desc View the S/MIME certificate details associated to the account.
|
||||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Card.prototype.$certificate = function() {
|
||||
var _this = this;
|
||||
|
||||
if (this.hasCertificate) {
|
||||
if (this.$$certificate)
|
||||
return Card.$q.when(this.$$certificate);
|
||||
else {
|
||||
return Card.$$resource.fetch([this.pid, this.id].join('/'), 'certificate').then(function(data) {
|
||||
_this.$$certificate = data;
|
||||
return data;
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
return Card.$q.reject();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $removeCertificate
|
||||
* @memberof Account.prototype
|
||||
* @desc Remove any S/MIME certificate associated with the account.
|
||||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Card.prototype.$removeCertificate = function() {
|
||||
var _this = this;
|
||||
|
||||
return Card.$$resource.fetch([this.pid, this.id].join('/'), 'removeCertificate').then(function() {
|
||||
_this.hasCertificate = false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function explode
|
||||
* @memberof Card.prototype
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
|
||||
_registerHotkeys(hotkeys);
|
||||
_loadCertificate();
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
// Deregister hotkeys
|
||||
|
@ -71,6 +72,15 @@
|
|||
});
|
||||
}
|
||||
|
||||
function _loadCertificate() {
|
||||
if (vm.card.hasCertificate)
|
||||
vm.card.$certificate().then(function(crt) {
|
||||
vm.certificate = crt;
|
||||
}, function() {
|
||||
delete vm.card.hasCertificate;
|
||||
});
|
||||
}
|
||||
|
||||
function transformCategory(input) {
|
||||
if (angular.isString(input))
|
||||
return { value: input };
|
||||
|
|
|
@ -298,7 +298,7 @@
|
|||
var formattedMessage = "<p>" + part.error.replace(/\n/, "</p><p class=\"md-caption\">");
|
||||
formattedMessage = formattedMessage.replace(/\n/g, "</p><p class=\"md-caption\">") + "</p>";
|
||||
_this.$smime = {
|
||||
validSignature: part.valid,
|
||||
valid: part.valid,
|
||||
certificate: part.certificates[part.certificates.length - 1],
|
||||
message: formattedMessage
|
||||
};
|
||||
|
@ -306,8 +306,12 @@
|
|||
else if (part.type == 'UIxMailPartEncryptedViewer') {
|
||||
_this.$smime = {
|
||||
isEncrypted: true,
|
||||
message: l("This message is encrypted")
|
||||
valid: part.valid
|
||||
};
|
||||
if (part.valid)
|
||||
_this.$smime.message = l("This message is encrypted");
|
||||
else
|
||||
_this.$smime.message = l("This message can't be decrypted. Please make sure you have uploaded your S/MIME certificate from the mail preferences module.");
|
||||
}
|
||||
_.forEach(part.content, function(mixedPart) {
|
||||
_visit(mixedPart);
|
||||
|
|
Loading…
Reference in New Issue