/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.updates;

import com.android.internal.util.HexDump;
import android.os.FileUtils;
import android.system.Os;
import android.system.ErrnoException;
import android.util.Base64;
import android.util.Slog;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringBufferInputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.NoSuchAlgorithmException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInstallReceiver {

    private static final String TAG = "CTLogInstallReceiver";
    private static final String LOGDIR_PREFIX = "logs-";

    public CertificateTransparencyLogInstallReceiver() {
        super("/data/misc/keychain/trusted_ct_logs/", "ct_logs", "metadata/", "version");
    }

    @Override
    protected void install(byte[] content, int version) throws IOException {
        /* Install is complicated here because we translate the input, which is a JSON file
         * containing log information to a directory with a file per log. To support atomically
         * replacing the old configuration directory with the new there's a bunch of steps. We
         * create a new directory with the logs and then do an atomic update of the current symlink
         * to point to the new directory.
         */

        // 1. Ensure that the update dir exists and is readable
        updateDir.mkdir();
        if (!updateDir.isDirectory()) {
            throw new IOException("Unable to make directory " + updateDir.getCanonicalPath());
        }
        if (!updateDir.setReadable(true, false)) {
            throw new IOException("Unable to set permissions on " +
                    updateDir.getCanonicalPath());
        }
        File currentSymlink = new File(updateDir, "current");
        File newVersion = new File(updateDir, LOGDIR_PREFIX + String.valueOf(version));
        File oldDirectory;
        // 2. Handle the corner case where the new directory already exists.
        if (newVersion.exists()) {
            // If the symlink has already been updated then the update died between steps 7 and 8
            // and so we cannot delete the directory since its in use. Instead just bump the version
            // and return.
            if (newVersion.getCanonicalPath().equals(currentSymlink.getCanonicalPath())) {
                writeUpdate(updateDir, updateVersion, Long.toString(version).getBytes());
                deleteOldLogDirectories();
                return;
            } else {
                FileUtils.deleteContentsAndDir(newVersion);
            }
        }
        try {
            // 3. Create /data/misc/keychain/trusted_ct_logs/<new_version>/ .
            newVersion.mkdir();
            if (!newVersion.isDirectory()) {
                throw new IOException("Unable to make directory " + newVersion.getCanonicalPath());
            }
            if (!newVersion.setReadable(true, false)) {
                throw new IOException("Failed to set " +newVersion.getCanonicalPath() +
                        " readable");
            }

            // 4. For each log in the log file create the corresponding file in <new_version>/ .
            try {
                JSONObject json = new JSONObject(new String(content, StandardCharsets.UTF_8));
                JSONArray logs = json.getJSONArray("logs");
                for (int i = 0; i < logs.length(); i++) {
                    JSONObject log = logs.getJSONObject(i);
                    installLog(newVersion, log);
                }
            } catch (JSONException e) {
                throw new IOException("Failed to parse logs", e);
            }

            // 5. Create the temp symlink. We'll rename this to the target symlink to get an atomic
            // update.
            File tempSymlink = new File(updateDir, "new_symlink");
            try {
                Os.symlink(newVersion.getCanonicalPath(), tempSymlink.getCanonicalPath());
            } catch (ErrnoException e) {
                throw new IOException("Failed to create symlink", e);
            }

            // 6. Update the symlink target, this is the actual update step.
            tempSymlink.renameTo(currentSymlink.getAbsoluteFile());
        } catch (IOException | RuntimeException e) {
            FileUtils.deleteContentsAndDir(newVersion);
            throw e;
        }
        Slog.i(TAG, "CT log directory updated to " + newVersion.getAbsolutePath());
        // 7. Update the current version information
        writeUpdate(updateDir, updateVersion, Long.toString(version).getBytes());
        // 8. Cleanup
        deleteOldLogDirectories();
    }

    private void installLog(File directory, JSONObject logObject) throws IOException {
        try {
            String logFilename = getLogFileName(logObject.getString("key"));
            File file = new File(directory, logFilename);
            try (OutputStreamWriter out =
                    new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
                writeLogEntry(out, "key", logObject.getString("key"));
                writeLogEntry(out, "url", logObject.getString("url"));
                writeLogEntry(out, "description", logObject.getString("description"));
            }
            if (!file.setReadable(true, false)) {
                throw new IOException("Failed to set permissions on " + file.getCanonicalPath());
            }
        } catch (JSONException e) {
            throw new IOException("Failed to parse log", e);
        }

    }

    /**
     * Get the filename for a log based on its public key. This must be kept in sync with
     * org.conscrypt.ct.CTLogStoreImpl.
     */
    private String getLogFileName(String base64PublicKey) {
        byte[] keyBytes = Base64.decode(base64PublicKey, Base64.DEFAULT);
        try {
            byte[] id = MessageDigest.getInstance("SHA-256").digest(keyBytes);
            return HexDump.toHexString(id, false);
        } catch (NoSuchAlgorithmException e) {
            // SHA-256 is guaranteed to be available.
            throw new RuntimeException(e);
        }
    }

    private void writeLogEntry(OutputStreamWriter out, String key, String value)
            throws IOException {
        out.write(key + ":" + value + "\n");
    }

    private void deleteOldLogDirectories() throws IOException {
        if (!updateDir.exists()) {
            return;
        }
        File currentTarget = new File(updateDir, "current").getCanonicalFile();
        FileFilter filter = new FileFilter() {
            @Override
            public boolean accept(File file) {
                return !currentTarget.equals(file) && file.getName().startsWith(LOGDIR_PREFIX);
            }
        };
        for (File f : updateDir.listFiles(filter)) {
            FileUtils.deleteContentsAndDir(f);
        }
    }
}
