/* * Copyright (C) 2012 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.tools.lint.checks; import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LintUtils; import com.android.tools.lint.detector.api.Location; import com.android.tools.lint.detector.api.Project; import com.android.tools.lint.detector.api.Scope; import com.android.tools.lint.detector.api.Severity; import com.android.tools.lint.detector.api.Speed; import com.google.common.base.Charsets; import com.google.common.io.Files; import java.io.File; import java.io.IOException; /** * Looks for packaged private key files. */ public class PrivateKeyDetector extends Detector { /** Packaged private key files */ public static final Issue ISSUE = Issue.create( "PackagedPrivateKey", //$NON-NLS-1$ "Looks for packaged private key files", "In general, you should not package private key files inside your app.", Category.SECURITY, 8, Severity.WARNING, PrivateKeyDetector.class, Scope.ALL_RESOURCES_SCOPE); /** Constructs a new {@link PrivateKeyDetector} check */ public PrivateKeyDetector() { } private boolean isPrivateKeyFile(File file) { if (!file.isFile() || (!LintUtils.endsWith(file.getPath(), "pem") && //NON-NLS-1$ !LintUtils.endsWith(file.getPath(), "key"))) { //NON-NLS-1$ return false; } try { String firstLine = Files.readFirstLine(file, Charsets.US_ASCII); return firstLine != null && firstLine.startsWith("---") && //NON-NLS-1$ firstLine.contains("PRIVATE KEY"); //NON-NLS-1$ } catch (IOException ex) { // Don't care } return false; } private void checkFolder(Context context, File dir) { if (dir.isDirectory()) { File[] files = dir.listFiles(); if (files != null) { for (File file : files) { if (file.isDirectory()) { checkFolder(context, file); } else { if (isPrivateKeyFile(file)) { String fileName = file.getParentFile().getName() + File.separator + file.getName(); String message = String.format( "The %1$s file seems to be a private key file. " + "Please make sure not to embed this in your APK file.", fileName); context.report(ISSUE, Location.create(file), message, null); } } } } } } @Override public void afterCheckProject(@NonNull Context context) { if (!context.getProject().getReportIssues()) { // If this is a library project not being analyzed, ignore it return; } Project project = context.getProject(); File projectFolder = project.getDir(); checkFolder(context, new File(projectFolder, "res")); checkFolder(context, new File(projectFolder, "assets")); for (File srcFolder : project.getJavaSourceFolders()) { checkFolder(context, srcFolder); } } @Override public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override public @NonNull Speed getSpeed() { return Speed.NORMAL; } }