001/**
002 *
003 * Copyright © 2017 Paul Schaub, 2021 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.hashes.element;
018
019import static org.jivesoftware.smack.util.Objects.requireNonNull;
020
021import javax.xml.namespace.QName;
022
023import org.jivesoftware.smack.packet.ExtensionElement;
024import org.jivesoftware.smack.util.XmlStringBuilder;
025import org.jivesoftware.smack.util.stringencoder.Base64;
026
027import org.jivesoftware.smackx.hashes.HashManager;
028
029/**
030 * Represent a hash element.
031 *
032 * @author Paul Schaub
033 */
034public class HashElement implements ExtensionElement {
035
036    public static final String ELEMENT = "hash";
037    public static final String ATTR_ALGO = "algo";
038
039    public static final QName QNAME = new QName(HashManager.NAMESPACE.V2.toString(), ELEMENT);
040
041    private final HashManager.ALGORITHM algorithm;
042    private final byte[] hash;
043    private final String hashB64;
044
045    /**
046     * Create a HashElement from pre-calculated values.
047     * @param algorithm The algorithm which was used.
048     * @param hash the checksum as byte array.
049     */
050    public HashElement(HashManager.ALGORITHM algorithm, byte[] hash) {
051        this.algorithm = requireNonNull(algorithm);
052        this.hash = requireNonNull(hash);
053        hashB64 = Base64.encodeToString(hash);
054    }
055
056    /**
057     * Create a HashElement from pre-calculated values.
058     * @param algorithm the algorithm that was used.
059     * @param hashB64 the checksum in base 64.
060     */
061    public HashElement(HashManager.ALGORITHM algorithm, String hashB64) {
062        this.algorithm = algorithm;
063        this.hash = Base64.decode(hashB64);
064        this.hashB64 = hashB64;
065    }
066
067    /**
068     * Return the hash algorithm used in this HashElement.
069     *
070     * @return algorithm the algorithm.
071     */
072    public HashManager.ALGORITHM getAlgorithm() {
073        return algorithm;
074    }
075
076    /**
077     * Return the checksum as a byte array.
078     *
079     * @return the hash.
080     */
081    public byte[] getHash() {
082        return hash;
083    }
084
085    /**
086     * Return the checksum as a base16 (hex) string.
087     *
088     * @return the hash.
089     */
090    public String getHashB64() {
091        return hashB64;
092    }
093
094    @Override
095    public String getElementName() {
096        return QNAME.getLocalPart();
097    }
098
099    @Override
100    public String getNamespace() {
101        return QNAME.getNamespaceURI();
102    }
103
104    @Override
105    public CharSequence toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
106        XmlStringBuilder sb = new XmlStringBuilder(this);
107        sb.attribute(ATTR_ALGO, algorithm.toString());
108        sb.rightAngleBracket();
109        sb.append(hashB64);
110        sb.closeElement(this);
111        return sb;
112    }
113
114    @Override
115    public boolean equals(Object other) {
116        if (other == null || !(other instanceof HashElement)) {
117            return false;
118        }
119
120        HashElement otherHashElement = (HashElement) other;
121        return this.getAlgorithm() == otherHashElement.getAlgorithm() &&
122            this.getHashB64().equals(otherHashElement.getHashB64());
123    }
124
125    @Override
126    public int hashCode() {
127        return toXML().toString().hashCode();
128    }
129}