001/** 002 * 003 * Copyright 2017 Florian Schmaus. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.ox; 018 019import java.io.IOException; 020import java.nio.charset.Charset; 021 022import org.jivesoftware.smack.util.Objects; 023import org.jivesoftware.smackx.ox.element.CryptElement; 024import org.jivesoftware.smackx.ox.element.OpenPgpContentElement; 025import org.jivesoftware.smackx.ox.element.OpenPgpElement; 026import org.jivesoftware.smackx.ox.element.SignElement; 027import org.jivesoftware.smackx.ox.element.SigncryptElement; 028import org.jivesoftware.smackx.ox.provider.OpenPgpContentElementProvider; 029 030import org.pgpainless.decryption_verification.OpenPgpMetadata; 031import org.xmlpull.v1.XmlPullParserException; 032 033/** 034 * This class embodies a decrypted {@link OpenPgpElement}. 035 */ 036public class OpenPgpMessage { 037 038 public enum State { 039 /** 040 * Represents a {@link SigncryptElement}. 041 */ 042 signcrypt, 043 /** 044 * Represents a {@link SignElement}. 045 */ 046 sign, 047 /** 048 * Represents a {@link CryptElement}. 049 */ 050 crypt, 051 ; 052 } 053 054 private final String element; 055 private final State state; 056 private final OpenPgpMetadata metadata; 057 058 private OpenPgpContentElement openPgpContentElement; 059 060 /** 061 * Constructor. 062 * 063 * @param content XML representation of the decrypted {@link OpenPgpContentElement}. 064 * @param state {@link State} of the {@link OpenPgpContentElement}. 065 * @param metadata Metadata about the encryption. 066 */ 067 public OpenPgpMessage(String content, State state, OpenPgpMetadata metadata) { 068 this.metadata = Objects.requireNonNull(metadata); 069 this.state = Objects.requireNonNull(state); 070 this.element = Objects.requireNonNull(content); 071 } 072 073 /** 074 * Constructor. 075 * 076 * @param bytes bytes of the XML representation of the decrypted {@link OpenPgpContentElement}. 077 * @param state {@link State} of the {@link OpenPgpContentElement}. 078 * @param metadata metadata about the encryption. 079 */ 080 public OpenPgpMessage(byte[] bytes, State state, OpenPgpMetadata metadata) { 081 this(new String(Objects.requireNonNull(bytes), Charset.forName("UTF-8")), state, metadata); 082 } 083 084 /** 085 * Return the decrypted {@link OpenPgpContentElement} of this message. 086 * To determine, whether the element is a {@link SignElement}, {@link CryptElement} or {@link SigncryptElement}, 087 * please consult {@link #getState()}. 088 * 089 * @return {@link OpenPgpContentElement} 090 * @throws XmlPullParserException if the parser encounters an error. 091 * @throws IOException if the parser encounters an error. 092 */ 093 public OpenPgpContentElement getOpenPgpContentElement() throws XmlPullParserException, IOException { 094 ensureOpenPgpContentElementSet(); 095 096 return openPgpContentElement; 097 } 098 099 private void ensureOpenPgpContentElementSet() throws XmlPullParserException, IOException { 100 if (openPgpContentElement != null) 101 return; 102 103 openPgpContentElement = OpenPgpContentElementProvider.parseOpenPgpContentElement(element); 104 if (openPgpContentElement == null) { 105 return; 106 } 107 108 // Determine the state of the content element. 109 if (openPgpContentElement instanceof SigncryptElement) { 110 if (state != State.signcrypt) { 111 throw new IllegalStateException("OpenPgpContentElement was signed and encrypted, but is not a SigncryptElement."); 112 } 113 } else if (openPgpContentElement instanceof SignElement) { 114 if (state != State.sign) { 115 throw new IllegalStateException("OpenPgpContentElement was signed and unencrypted, but is not a SignElement."); 116 } 117 } else if (openPgpContentElement instanceof CryptElement) { 118 if (state != State.crypt) { 119 throw new IllegalStateException("OpenPgpContentElement was unsigned and encrypted, but is not a CryptElement."); 120 } 121 } 122 } 123 124 /** 125 * Return the state of the message. This value determines, whether the message was a {@link SignElement}, 126 * {@link CryptElement} or {@link SigncryptElement}. 127 * 128 * @return state of the content element. 129 * @throws IOException if the parser encounters an error. 130 * @throws XmlPullParserException if the parser encounters and error. 131 */ 132 public State getState() throws IOException, XmlPullParserException { 133 ensureOpenPgpContentElementSet(); 134 return state; 135 } 136 137 /** 138 * Return metadata about the encrypted message. 139 * 140 * @return metadata 141 */ 142 public OpenPgpMetadata getMetadata() { 143 return metadata; 144 } 145}