mirror of https://github.com/JakubMelka/PDF4QT.git
Security information
This commit is contained in:
parent
c228cf6d24
commit
f2f398e82b
|
@ -64,6 +64,18 @@ const PDFDictionary* PDFDocument::getTrailerDictionary() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
QByteArray PDFDocument::getVersion() const
|
||||
{
|
||||
QByteArray result = m_catalog.getVersion();
|
||||
|
||||
if (result.isEmpty() && m_info.version.isValid())
|
||||
{
|
||||
result = QString("%1.%2").arg(m_info.version.major).arg(m_info.version.minor).toLatin1();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PDFDocument::init()
|
||||
{
|
||||
initInfo();
|
||||
|
@ -164,6 +176,32 @@ void PDFDocument::initInfo()
|
|||
throw PDFException(tr("Bad format of document info entry in trailer dictionary. Trapping information expected"));
|
||||
}
|
||||
}
|
||||
|
||||
// Scan for extra items
|
||||
constexpr const char* PREDEFINED_ITEMS[] = { PDF_DOCUMENT_INFO_ENTRY_TITLE, PDF_DOCUMENT_INFO_ENTRY_AUTHOR, PDF_DOCUMENT_INFO_ENTRY_SUBJECT,
|
||||
PDF_DOCUMENT_INFO_ENTRY_KEYWORDS, PDF_DOCUMENT_INFO_ENTRY_CREATOR, PDF_DOCUMENT_INFO_ENTRY_PRODUCER,
|
||||
PDF_DOCUMENT_INFO_ENTRY_CREATION_DATE, PDF_DOCUMENT_INFO_ENTRY_MODIFIED_DATE, PDF_DOCUMENT_INFO_ENTRY_TRAPPED };
|
||||
for (size_t i = 0; i < infoDictionary->getCount(); ++i)
|
||||
{
|
||||
const QByteArray& key = infoDictionary->getKey(i);
|
||||
if (std::none_of(std::begin(PREDEFINED_ITEMS), std::end(PREDEFINED_ITEMS), [&key](const char* item) { return item == key; }))
|
||||
{
|
||||
const PDFObject& value = getObject(infoDictionary->getValue(i));
|
||||
if (value.isString())
|
||||
{
|
||||
const QByteArray& stringValue = value.getString();
|
||||
QDateTime dateTime = PDFEncoding::convertToDateTime(stringValue);
|
||||
if (dateTime.isValid())
|
||||
{
|
||||
m_info.extra[key] = dateTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_info.extra[key] = PDFEncoding::convertTextString(stringValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!info.isNull()) // Info may be invalid...
|
||||
{
|
||||
|
|
|
@ -305,7 +305,9 @@ public:
|
|||
|
||||
const PDFObjectStorage& getStorage() const { return m_pdfObjectStorage; }
|
||||
|
||||
/// Info about the document. Title, Author, Keywords...
|
||||
/// Info about the document. Title, Author, Keywords... It also stores "extra"
|
||||
/// values, which are in info dictionary. They can be either strings, or date
|
||||
/// time (QString or QDateTime).
|
||||
struct Info
|
||||
{
|
||||
/// Indicates, that document was modified that it includes trapping information.
|
||||
|
@ -326,6 +328,8 @@ public:
|
|||
QDateTime creationDate;
|
||||
QDateTime modifiedDate;
|
||||
Trapped trapped = Trapped::Unknown;
|
||||
PDFVersion version;
|
||||
std::map<QByteArray, QVariant> extra;
|
||||
};
|
||||
|
||||
/// Returns info about the document (title, author, etc.)
|
||||
|
@ -356,13 +360,20 @@ public:
|
|||
/// Returns the trailer dictionary
|
||||
const PDFDictionary* getTrailerDictionary() const;
|
||||
|
||||
/// Returns version of the PDF document. Version can be taken from catalog,
|
||||
/// or from PDF file header. Version from catalog has precedence over version from
|
||||
/// header.
|
||||
QByteArray getVersion() const;
|
||||
|
||||
private:
|
||||
friend class PDFDocumentReader;
|
||||
|
||||
explicit PDFDocument(PDFObjectStorage&& storage) :
|
||||
explicit PDFDocument(PDFObjectStorage&& storage, PDFVersion version) :
|
||||
m_pdfObjectStorage(std::move(storage))
|
||||
{
|
||||
init();
|
||||
|
||||
m_info.version = version;
|
||||
}
|
||||
|
||||
/// Initialize data based on object in the storage.
|
||||
|
|
|
@ -481,7 +481,7 @@ PDFDocument PDFDocumentReader::readFromBuffer(const QByteArray& buffer)
|
|||
std::for_each(std::execution::parallel_policy(), objectStreams.cbegin(), objectStreams.cend(), processObjectStream);
|
||||
|
||||
PDFObjectStorage storage(std::move(objects), PDFObject(xrefTable.getTrailerDictionary()), std::move(securityHandler));
|
||||
return PDFDocument(std::move(storage));
|
||||
return PDFDocument(std::move(storage), m_version);
|
||||
}
|
||||
catch (PDFException parserException)
|
||||
{
|
||||
|
|
|
@ -92,6 +92,7 @@ public:
|
|||
|
||||
enum class AuthorizationResult
|
||||
{
|
||||
NoAuthorizationRequired,
|
||||
UserAuthorized,
|
||||
OwnerAuthorized,
|
||||
Failed,
|
||||
|
@ -146,6 +147,12 @@ public:
|
|||
/// Returns true, if metadata are encrypted
|
||||
virtual bool isMetadataEncrypted() const = 0;
|
||||
|
||||
/// Returns result of authorization process
|
||||
virtual AuthorizationResult getAuthorizationResult() const = 0;
|
||||
|
||||
/// Returns version of the encryption
|
||||
int getVersion() const { return m_V; }
|
||||
|
||||
/// Creates a security handler from the object. If object is null, then
|
||||
/// "None" security handler is created. If error occurs, then exception is thrown.
|
||||
/// \param encryptionDictionaryObject Encryption dictionary object
|
||||
|
@ -185,7 +192,8 @@ public:
|
|||
virtual QByteArray decrypt(const QByteArray& data, PDFObjectReference, EncryptionScope) const override { return data; }
|
||||
virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray&, PDFObjectReference) const override { return data; }
|
||||
virtual bool isMetadataEncrypted() const override { return true; }
|
||||
virtual bool isAllowed(Permission) const { return true; }
|
||||
virtual bool isAllowed(Permission) const override { return true; }
|
||||
virtual AuthorizationResult getAuthorizationResult() const override { return AuthorizationResult::NoAuthorizationRequired; }
|
||||
};
|
||||
|
||||
/// Specifies the security using standard security handler (see PDF specification
|
||||
|
@ -199,6 +207,7 @@ public:
|
|||
virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const override;
|
||||
virtual bool isMetadataEncrypted() const override { return m_encryptMetadata; }
|
||||
virtual bool isAllowed(Permission permission) const { return m_authorizationData.authorizationResult == AuthorizationResult::OwnerAuthorized || (m_permissions & static_cast<uint32_t>(permission)); }
|
||||
virtual AuthorizationResult getAuthorizationResult() const override { return m_authorizationData.authorizationResult; }
|
||||
|
||||
struct AuthorizationData
|
||||
{
|
||||
|
|
|
@ -37,6 +37,7 @@ PDFDocumentPropertiesDialog::PDFDocumentPropertiesDialog(const pdf::PDFDocument*
|
|||
|
||||
initializeProperties(document);
|
||||
initializeFileInfoProperties(fileInfo);
|
||||
initializeSecurity(document);
|
||||
|
||||
const int defaultWidth = PDFWidgetUtils::getPixelSize(this, 240.0);
|
||||
const int defaultHeight = PDFWidgetUtils::getPixelSize(this, 200.0);
|
||||
|
@ -57,6 +58,7 @@ void PDFDocumentPropertiesDialog::initializeProperties(const pdf::PDFDocument* d
|
|||
|
||||
const pdf::PDFDocument::Info* info = document->getInfo();
|
||||
const pdf::PDFCatalog* catalog = document->getCatalog();
|
||||
new QTreeWidgetItem(propertiesRoot, { tr("PDF version"), QString::fromLatin1(document->getVersion()) });
|
||||
new QTreeWidgetItem(propertiesRoot, { tr("Title"), info->title });
|
||||
new QTreeWidgetItem(propertiesRoot, { tr("Subject"), info->subject });
|
||||
new QTreeWidgetItem(propertiesRoot, { tr("Author"), info->author });
|
||||
|
@ -65,7 +67,6 @@ void PDFDocumentPropertiesDialog::initializeProperties(const pdf::PDFDocument* d
|
|||
new QTreeWidgetItem(propertiesRoot, { tr("Producer"), info->producer });
|
||||
new QTreeWidgetItem(propertiesRoot, { tr("Creation date"), locale.toString(info->creationDate) });
|
||||
new QTreeWidgetItem(propertiesRoot, { tr("Modified date"), locale.toString(info->modifiedDate) });
|
||||
new QTreeWidgetItem(propertiesRoot, { tr("Version"), QString::fromLatin1(catalog->getVersion()) });
|
||||
|
||||
QString trapped;
|
||||
switch (info->trapped)
|
||||
|
@ -105,6 +106,20 @@ void PDFDocumentPropertiesDialog::initializeProperties(const pdf::PDFDocument* d
|
|||
|
||||
ui->propertiesTreeWidget->addTopLevelItem(propertiesRoot);
|
||||
ui->propertiesTreeWidget->addTopLevelItem(contentRoot);
|
||||
|
||||
if (!info->extra.empty())
|
||||
{
|
||||
QTreeWidgetItem* customRoot = new QTreeWidgetItem({ tr("Custom properties") });
|
||||
for (const auto& item : info->extra)
|
||||
{
|
||||
QString key = QString::fromLatin1(item.first);
|
||||
QVariant valueVariant = item.second;
|
||||
QString value = (valueVariant.type() == QVariant::DateTime) ? locale.toString(valueVariant.toDateTime()) : valueVariant.toString();
|
||||
new QTreeWidgetItem(customRoot, { key, value });
|
||||
}
|
||||
ui->propertiesTreeWidget->addTopLevelItem(customRoot);
|
||||
}
|
||||
|
||||
ui->propertiesTreeWidget->expandAll();
|
||||
ui->propertiesTreeWidget->resizeColumnToContents(0);
|
||||
}
|
||||
|
@ -140,4 +155,77 @@ void PDFDocumentPropertiesDialog::initializeFileInfoProperties(const PDFFileInfo
|
|||
ui->fileInfoTreeWidget->resizeColumnToContents(0);
|
||||
}
|
||||
|
||||
void PDFDocumentPropertiesDialog::initializeSecurity(const pdf::PDFDocument* document)
|
||||
{
|
||||
QLocale locale;
|
||||
|
||||
QTreeWidgetItem* securityRoot = new QTreeWidgetItem({ tr("Security") });
|
||||
const pdf::PDFSecurityHandler* securityHandler = document->getStorage().getSecurityHandler();
|
||||
const pdf::EncryptionMode mode = securityHandler->getMode();
|
||||
QString modeString;
|
||||
switch (mode)
|
||||
{
|
||||
case pdf::EncryptionMode::None:
|
||||
modeString = tr("None");
|
||||
break;
|
||||
|
||||
case pdf::EncryptionMode::Standard:
|
||||
modeString = tr("Standard");
|
||||
break;
|
||||
|
||||
case pdf::EncryptionMode::Custom:
|
||||
modeString = tr("Custom");
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
QString authorizationMode;
|
||||
switch (securityHandler->getAuthorizationResult())
|
||||
{
|
||||
case pdf::PDFSecurityHandler::AuthorizationResult::NoAuthorizationRequired:
|
||||
authorizationMode = tr("No authorization required");
|
||||
break;
|
||||
|
||||
case pdf::PDFSecurityHandler::AuthorizationResult::OwnerAuthorized:
|
||||
authorizationMode = tr("Authorized as owner");
|
||||
break;
|
||||
|
||||
case pdf::PDFSecurityHandler::AuthorizationResult::UserAuthorized:
|
||||
authorizationMode = tr("Authorized as user");
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
new QTreeWidgetItem(securityRoot, { tr("Document encryption"), modeString });
|
||||
new QTreeWidgetItem(securityRoot, { tr("Authorized as"), authorizationMode });
|
||||
new QTreeWidgetItem(securityRoot, { tr("Metadata encrypted"), securityHandler->isMetadataEncrypted() ? tr("Yes") : tr("No") });
|
||||
new QTreeWidgetItem(securityRoot, { tr("Version"), locale.toString(securityHandler->getVersion()) });
|
||||
|
||||
QTreeWidgetItem* permissionsRoot = new QTreeWidgetItem({ tr("Permissions") });
|
||||
|
||||
auto addPermissionInfo = [securityHandler, permissionsRoot](QString caption, pdf::PDFSecurityHandler::Permission permission)
|
||||
{
|
||||
new QTreeWidgetItem(permissionsRoot, { caption, securityHandler->isAllowed(permission) ? tr("Yes") : tr("No")});
|
||||
};
|
||||
addPermissionInfo(tr("Print (low resolution)"), pdf::PDFSecurityHandler::Permission::PrintLowResolution);
|
||||
addPermissionInfo(tr("Print (high resolution)"), pdf::PDFSecurityHandler::Permission::PrintHighResolution);
|
||||
addPermissionInfo(tr("Content extraction"), pdf::PDFSecurityHandler::Permission::CopyContent);
|
||||
addPermissionInfo(tr("Content extraction (accessibility)"), pdf::PDFSecurityHandler::Permission::Accessibility);
|
||||
addPermissionInfo(tr("Page assembling"), pdf::PDFSecurityHandler::Permission::Assemble);
|
||||
addPermissionInfo(tr("Modify content"), pdf::PDFSecurityHandler::Permission::Modify);
|
||||
addPermissionInfo(tr("Modify interactive items"), pdf::PDFSecurityHandler::Permission::ModifyInteractiveItems);
|
||||
addPermissionInfo(tr("Fill form fields"), pdf::PDFSecurityHandler::Permission::ModifyFormFields);
|
||||
|
||||
ui->securityTreeWidget->addTopLevelItem(securityRoot);
|
||||
ui->securityTreeWidget->addTopLevelItem(permissionsRoot);
|
||||
ui->securityTreeWidget->expandAll();
|
||||
ui->securityTreeWidget->resizeColumnToContents(0);
|
||||
}
|
||||
|
||||
} // namespace pdfviewer
|
||||
|
|
|
@ -61,6 +61,7 @@ private:
|
|||
|
||||
void initializeProperties(const pdf::PDFDocument* document);
|
||||
void initializeFileInfoProperties(const PDFFileInfo* fileInfo);
|
||||
void initializeSecurity(const pdf::PDFDocument* document);
|
||||
};
|
||||
|
||||
} // namespace pdfviewer
|
||||
|
|
|
@ -88,6 +88,37 @@
|
|||
<attribute name="title">
|
||||
<string>Security</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="securityGroupBox">
|
||||
<property name="title">
|
||||
<string>Security</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="securityTreeWidget">
|
||||
<property name="columnCount">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">2</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
Loading…
Reference in New Issue