001/** 002 * 003 * Copyright 2018 Paul Schaub. 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.element; 018 019import java.util.Collections; 020import java.util.Date; 021import java.util.Map; 022import java.util.TreeMap; 023 024import org.jivesoftware.smack.packet.ExtensionElement; 025import org.jivesoftware.smack.util.Objects; 026import org.jivesoftware.smack.util.XmlStringBuilder; 027 028import org.pgpainless.key.OpenPgpV4Fingerprint; 029 030/** 031 * Class that represents a public key list which was announced to a users metadata node. 032 * 033 * @see <a href="https://xmpp.org/extensions/xep-0373.html#announcing-pubkey-list"> 034 * XEP-0373: ยง4.2 The OpenPGP Public Key Metadata Node</a> 035 */ 036public final class PublicKeysListElement implements ExtensionElement { 037 038 public static final String NAMESPACE = OpenPgpElement.NAMESPACE; 039 public static final String ELEMENT = "public-keys-list"; 040 041 private final Map<OpenPgpV4Fingerprint, PubkeyMetadataElement> metadata; 042 043 private PublicKeysListElement(TreeMap<OpenPgpV4Fingerprint, PubkeyMetadataElement> metadata) { 044 this.metadata = Collections.unmodifiableMap(Objects.requireNonNull(metadata)); 045 } 046 047 public static Builder builder() { 048 return new Builder(); 049 } 050 051 public TreeMap<OpenPgpV4Fingerprint, PubkeyMetadataElement> getMetadata() { 052 return new TreeMap<>(metadata); 053 } 054 055 @Override 056 public String getNamespace() { 057 return NAMESPACE; 058 } 059 060 @Override 061 public String getElementName() { 062 return ELEMENT; 063 } 064 065 @Override 066 public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) { 067 XmlStringBuilder xml = new XmlStringBuilder(this).rightAngleBracket(); 068 xml.append(metadata.values()); 069 xml.closeElement(this); 070 return xml; 071 } 072 073 public static final class Builder { 074 075 private final TreeMap<OpenPgpV4Fingerprint, PubkeyMetadataElement> metadata = new TreeMap<>(); 076 077 private Builder() { 078 // Empty 079 } 080 081 public Builder addMetadata(PubkeyMetadataElement key) { 082 Objects.requireNonNull(key); 083 metadata.put(key.getV4Fingerprint(), key); 084 return this; 085 } 086 087 public PublicKeysListElement build() { 088 return new PublicKeysListElement(metadata); 089 } 090 } 091 092 public static class PubkeyMetadataElement implements ExtensionElement { 093 094 public static final String ELEMENT = "pubkey-metadata"; 095 public static final String ATTR_V4_FINGERPRINT = "v4-fingerprint"; 096 public static final String ATTR_DATE = "date"; 097 098 private final OpenPgpV4Fingerprint v4_fingerprint; 099 private final Date date; 100 101 public PubkeyMetadataElement(OpenPgpV4Fingerprint v4_fingerprint, Date date) { 102 this.v4_fingerprint = Objects.requireNonNull(v4_fingerprint); 103 this.date = Objects.requireNonNull(date); 104 105 if (v4_fingerprint.length() != 40) { 106 throw new IllegalArgumentException("OpenPGP v4 fingerprint must be 40 characters long."); 107 } 108 } 109 110 public OpenPgpV4Fingerprint getV4Fingerprint() { 111 return v4_fingerprint; 112 } 113 114 public Date getDate() { 115 return date; 116 } 117 118 @Override 119 public String getElementName() { 120 return ELEMENT; 121 } 122 123 @Override 124 public String getNamespace() { 125 return NAMESPACE; 126 } 127 128 @Override 129 public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) { 130 XmlStringBuilder xml = new XmlStringBuilder(this) 131 .attribute(ATTR_V4_FINGERPRINT, getV4Fingerprint()) 132 .attribute(ATTR_DATE, date).closeEmptyElement(); 133 return xml; 134 } 135 136 @Override 137 public int hashCode() { 138 return getV4Fingerprint().hashCode() + 3 * getDate().hashCode(); 139 } 140 141 @SuppressWarnings("UndefinedEquals") 142 // TODO: Fix the UndefinedEquals due using Date.equals(Date) 143 @Override 144 public boolean equals(Object o) { 145 if (o == null) { 146 return false; 147 } 148 149 if (!(o instanceof PubkeyMetadataElement)) { 150 return false; 151 } 152 153 if (o == this) { 154 return true; 155 } 156 157 PubkeyMetadataElement otherPubkeyMetadataElement = (PubkeyMetadataElement) o; 158 return this.getV4Fingerprint().equals(otherPubkeyMetadataElement.getV4Fingerprint()) && 159 this.getDate().equals(otherPubkeyMetadataElement.getDate()); 160 } 161 } 162}