<commit_before>#!/usr/bin/env python
# encoding: utf-8
import os
import tempfile
import parsedatetime.parsedatetime as pdt
import parsedatetime.parsedatetime_consts as pdc
import subprocess
import re
import argparse
from datetime import datetime
import time
try: import simplejson as json
except ImportError: import json
import sys
import readline, glob
from Crypto.Cipher import AES
from Crypto.Random import random, atfork
import hashlib
import getpass
import mimetypes

default_config = {
    'journal': os.path.expanduser("~/journal.txt"),
    'editor': "",
    'encrypt': False,
    'password': "",
    'default_hour': 9,
    'default_minute': 0,
    'timeformat': "%Y-%m-%d %H:%M",
    'tagsymbols': '@'
}

class Entry:
    def __init__(self, journal, date=None, title="", body=""):
        self.journal = journal # Reference to journal mainly to access it's config
        self.date = date
        self.title = title.strip()
        self.body = body.strip()
        self.tags = self.parse_tags()

    def parse_tags(self):
        fulltext = " ".join([self.title, self.body]).lower()
        tags = re.findall(r"([%s]\w+)" % self.journal.config['tagsymbols'], fulltext)
        self.tags = set(tags)

    def __str__(self):
        date_str = self.date.strftime(self.journal.config['timeformat'])
        body_wrapper = "\n" if self.body else ""
        body = body_wrapper + self.body.strip()
        space = "\n"

        return "%(date)s %(title)s %(body)s %(space)s" % {
            'date': date_str,
            'title': self.title,
            'body': body,
            'space': space
        }

    def __repr__(self):
        return str(self)

    def to_dict(self):
        return {
            'title': self.title.strip(),
            'body': self.body.strip(),
            'date': self.date.strftime("%Y-%m-%d"),
            'time': self.date.strftime("%H:%M")
        }

class Journal:
    def __init__(self, config, **kwargs):
        config.update(kwargs)
        self.config = config

        # Set up date parser
        consts = pdc.Constants()
        consts.DOWParseStyle = -1 # "Monday" will be either today or the last Monday
        self.dateparse = pdt.Calendar(consts)
        self.key = None # used to decrypt and encrypt the journal

        journal_txt = self.open()
        self.entries = self.parse(journal_txt)
        self.sort()

    def _block_tail(self, s, b=16, force=False):
        """Appends spaces to a string until length is a multiple of b"""
        if force and len(s) % 16 == 0:
            return s + " "*16
        return s + " "*(b - len(s) % b)

    def _decrypt(self, cipher):
        """Decrypts a cipher string using self.key as the key and the first 16 byte of the cipher as the IV"""
        crypto = AES.new(self.key, AES.MODE_CBC, cipher[:16])
        plain = crypto.decrypt(cipher[16:])
        return plain

    def _encrypt(self, plain):
        """Encrypt a plaintext string using self.key as the key"""
        atfork() # A seed for PyCrypto
        iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16))
        crypto = AES.new(self.key, AES.MODE_CBC, iv)
        if len(plain) % 16 != 0:
            plain += " " * (16 - len(plain) % 16)
        else: # Always pad so we can detect properly decrypted files :)
            plain += " " * 16
        return iv + crypto.encrypt(plain)

    def open(self, filename=None):
        """Opens the journal file defined in the config and parses it into a list of Entries.
        Entries have the form (date, title, body)."""
        filename = filename or self.config['journal']
        journal = None
        with open(filename) as f:
            journal = f.read()
        if self.config['encrypt']:
            password = self.config['password'] or getpass.getpass()
            self.key = hashlib.sha256(password).digest()
            journal = self._decrypt(journal)
        print journal
        return journal

    def parse(self, journal):
        """Parses a journal that's stored in a string and returns a list of entries"""

        # Entries start with a line that looks like 'date title' - let's figure out how
        # long the date will be by constructing one
        date_length = len(datetime.today().strftime(self.config['timeformat']))

        # Initialise our current entry
        entries = []
        current_entry = None

        for line in journal.split(os.linesep):
            if line:
                try:
                    new_date = datetime.fromtimestamp(time.mktime(time.strptime(line[:date_length], self.config['timeformat'])))
                    # make a journal entry of the current stuff first
                    if new_date and current_entry:
                        entries.append(current_entry)
                    # Start constructing current entry
                    current_entry = Entry(self, date=new_date, title=line[date_length+1:])<commit_msg>Queries the password three times before exiting<commit_after>#!/usr/bin/env python
# encoding: utf-8
import os
import tempfile
import parsedatetime.parsedatetime as pdt
import parsedatetime.parsedatetime_consts as pdc
import subprocess
import re
import argparse
from datetime import datetime
import time
try: import simplejson as json
except ImportError: import json
import sys
import readline, glob
from Crypto.Cipher import AES
from Crypto.Random import random, atfork
import hashlib
import getpass
import mimetypes

default_config = {
    'journal': os.path.expanduser("~/journal.txt"),
    'editor': "",
    'encrypt': False,
    'password': "",
    'default_hour': 9,
    'default_minute': 0,
    'timeformat': "%Y-%m-%d %H:%M",
    'tagsymbols': '@'
}

class Entry:
    def __init__(self, journal, date=None, title="", body=""):
        self.journal = journal # Reference to journal mainly to access it's config
        self.date = date
        self.title = title.strip()
        self.body = body.strip()
        self.tags = self.parse_tags()

    def parse_tags(self):
        fulltext = " ".join([self.title, self.body]).lower()
        tags = re.findall(r"([%s]\w+)" % self.journal.config['tagsymbols'], fulltext)
        self.tags = set(tags)

    def __str__(self):
        date_str = self.date.strftime(self.journal.config['timeformat'])
        body_wrapper = "\n" if self.body else ""
        body = body_wrapper + self.body.strip()
        space = "\n"

        return "%(date)s %(title)s %(body)s %(space)s" % {
            'date': date_str,
            'title': self.title,
            'body': body,
            'space': space
        }

    def __repr__(self):
        return str(self)

    def to_dict(self):
        return {
            'title': self.title.strip(),
            'body': self.body.strip(),
            'date': self.date.strftime("%Y-%m-%d"),
            'time': self.date.strftime("%H:%M")
        }

class Journal:
    def __init__(self, config, **kwargs):
        config.update(kwargs)
        self.config = config

        # Set up date parser
        consts = pdc.Constants()
        consts.DOWParseStyle = -1 # "Monday" will be either today or the last Monday
        self.dateparse = pdt.Calendar(consts)
        self.key = None # used to decrypt and encrypt the journal

        journal_txt = self.open()
        self.entries = self.parse(journal_txt)
        self.sort()

    def _block_tail(self, s, b=16, force=False):
        """Appends spaces to a string until length is a multiple of b"""
        if force and len(s) % 16 == 0:
            return s + " "*16
        return s + " "*(b - len(s) % b)

    def _decrypt(self, cipher):
        """Decrypts a cipher string using self.key as the key and the first 16 byte of the cipher as the IV"""
        crypto = AES.new(self.key, AES.MODE_CBC, cipher[:16])
        plain = crypto.decrypt(cipher[16:])
        if plain[-1] != " ": # Journals are always padded
            return None
        else:
            return plain

    def _encrypt(self, plain):
        """Encrypt a plaintext string using self.key as the key"""
        atfork() # A seed for PyCrypto
        iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16))
        crypto = AES.new(self.key, AES.MODE_CBC, iv)
        if len(plain) % 16 != 0:
            plain += " " * (16 - len(plain) % 16)
        else: # Always pad so we can detect properly decrypted files :)
            plain += " " * 16
        return iv + crypto.encrypt(plain)

    def open(self, filename=None):
        """Opens the journal file defined in the config and parses it into a list of Entries.
        Entries have the form (date, title, body)."""
        filename = filename or self.config['journal']
        journal = None
        with open(filename) as f:
            journal = f.read()
        if self.config['encrypt']:
            decrypted = None
            attempts = 0
            while not decrypted:
                password = self.config['password'] or getpass.getpass()
                self.key = hashlib.sha256(password).digest()
                decrypted = self._decrypt(journal)
                if not decrypted:
                    attempts += 1
                    self.config['password'] = None # This doesn't work.
                    if attempts < 3:
                        print("Wrong password, try again.")
                    else: 
                        print("Extremely wrong password.")
                        sys.exit(-1)
            journal = decrypted
        return journal

    def parse(self, journal):
        """Parses a journal that's stored in a string and returns a list of entries"""

        # Entries start with a line that looks like 'date title' - let's figure out how
        # long the date will be by constructing one
        date_length = len(datetime.today().strftime(self.config['timeformat']))

        # Initialise our current entry
        entries = []
        current_entry = None

        for line in journal.split(os.linesep):
            if line:
                try:
                    new_date = datetime.fromtimestamp(time.mktime(time.strptime(line[:date_length], self.config['timeformat'])))
                    # make a journal entry of the current stuff first
                    if new_date and current_entry:
                        entries.append(current_entry)
                    # Start constructing current entry
                    current_entry = Entry(self, date=new_date, title=line[date_length+1:])
{'fraction_non_alphanumeric': 0.11614758025874461, 'fraction_numerical': 0.006995687589841878, 'mean_word_length': 2.1414810355207705, 'pattern_counts': {'":': 1, '<': 4, '<?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': '1702230', 'n_tokens_mistral': 3103, 'n_tokens_neox': 2938, 'n_words': 919}