Smack/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpMessage.java

157 lines
5.9 KiB
Java

/**
*
* Copyright 2017 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.ox;
import java.io.IOException;
import java.nio.charset.Charset;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smackx.ox.element.CryptElement;
import org.jivesoftware.smackx.ox.element.OpenPgpContentElement;
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
import org.jivesoftware.smackx.ox.element.SignElement;
import org.jivesoftware.smackx.ox.element.SigncryptElement;
import org.jivesoftware.smackx.ox.provider.OpenPgpContentElementProvider;
import org.pgpainless.decryption_verification.OpenPgpMetadata;
/**
* This class embodies a decrypted and/or verified {@link OpenPgpElement}.
* <br>
* The content can be one of the following three {@link OpenPgpContentElement}s:
* <br><br>
* {@link SignElement}: The content is expected to be signed with the senders key, but unencrypted.<br>
* {@link CryptElement}: The content is expected to be encrypted, but not signed.<br>
* {@link SigncryptElement}: The content is expected to be signed with the senders key and encrypted.<br>
* <br>
* To determine, of which nature the content of the message is, use {@link #getState()}. You should utilize this
* information to cast the return value of {@link #getOpenPgpContentElement()} correctly.
* <br>
* Use {@link #getMetadata()} in order to get information about the messages encryption status, its signatures etc.
*/
public class OpenPgpMessage {
public enum State {
/**
* Represents a {@link SigncryptElement}.
*/
signcrypt,
/**
* Represents a {@link SignElement}.
*/
sign,
/**
* Represents a {@link CryptElement}.
*/
crypt,
}
private final String element;
private final State state;
private final OpenPgpMetadata metadata;
private OpenPgpContentElement openPgpContentElement;
/**
* Constructor.
*
* @param content XML representation of the decrypted {@link OpenPgpContentElement}.
* @param state {@link State} of the {@link OpenPgpContentElement}.
* @param metadata Metadata about the encryption.
*/
public OpenPgpMessage(String content, State state, OpenPgpMetadata metadata) {
this.metadata = Objects.requireNonNull(metadata);
this.state = Objects.requireNonNull(state);
this.element = Objects.requireNonNull(content);
}
/**
* Constructor.
*
* @param bytes bytes of the XML representation of the decrypted {@link OpenPgpContentElement}.
* @param state {@link State} of the {@link OpenPgpContentElement}.
* @param metadata metadata about the encryption.
*/
public OpenPgpMessage(byte[] bytes, State state, OpenPgpMetadata metadata) {
this(new String(Objects.requireNonNull(bytes), Charset.forName("UTF-8")), state, metadata);
}
/**
* Return the decrypted {@link OpenPgpContentElement} of this message.
* To determine, whether the element is a {@link SignElement}, {@link CryptElement} or {@link SigncryptElement},
* please consult {@link #getState()}.
*
* @return {@link OpenPgpContentElement}
* @throws XmlPullParserException if the parser encounters an error.
* @throws IOException if the parser encounters an error.
*/
public OpenPgpContentElement getOpenPgpContentElement() throws XmlPullParserException, IOException {
ensureOpenPgpContentElementSet();
return openPgpContentElement;
}
private void ensureOpenPgpContentElementSet() throws XmlPullParserException, IOException {
if (openPgpContentElement != null)
return;
openPgpContentElement = OpenPgpContentElementProvider.parseOpenPgpContentElement(element);
if (openPgpContentElement == null) {
return;
}
// Determine the state of the content element.
if (openPgpContentElement instanceof SigncryptElement) {
if (state != State.signcrypt) {
throw new IllegalStateException("OpenPgpContentElement was signed and encrypted, but is not a SigncryptElement.");
}
} else if (openPgpContentElement instanceof SignElement) {
if (state != State.sign) {
throw new IllegalStateException("OpenPgpContentElement was signed and unencrypted, but is not a SignElement.");
}
} else if (openPgpContentElement instanceof CryptElement) {
if (state != State.crypt) {
throw new IllegalStateException("OpenPgpContentElement was unsigned and encrypted, but is not a CryptElement.");
}
}
}
/**
* Return the state of the message. This value determines, whether the message was a {@link SignElement},
* {@link CryptElement} or {@link SigncryptElement}.
*
* @return state of the content element.
* @throws IOException if the parser encounters an error.
* @throws XmlPullParserException if the parser encounters and error.
*/
public State getState() throws IOException, XmlPullParserException {
ensureOpenPgpContentElementSet();
return state;
}
/**
* Return metadata about the encrypted message.
*
* @return metadata
*/
public OpenPgpMetadata getMetadata() {
return metadata;
}
}