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