mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-28 19:49:20 +03:00
Added isSMimeEncrypted() and isSMimeSigned() #259
This commit is contained in:
parent
3648b3eb60
commit
7b3102a6b3
5 changed files with 77 additions and 27 deletions
|
|
@ -127,9 +127,9 @@ class BodyStructure implements \JsonSerializable
|
|||
return 'text/html' === $this->sContentType || 'text/plain' === $this->sContentType;
|
||||
}
|
||||
|
||||
public function IsPgpEncrypted() : bool
|
||||
// https://datatracker.ietf.org/doc/html/rfc3156#section-4
|
||||
public function isPgpEncrypted() : bool
|
||||
{
|
||||
// https://datatracker.ietf.org/doc/html/rfc3156#section-4
|
||||
return 'multipart/encrypted' === $this->sContentType
|
||||
&& !empty($this->aContentTypeParams['protocol'])
|
||||
&& 'application/pgp-encrypted' === \strtolower(\trim($this->aContentTypeParams['protocol']))
|
||||
|
|
@ -140,20 +140,39 @@ class BodyStructure implements \JsonSerializable
|
|||
// && 'Version: 1' === $this->aSubParts[0]->Body()
|
||||
}
|
||||
|
||||
public function IsPgpSigned() : bool
|
||||
// https://datatracker.ietf.org/doc/html/rfc3156#section-5
|
||||
public function isPgpSigned() : bool
|
||||
{
|
||||
// https://datatracker.ietf.org/doc/html/rfc3156#section-5
|
||||
return 'multipart/signed' === $this->sContentType
|
||||
&& !empty($this->aContentTypeParams['protocol'])
|
||||
&& 'application/pgp-signature' === \strtolower(\trim($this->aContentTypeParams['protocol']))
|
||||
// The multipart/signed body MUST consist of exactly two parts.
|
||||
&& 2 === \count($this->aSubParts)
|
||||
&& $this->aSubParts[1]->IsPgpSignature();
|
||||
&& 'application/pgp-signature' === $this->aSubParts[1]->ContentType();
|
||||
}
|
||||
|
||||
public function IsPgpSignature() : bool
|
||||
// https://datatracker.ietf.org/doc/html/rfc2633#section-3.3
|
||||
public function isSMimeEncrypted() : bool
|
||||
{
|
||||
return \in_array($this->sContentType, ['application/pgp-signature', 'application/pkcs7-signature']);
|
||||
$type = \strtolower(\trim($this->aContentTypeParams['smime-type'] ?? ''));
|
||||
return 'application/pkcs7-mime' === $this->sContentType
|
||||
&& !empty($this->aContentTypeParams['smime-type'])
|
||||
&& ('enveloped-data' === $type || 'authenveloped-data' === $type);
|
||||
}
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc8551.html#section-3.5
|
||||
public function isSMimeSigned() : bool
|
||||
{
|
||||
return ('multipart/signed' === $this->sContentType
|
||||
&& !empty($this->aContentTypeParams['protocol'])
|
||||
&& 'application/pkcs7-signature' === \strtolower(\trim($this->aContentTypeParams['protocol']))
|
||||
// The multipart/signed body MUST consist of exactly two parts.
|
||||
&& 2 === \count($this->aSubParts)
|
||||
&& 'application/pkcs7-signature' === $this->aSubParts[1]->ContentType()
|
||||
) || ('application/pkcs7-mime' === $this->sContentType
|
||||
&& !empty($this->aContentTypeParams['smime-type'])
|
||||
&& 'signed-data' === \strtolower(\trim($this->aContentTypeParams['smime-type']))
|
||||
);
|
||||
}
|
||||
|
||||
public function IsAttachment() : bool
|
||||
|
|
@ -192,7 +211,7 @@ class BodyStructure implements \JsonSerializable
|
|||
if (!$aParts) {
|
||||
$gEncryptedParts = $this->SearchByContentType('multipart/encrypted');
|
||||
foreach ($gEncryptedParts as $oPart) {
|
||||
if ($oPart->IsPgpEncrypted() && $oPart->SubParts()[1]->isInline()) {
|
||||
if ($oPart->isPgpEncrypted() && $oPart->SubParts()[1]->isInline()) {
|
||||
return array($oPart->SubParts()[1]);
|
||||
}
|
||||
}
|
||||
|
|
@ -242,7 +261,7 @@ class BodyStructure implements \JsonSerializable
|
|||
{
|
||||
return $this->SearchByCallback(function ($oItem, $oParent) {
|
||||
// return $oItem->IsAttachment();
|
||||
return $oItem->IsAttachment() && (!$oParent || !$oParent->IsPgpEncrypted());
|
||||
return $oItem->IsAttachment() && (!$oParent || !$oParent->isPgpEncrypted());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class MailClient
|
|||
/*
|
||||
$gSignatureParts = $oBodyStructure->SearchByContentType('multipart/signed');
|
||||
foreach ($gSignatureParts as $oPart) {
|
||||
if ($oPart->IsPgpSigned()) {
|
||||
if ($oPart->isPgpSigned()) {
|
||||
// An empty section specification refers to the entire message, including the header.
|
||||
// But Dovecot does not return it with BODY.PEEK[1], so we also use BODY.PEEK[1.MIME].
|
||||
$aFetchItems[] = FetchType::BODY_PEEK.'['.$oPart->SubParts()[0]->PartID().'.MIME]';
|
||||
|
|
|
|||
|
|
@ -65,9 +65,13 @@ class Message implements \JsonSerializable
|
|||
$aThreadUnseenUIDs = [];
|
||||
|
||||
private ?array $DraftInfo = null;
|
||||
|
||||
private ?array $pgpSigned = null;
|
||||
private ?array $pgpEncrypted = null;
|
||||
|
||||
private ?array $smimeSigned = null;
|
||||
private ?array $smimeEncrypted = null;
|
||||
|
||||
private ?\MailSo\Mime\EmailCollection
|
||||
$oFrom = null,
|
||||
$oSender = null,
|
||||
|
|
@ -309,26 +313,44 @@ class Message implements \JsonSerializable
|
|||
if ($oBodyStructure) {
|
||||
$gEncryptedParts = $oBodyStructure->SearchByContentType('multipart/encrypted');
|
||||
foreach ($gEncryptedParts as $oPart) {
|
||||
if ($oPart->IsPgpEncrypted()) {
|
||||
if ($oPart->isPgpEncrypted()) {
|
||||
$oMessage->pgpEncrypted = [
|
||||
'partId' => $oPart->SubParts()[1]->PartID()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$gEncryptedParts = $oBodyStructure->SearchByContentType('application/pkcs7-mime');
|
||||
foreach ($gEncryptedParts as $oPart) {
|
||||
if ($oPart->isSMimeEncrypted()) {
|
||||
$oMessage->smimeEncrypted = [
|
||||
'partId' => $oPart->PartID()
|
||||
];
|
||||
} else if ($oPart->isSMimeSigned()) {
|
||||
$oMessage->smimeSigned = [
|
||||
'sigPartId' => $oPart->PartID(),
|
||||
'micAlg' => $oHeaders ? (string) $oHeaders->ParameterValue(MimeHeader::CONTENT_TYPE, 'micalg') : ''
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$gSignatureParts = $oBodyStructure->SearchByContentType('multipart/signed');
|
||||
foreach ($gSignatureParts as $oPart) {
|
||||
if (!$oPart->IsPgpSigned()) {
|
||||
continue;
|
||||
if ($oPart->isPgpSigned()) {
|
||||
$oMessage->pgpSigned = [
|
||||
// /?/Raw/&q[]=/0/Download/&q[]=/...
|
||||
// /?/Raw/&q[]=/0/View/&q[]=/...
|
||||
'bodyPartId' => $oPart->SubParts()[0]->PartID(),
|
||||
'sigPartId' => $oPart->SubParts()[1]->PartID(),
|
||||
'micAlg' => $oHeaders ? (string) $oHeaders->ParameterValue(MimeHeader::CONTENT_TYPE, 'micalg') : ''
|
||||
];
|
||||
} else if ($oPart->isSMimeSigned()) {
|
||||
$oMessage->smimeSigned = [
|
||||
'bodyPartId' => $oPart->SubParts()[0]->PartID(),
|
||||
'sigPartId' => $oPart->SubParts()[1]->PartID(),
|
||||
'micAlg' => $oHeaders ? (string) $oHeaders->ParameterValue(MimeHeader::CONTENT_TYPE, 'micalg') : ''
|
||||
];
|
||||
}
|
||||
$oPgpSignaturePart = $oPart->SubParts()[1];
|
||||
$oMessage->pgpSigned = [
|
||||
// /?/Raw/&q[]=/0/Download/&q[]=/...
|
||||
// /?/Raw/&q[]=/0/View/&q[]=/...
|
||||
'bodyPartId' => $oPart->SubParts()[0]->PartID(),
|
||||
'sigPartId' => $oPgpSignaturePart->PartID(),
|
||||
'micAlg' => $oHeaders ? (string) $oHeaders->ParameterValue(MimeHeader::CONTENT_TYPE, 'micalg') : ''
|
||||
];
|
||||
/*
|
||||
// An empty section specification refers to the entire message, including the header.
|
||||
// But Dovecot does not return it with BODY.PEEK[1], so we also use BODY.PEEK[1.MIME].
|
||||
|
|
|
|||
|
|
@ -80,20 +80,29 @@ class Part
|
|||
return $sResult;
|
||||
}
|
||||
|
||||
public function IsPgpSigned() : bool
|
||||
// https://datatracker.ietf.org/doc/html/rfc3156#section-5
|
||||
public function isPgpSigned() : bool
|
||||
{
|
||||
// https://datatracker.ietf.org/doc/html/rfc3156#section-5
|
||||
$header = $this->Headers->GetByName(Enumerations\Header::CONTENT_TYPE);
|
||||
return $header
|
||||
&& \preg_match('#multipart/signed.+protocol=["\']?application/pgp-signature#si', $header->FullValue())
|
||||
// The multipart/signed body MUST consist of exactly two parts.
|
||||
&& 2 === \count($this->SubParts)
|
||||
&& $this->SubParts[1]->IsPgpSignature();
|
||||
&& 'application/pgp-signature' === $this->SubParts[1]->ContentType();
|
||||
}
|
||||
|
||||
public function IsPgpSignature() : bool
|
||||
// https://www.rfc-editor.org/rfc/rfc8551.html#section-3.5
|
||||
public function isSMimeSigned() : bool
|
||||
{
|
||||
return \in_array($this->ContentType(), array('application/pgp-signature', 'application/pkcs7-signature'));
|
||||
$header = $this->Headers->GetByName(Enumerations\Header::CONTENT_TYPE);
|
||||
return ($header
|
||||
&& \preg_match('#multipart/signed.+protocol=["\']?application/pkcs7-signature#si', $header->FullValue())
|
||||
// The multipart/signed body MUST consist of exactly two parts.
|
||||
&& 2 === \count($this->SubParts)
|
||||
&& 'application/pkcs7-signature' === $this->SubParts[1]->ContentType()
|
||||
) || ($header
|
||||
&& \preg_match('#application/pkcs7-mime.+smime-type=["\']?signed-data#si', $header->FullValue())
|
||||
);
|
||||
}
|
||||
|
||||
public static function FromFile(string $sFileName) : ?self
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ trait Pgp
|
|||
);
|
||||
}
|
||||
|
||||
if ($oPart && $oPart->IsPgpSigned()) {
|
||||
if ($oPart && $oPart->isPgpSigned()) {
|
||||
// $GPG->verifyStream($oPart->SubParts[0]->Body, \stream_get_contents($oPart->SubParts[1]->Body));
|
||||
// $result['signatures'] = $oPart->SubParts[0];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue