<commit_before>// +build linux

package store

import (
	"bytes"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/adamdecaf/cert-manage/tools/file"
	"github.com/adamdecaf/cert-manage/tools/pem"
	"github.com/adamdecaf/cert-manage/whitelist"
)

type cadir struct {
	// base dir for all ca certs
	dir string
	// the filepath containing all certs (optional)
	all string
}

func (ca *cadir) empty() bool {
	if ca == nil {
		return false
	}
	path, err := filepath.Abs(ca.all)
	return err != nil || !file.Exists(path)
}

var (
	// From Go's source, src/crypto/x509/root_linux.go
	cadirs = []cadir{
		// Debian/Ubuntu/Gentoo/etc..
		cadir{
			dir: "/etc/ssl/certs",
			all: "/etc/ssl/certs/ca-certificates.crt",
		},
		// TODO(adam): These paths aren't supported, _yet_
		// "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
		// "/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
		// "/etc/ssl/ca-bundle.pem",                            // OpenSUSE
		// "/etc/pki/tls/cacert.pem",                           // OpenELEC
	}
)

type linuxStore struct {
	ca cadir
}

func platform() Store {
	var ca cadir
	// find the cadir, if it exists
	for _, ca = range cadirs {
		if ca.empty() {
			break
		}
	}

	return linuxStore{
		ca: ca,
	}
}

func (s linuxStore) List() ([]*x509.Certificate, error) {
	if s.ca.empty() {
		return nil, nil
	}

	bytes, err := ioutil.ReadFile(s.ca.all)
	if err != nil {
		return nil, err
	}

	certs, err := pem.Parse(bytes)
	if err != nil {
		return nil, err
	}

	return certs, nil
}

// Remove walks through the installed CA certificates on a linux based
// machine and deactivates those that are not to be trusted.
//
// Steps
// 1. Walk through the dir (/etc/ssl/certs/) and chmod 000 the certs we aren't trusting
// 2. Run `update-ca-certificates` to re-create the ca-certificates.crt file
func (s linuxStore) Remove(wh whitelist.Whitelist) error {
	// Check each CA cert file and optionally disable
	walk := func(path string, info os.FileInfo, err error) error {
		// Ignore SkipDir and directories
		if (err != nil && err != filepath.SkipDir) || info.IsDir() {
			return nil
		}

		// TODO(adam): ignore backup files, or those w/ info.Mode == 000

		// read the cert(s) contained at the file and only keep those
		// that aren't removable
		read, err := pem.FromFile(path)
		if err != nil {
			return err
		}
		for i := 0; i < len(read); i++ {
			// Remove the cert if we don't match
			if !wh.Matches(read[i]) {
				read = append(read[:i], read[i+1:]...)
				if len(read) == 0 {
					break
				}
			}
		}

		// // chmod 000 the file if it's going to be empty
		// if len(read) == 0 {
		// 	// disable the file
		// 	// fmt.Println("A")
		// 	return os.Remove(path, 0000)
		// }

		// otherwise, write kept certs from `read` back
		err = pem.ToFile(path, read)
		if err != nil {
			return err
		}

		return nil
	}

	// Walk the fs and deactivate each cert
	err := filepath.Walk(s.ca.dir, walk)
	if err != nil {
		return err
	}

	// Update the certs trust system-wide
	var out bytes.Buffer
	cmd := exec.Command("/usr/sbin/update-ca-certificates")
	cmd.Stdout = &out
<commit_msg>store/linux: don't chmod 000 empty files<commit_after>// +build linux

package store

import (
	"bytes"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/adamdecaf/cert-manage/tools/file"
	"github.com/adamdecaf/cert-manage/tools/pem"
	"github.com/adamdecaf/cert-manage/whitelist"
)

type cadir struct {
	// base dir for all ca certs
	dir string
	// the filepath containing all certs (optional)
	all string
}

func (ca *cadir) empty() bool {
	if ca == nil {
		return false
	}
	path, err := filepath.Abs(ca.all)
	return err != nil || !file.Exists(path)
}

var (
	// From Go's source, src/crypto/x509/root_linux.go
	cadirs = []cadir{
		// Debian/Ubuntu/Gentoo/etc..
		cadir{
			dir: "/etc/ssl/certs",
			all: "/etc/ssl/certs/ca-certificates.crt",
		},
		// TODO(adam): These paths aren't supported, _yet_
		// "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
		// "/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
		// "/etc/ssl/ca-bundle.pem",                            // OpenSUSE
		// "/etc/pki/tls/cacert.pem",                           // OpenELEC
	}
)

type linuxStore struct {
	ca cadir
}

func platform() Store {
	var ca cadir
	// find the cadir, if it exists
	for _, ca = range cadirs {
		if ca.empty() {
			break
		}
	}

	return linuxStore{
		ca: ca,
	}
}

func (s linuxStore) List() ([]*x509.Certificate, error) {
	if s.ca.empty() {
		return nil, nil
	}

	bytes, err := ioutil.ReadFile(s.ca.all)
	if err != nil {
		return nil, err
	}

	certs, err := pem.Parse(bytes)
	if err != nil {
		return nil, err
	}

	return certs, nil
}

// Remove walks through the installed CA certificates on a linux based
// machine and deactivates those that are not to be trusted.
//
// Steps
// 1. Walk through the dir (/etc/ssl/certs/) and chmod 000 the certs we aren't trusting
// 2. Run `update-ca-certificates` to re-create the ca-certificates.crt file
func (s linuxStore) Remove(wh whitelist.Whitelist) error {
	// Check each CA cert file and optionally disable
	walk := func(path string, info os.FileInfo, err error) error {
		// Ignore SkipDir and directories
		if (err != nil && err != filepath.SkipDir) || info.IsDir() {
			return nil
		}

		// read the cert(s) contained at the file and only keep those
		// that aren't removable
		read, err := pem.FromFile(path)
		if err != nil {
			return err
		}
		for i := 0; i < len(read); i++ {
			// Remove the cert if we don't match
			if !wh.Matches(read[i]) {
				read = append(read[:i], read[i+1:]...)
				if len(read) == 0 {
					break
				}
			}
		}

		// otherwise, write kept certs from `read` back
		err = pem.ToFile(path, read)
		if err != nil {
			return err
		}

		return nil
	}

	// Walk the fs and deactivate each cert
	err := filepath.Walk(s.ca.dir, walk)
	if err != nil {
		return err
	}

	// Update the certs trust system-wide
	var out bytes.Buffer
	cmd := exec.Command("/usr/sbin/update-ca-certificates")
	cmd.Stdout = &out

{'fraction_non_alphanumeric': 0.14675155076722168, 'fraction_numerical': 0.008488410055501142, 'mean_word_length': 2.523289246693502, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7436664', 'n_tokens_mistral': 2550, 'n_tokens_neox': 2261, 'n_words': 648}