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.store.filebased;
018
019import java.io.BufferedReader;
020import java.io.BufferedWriter;
021import java.io.File;
022import java.io.FileNotFoundException;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.InputStreamReader;
026import java.io.OutputStream;
027import java.io.OutputStreamWriter;
028import java.util.logging.Level;
029import java.util.logging.Logger;
030
031import org.jivesoftware.smack.util.CloseableUtil;
032import org.jivesoftware.smack.util.FileUtils;
033import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpTrustStore;
034import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
035import org.jivesoftware.smackx.ox.util.Util;
036
037import org.jxmpp.jid.BareJid;
038import org.pgpainless.key.OpenPgpV4Fingerprint;
039
040/**
041 * Implementation of the {@link OpenPgpTrustStore} which stores information in a directory structure.
042 *
043 * <pre>
044 * {@code
045 * <basePath>/
046 *     <userjid@server.tld>/
047 *         <fingerprint>.trust      // Trust record for a key
048 * }
049 * </pre>
050 */
051public class FileBasedOpenPgpTrustStore extends AbstractOpenPgpTrustStore {
052
053    private static final Logger LOGGER = Logger.getLogger(FileBasedOpenPgpTrustStore.class.getName());
054
055    private final File basePath;
056
057    public static String TRUST_RECORD(OpenPgpV4Fingerprint fingerprint) {
058        return fingerprint.toString() + ".trust";
059    }
060
061    public FileBasedOpenPgpTrustStore(File basePath) {
062        this.basePath = basePath;
063    }
064
065    @Override
066    protected Trust readTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException {
067        File file = getTrustPath(owner, fingerprint);
068        BufferedReader reader = null;
069        try {
070            InputStream inputStream = FileUtils.prepareFileInputStream(file);
071            InputStreamReader isr = new InputStreamReader(inputStream, Util.UTF8);
072            reader = new BufferedReader(isr);
073
074            Trust trust = null;
075            String line; int lineNr = 0;
076            while ((line = reader.readLine()) != null) {
077                lineNr++;
078                try {
079                    trust = Trust.valueOf(line);
080                    break;
081                } catch (IllegalArgumentException e) {
082                    LOGGER.log(Level.WARNING, "Skipping invalid trust record in line " + lineNr + " \"" + line
083                            + "\" of file " + file.getAbsolutePath());
084                }
085            }
086            return trust != null ? trust : Trust.undecided;
087        } catch (IOException e) {
088            if (e instanceof FileNotFoundException) {
089                return Trust.undecided;
090            }
091            throw e;
092        } finally {
093            CloseableUtil.maybeClose(reader, LOGGER);
094        }
095    }
096
097    @Override
098    protected void writeTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) throws IOException {
099        File file = getTrustPath(owner, fingerprint);
100
101        if (trust == null || trust == Trust.undecided) {
102            FileUtils.maybeDeleteFileOrThrow(file);
103        }
104
105        FileUtils.maybeCreateFileWithParentDirectories(file);
106
107        BufferedWriter writer = null;
108        try {
109            OutputStream outputStream = FileUtils.prepareFileOutputStream(file);
110            OutputStreamWriter osw = new OutputStreamWriter(outputStream, Util.UTF8);
111            writer = new BufferedWriter(osw);
112
113            writer.write(trust.toString());
114        } finally {
115            CloseableUtil.maybeClose(writer, LOGGER);
116        }
117    }
118
119    private File getTrustPath(BareJid owner, OpenPgpV4Fingerprint fingerprint) {
120        return new File(FileBasedOpenPgpStore.getContactsPath(basePath, owner), TRUST_RECORD(fingerprint));
121    }
122}