<commit_before>#![allow(dead_code, unused_must_use, unused_imports, unstable)]

extern crate "rustc-serialize" as rustc_serialize;
extern crate log;

use utils;
use std::fmt;
use std::str;
use std::string;
use std::ops::Drop;
use std::old_io::{File, Open, Append, Read, Write, ReadWrite};
use std::old_io::TempDir;
use std::old_io::fs;
use std::old_io::fs::PathExtensions;
use std::old_io::{BufferedReader, BufferedWriter};
use std::old_path::BytesContainer;
use self::rustc_serialize::base64::{STANDARD, FromBase64, ToBase64};

/// A result type that's specfici to the Reader module.
/// TODO Decide if this is necessary
pub type ReaderResult<T, E> = Result<T, E>;

/// Reader struct of its basic properties.
pub struct Reader {
    /// Path to file where the Reader is created.
    path: Path,
    /// BufferedReader for reading the file. Initialized with the Path.
    read_buffer: BufferedReader<File>,
    /// BufferedWriter for writing to the file. Initialized with the Path.
    write_buffer: BufferedWriter<File>,
    /// Index counter to know how many records exist.
    id_count: u64,
}

/// ReaderFile traits
pub trait ReaderFile {
    // Opens a new File to the Path provided.
    // Returns a boxed File.
    fn open(&self) -> File;
    // Inserts a string to the database.
    fn insert_string(&mut self, String);
}

impl fmt::Debug for Reader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Reader: ( path: {} )", self.path.display())
    }
}

impl ToString for Reader {
    fn to_string(&self) -> String {
        format!("{:?}", self)
    }
}

impl Reader {
    /// Creates a new Reader from the Path provided.
    /// Opens a new BufferedReader and BufferedWriter (with Append mode) to the file.
    /// If the file doesn't exist, it is created.
    // TODO, create a .lock file to let other readers know the database is in use (see: #2).
    pub fn new(apath: &Path) -> Reader {
        Reader::file_lock_create(apath);
        // if file_lock exists, panic and crash with appropriate error.
        // Error: A .lock file already exists, if this is from a previous session, consider
        // deleting the .lock file.

        if !apath.exists() {
            let mut file = File::create(&apath.clone());
            file.write_line("0");
            file.flush();
        }

        let mut buffer_writer = match File::open_mode(&apath.clone(), Append, ReadWrite) {
                                    Ok(file)    => { BufferedWriter::new(file) },
                                    Err(..)     => {
                                        panic!("Failed to create a write buffer to file path: {}",
                                                apath.display())
                                    },
                                };

        let mut buffer_reader = match File::open_mode(&apath.clone(), Open, Read) {
                                    Ok(file)    => BufferedReader::new(file),
                                    Err(..)     => panic!("Failed to create a read buffer to file path: {}",
                                                            apath.display()),
                                };

        let current_record_count = match buffer_reader.read_line() {
                                        Ok(line)    => {
                                            let first_line = utils::string_slice(line);
                                            let input = first_line[0].trim().parse::<u64>();
                                            match input {
                                                Ok(num) => num,
                                                Err(..) => {
                                                    warn!("We can't parse the record count from metadata");
                                                    warn!("Our parsed db metadata: {:?}", first_line);
                                                    // Setting counter to zero because we can't do
                                                    // anything else.
                                                    0
                                                },
                                            }
                                        },
                                        Err(..) => {
                                            error!("Can't read database metadata! Everybody do the flop!");
                                            // Setting counter to zero because we can't do anything
                                            // else.
                                            0
                                        },
                                   };

        Reader {
            path: apath.clone(),
            read_buffer: buffer_reader,
            write_buffer: buffer_writer,
            id_count: current_record_count,
        }
    }

    /// This is a helder function that realistically shouldn't exist in production.
    /// Used primarily for "spilling" the entire database file into a Vec<String>
    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        let mut buffer_reader = BufferedReader::new(File::open(&self.path.clone()));
        for line_iter in buffer_reader.lines() {
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    /// Inserts a &str into the database.
    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
        self.id_count = self.id_count + 1;
        self.update_counter(self.id_count);
    }

    /// Inserts a byte array into the database.
    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
        self.id_count = self.id_count + 1;
        self.update_counter(self.id_count);
    }

    /// Read a &str from the database
    fn read_line(&mut self) -> String {
        match self.read_buffer.read_line() {
            Ok(string)  => { string.to_string() },
            Err(..)     => {
                error!("Unable to read next line. BufferedReader error.");
                "".to_string()
            },
        }
    }

    /// Creates a .lock file to let other processes know that the database is in use.
    /// This is still unfinished and should be considered broken.
    fn file_lock_create(lockpath: &Path) -> (bool, Path) {
        if lockpath.exists() {
            return (true, lockpath.clone())
        }

        let mut filelock_path = lockpath.clone();

        // Remove the old name
        filelock_path.pop();
        // Surely, there's a less ugly way to take the filename of a Path and convert it to a string?!
        let mut filename_lock: String = str::from_utf8(lockpath.filename().unwrap()).unwrap().to_string();
        filename_lock.push_str(".lock");
        // Join the new filename with the path
        filelock_path = filelock_path.join(filename_lock);
        println!("{}", filelock_path.display());
        match File::create(&filelock_path) {
            Ok(..)  => (true, filelock_path),
            Err(..) => (false, filelock_path),
        }
    }

    /// Removes .lock file when the reader process is completed.
    fn file_lock_remove(&self, filelock: &Path) -> bool {
        fs::unlink(&filelock.clone());
        filelock.exists()
    }

    /// Updates database counter on disk.
    fn update_counter(&self, value: u64) {
        let file = File::open_mode(&self.path.clone(), Open, Write);
        let mut buffer_writer = BufferedWriter::new(file);
        buffer_writer.write_line(value.to_string().as_slice());
        buffer_writer.flush();
    }

}

impl Drop for Reader {
    fn drop(&mut self) {
        let mut lock_path = self.path.clone();
        let mut filename = String::from_str(lock_path.filename_str().unwrap());
        filename.push_str(".lock");
        lock_path.set_filename(filename);
        println!("File about to remove: {}", lock_path.display());
        self.file_lock_remove(&lock_path);
    }
}

impl ReaderFile for Reader {

    fn open(&self) -> File {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(&*item);
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(&Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::rand;
    let mut path_str = String::from_str("tests/");
    path_str.push_str(&*rand::random::<usize>().to_string());
    path_str.push_str(".txt");

    let (tempdir, apath) = setup();
    let path = tempdir.path().join(rand::random::<usize>().to_string());

    //let path = Path::new(path_str);
    assert!(!path.exists());
    let reader = Reader::new(&path.clone());
    assert!(path.exists());
    fs::unlink(&path);
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["2".to_string(), "10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["3".to_string(), "10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["3".to_string(), "10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_file_path_lock() {

    let (tempdir, path) = setup();

    let mut expected = path.clone();
    expected.pop();

    // Surely, there's a less ugly way to take the filename of a Path and convert it to a string?!
    let mut filename_lock: String = str::from_utf8(path.filename().unwrap()).unwrap().to_string();
    filename_lock.push_str(".lock");
    expected = expected.join(filename_lock);

    let reader = Reader::new(&expected.clone());
    assert!(expected.exists() && expected.is_file());
}

#[test]
fn test_reader_show() {
    let reader: Reader = Reader::new(&Path::new("tests/file.txt"));
    assert_eq!("Reader: ( path: tests/file.txt )", reader.to_string());
}

/// Test setup code. Current functions:
/// - Create a new file with `TempDir` and a random name.
/// - Write a 2x2 matrix of records into the base-test.txt file
/// - Returns a tuple of `TempDir` and `Path` to the file.
/// - The path is for r/w access and `TempDir` is so that the directory
///   isn't deleted before the test is completed.
#[allow(dead_code, unused_must_use)]
fn setup() -> (TempDir, Path) {
    use std::rand;

    let tmpdir = match TempDir::new("txtdb-tests") {
        Ok(dir) => dir,
        Err(..) => panic!("Cannot create test directory. Tests will fail."),
    };

    let final_dir = tmpdir.path().join(rand::random::<usize>().to_string());

    let mut file = File::create(&final_dir.clone());
    file.write_str("2\n10 11\n20 21\n");

    (tmpdir, final_dir)
}
<commit_msg>Removed old io code and put comment placeholders<commit_after>#![allow(dead_code, unused_must_use, unused_imports, unstable)]

extern crate "rustc-serialize" as rustc_serialize;
extern crate log;

use utils;
use std::fmt;
use std::str;
use std::string;
use std::ops::Drop;
use self::rustc_serialize::base64::{STANDARD, FromBase64, ToBase64};

/// A result type that's specfici to the Reader module.
/// TODO Decide if this is necessary
pub type ReaderResult<T, E> = Result<T, E>;

/// Reader struct of its basic properties.
pub struct Reader {
    /// Path to file where the Reader is created.
    path: Path,
    /// BufferedReader for reading the file. Initialized with the Path.
    read_buffer: BufferedReader<File>,
    /// BufferedWriter for writing to the file. Initialized with the Path.
    write_buffer: BufferedWriter<File>,
    /// Index counter to know how many records exist.
    id_count: u64,
}

/// ReaderFile traits
pub trait ReaderFile {
    // Opens a new File to the Path provided.
    // Returns a boxed File.
    fn open(&self) -> File;
    // Inserts a string to the database.
    fn insert_string(&mut self, String);
}

impl fmt::Debug for Reader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Reader: ( path: {} )", self.path.display())
    }
}

impl ToString for Reader {
    fn to_string(&self) -> String {
        format!("{:?}", self)
    }
}

impl Reader {
    /// Creates a new Reader from the Path provided.
    /// Opens a new BufferedReader and BufferedWriter (with Append mode) to the file.
    /// If the file doesn't exist, it is created.
    // TODO: create a .lock file to let other readers know the database is in use (see: #2).
    pub fn new(apath: &Path) -> Reader {
        Reader::file_lock_create(apath);
        // if file_lock exists, panic and crash with appropriate error.
        // Error: A .lock file already exists, if this is from a previous session, consider
        // deleting the .lock file.

        // Check if file exists or not. If not, create it.

        // Create a buffer_writer and buffer_reader.

        // Get the current_record count or set it to zero. See old_controller for logic.
        Reader {
            path: apath.clone(),
            read_buffer: buffer_reader,
            write_buffer: buffer_writer,
            id_count: current_record_count,
        }
    }

    /// This is a helder function that realistically shouldn't exist in production.
    /// Used primarily for "spilling" the entire database file into a Vec<String>
    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        let mut buffer_reader = BufferedReader::new(File::open(&self.path.clone()));
        for line_iter in buffer_reader.lines() {
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    /// Inserts a &str into the database.
    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
        self.id_count = self.id_count + 1;
        self.update_counter(self.id_count);
    }

    /// Inserts a byte array into the database.
    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
        self.id_count = self.id_count + 1;
        self.update_counter(self.id_count);
    }

    /// Read a &str from the database
    fn read_line(&mut self) -> String {
        match self.read_buffer.read_line() {
            Ok(string)  => { string.to_string() },
            Err(..)     => {
                error!("Unable to read next line. BufferedReader error.");
                "".to_string()
            },
        }
    }

    /// Creates a .lock file to let other processes know that the database is in use.
    /// This is still unfinished and should be considered broken.
    fn file_lock_create(lockpath: &Path) -> (bool, Path) {
        // Check if lock path exists, if not return false and create a new lock file
        if lockpath.exists() {
            return (true, lockpath.clone())
        }

        // Create a filename.lock
    }

    /// Removes .lock file when the reader process is completed.
    fn file_lock_remove(&self, filelock: &Path) -> bool {
        fs::remove_file(&filelock.clone());
        filelock.exists()
    }

    /// Updates database counter on disk.
    fn update_counter(&self, value: u64) {
        // Get file to open for writing
        let mut buffer_writer = BufWriter::new(file);
        buffer_writer.write_line(value.to_string().as_slice());
        buffer_writer.flush();
    }

}

impl Drop for Reader {
    fn drop(&mut self) {
        // Remove the lock file.
    }
}

impl ReaderFile for Reader {

    fn open(&self) -> File {
        // Open file
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(&*item);
    }

}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_open_file() {
        let reader = Reader::new(&Path::new("tests/base-test.txt"));
    }

    #[test]
    fn test_create_file() {
        use std::rand;
        let mut path_str = String::from_str("tests/");
        path_str.push_str(&*rand::random::<usize>().to_string());
        path_str.push_str(".txt");

        let (tempdir, apath) = setup();
        let path = tempdir.path().join(rand::random::<usize>().to_string());

        assert!(!path.exists());
        let reader = Reader::new(&path.clone());
        assert!(path.exists());
        fs::unlink(&path);
    }

    #[test]
    fn test_read_file() {
        // We should output the entire contents of the database file we open
        // into standard output.
        let (tempdir, path) = setup();
        let mut reader = Reader::new(&path);
        let expected = vec!["2".to_string(), "10 11".to_string(), "20 21".to_string()];
        assert_eq!(expected, reader.spill());
    }

    #[test]
    fn test_write_string_to_file() {
        let (tempdir, path) = setup();
        let mut reader = Reader::new(&path);
        let expected = vec!["3".to_string(), "10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
        reader.insert_string("30 31".to_string());
        assert_eq![expected, reader.spill()];
    }

    #[test]
    fn test_write_str_to_file() {
        let (tempdir, path) = setup();
        let mut reader = Reader::new(&path);
        let expected = vec!["3".to_string(), "10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
        reader.insert_str("30 31");
        assert_eq![expected, reader.spill()];
    }

    #[test]
    fn test_file_path_lock() {

        let (tempdir, path) = setup();

        let mut expected = path.clone();
        expected.pop();

        // Surely, there's a less ugly way to take the filename of a Path and convert it to a string?!
        let mut filename_lock: String = str::from_utf8(path.filename().unwrap()).unwrap().to_string();
        filename_lock.push_str(".lock");
        expected = expected.join(filename_lock);

        let reader = Reader::new(&expected.clone());
        assert!(expected.exists() && expected.is_file());
    }

    #[test]
    fn test_reader_show() {
        let reader: Reader = Reader::new(&Path::new("tests/file.txt"));
        assert_eq!("Reader: ( path: tests/file.txt )", reader.to_string());
    }

    /// Test setup code. Current functions:
    /// - Create a new file with `TempDir` and a random name.
    /// - Write a 2x2 matrix of records into the base-test.txt file
    /// - Returns a tuple of `TempDir` and `Path` to the file.
    /// - The path is for r/w access and `TempDir` is so that the directory
    ///   isn't deleted before the test is completed.
    #[allow(dead_code, unused_must_use)]
    fn setup() -> (TempDir, Path) {
        use std::rand;

        let tmpdir = match TempDir::new("txtdb-tests") {
            Ok(dir) => dir,
            Err(..) => panic!("Cannot create test directory. Tests will fail."),
        };

        let final_dir = tmpdir.path().join(rand::random::<usize>().to_string());

        let mut file = File::create(&final_dir.clone());
        file.write_str("2\n10 11\n20 21\n");

        (tmpdir, final_dir)
    }
}
<|endoftext|>


<commit_before>use std::fmt::Write;

use hir::{AdtDef, Ty, source_binder};
use hir::db::HirDatabase;

use ra_syntax::ast::{self, AstNode, Expr};

use crate::{AssistCtx, Assist, AssistId};

pub(crate) fn fill_struct_fields(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let struct_lit = ctx.node_at_offset::<ast::StructLit>()?;

    // If we already have existing struct fields, don't provide the assist.
    // TODO: provide assist for tuple structs
    match struct_lit.named_field_list() {
        Some(named_field_list) if named_field_list.fields().count() > 0 => {
            return None;
        }
        _ => {}
    }

    let expr: &Expr = struct_lit.into();
    let function =
        source_binder::function_from_child_node(ctx.db, ctx.frange.file_id, struct_lit.syntax())?;

    let infer_result = function.infer(ctx.db);
    let source_map = function.body_source_map(ctx.db);
    let node_expr = source_map.node_expr(expr)?;
    let struct_lit_ty = infer_result[node_expr].clone();
    let struct_def = match struct_lit_ty {
        Ty::Adt { def_id: AdtDef::Struct(s), .. } => s,
        _ => return None,
    };

    let struct_name = struct_def.name(ctx.db)?;
    let db = ctx.db;

    ctx.add_action(AssistId("fill_struct_fields"), "fill struct fields", |edit| {
        let mut buf = format!("{} {{\n", struct_name);
        let struct_fields = struct_def.fields(db);
        for field in struct_fields {
            let field_name = field.name(db).to_string();
            write!(&mut buf, "    {}: (),\n", field_name).unwrap();
        }
        buf.push_str("}");

        edit.target(struct_lit.syntax().range());
        edit.set_cursor(expr.syntax().range().start());
        edit.replace_node_and_indent(struct_lit.syntax(), buf);
    });

    ctx.build()
}

#[cfg(test)]
mod tests {
    use crate::helpers::{check_assist, check_assist_target};

    use super::fill_struct_fields;

    #[test]
    fn fill_struct_fields_empty_body() {
        check_assist(
            fill_struct_fields,
            r#"
            struct S<'a, D> {
                a: u32,
                b: String,
                c: (i32, i32),
                d: D,
                r: &'a str,
            }

            fn main() {
                let s = S<|> {}
            }
            "#,
            r#"
            struct S<'a, D> {
                a: u32,
                b: String,
                c: (i32, i32),
                d: D,
                r: &'a str,
            }

            fn main() {
                let s = <|>S {
                    a: (),
                    b: (),
                    c: (),
                    d: (),
                    r: (),
                }
            }
            "#,
        );
    }

    #[test]
    fn fill_struct_fields_target() {
        check_assist_target(
            fill_struct_fields,
            r#"
            struct S<'a, D> {
                a: u32,
                b: String,
                c: (i32, i32),
                d: D,
                r: &'a str,
            }

            fn main() {
                let s = S<|> {}
            }
            "#,
            "S {}",
        );
    }
}
<commit_msg>Remove unachievable TODO<commit_after>use std::fmt::Write;

use hir::{AdtDef, Ty, source_binder};
use hir::db::HirDatabase;

use ra_syntax::ast::{self, AstNode, Expr};

use crate::{AssistCtx, Assist, AssistId};

pub(crate) fn fill_struct_fields(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let struct_lit = ctx.node_at_offset::<ast::StructLit>()?;

    // If we already have existing struct fields, don't provide the assist.
    match struct_lit.named_field_list() {
        Some(named_field_list) if named_field_list.fields().count() > 0 => {
            return None;
        }
        _ => {}
    }

    let expr: &Expr = struct_lit.into();
    let function =
        source_binder::function_from_child_node(ctx.db, ctx.frange.file_id, struct_lit.syntax())?;

    let infer_result = function.infer(ctx.db);
    let source_map = function.body_source_map(ctx.db);
    let node_expr = source_map.node_expr(expr)?;
    let struct_lit_ty = infer_result[node_expr].clone();
    let struct_def = match struct_lit_ty {
        Ty::Adt { def_id: AdtDef::Struct(s), .. } => s,
        _ => return None,
    };

    let struct_name = struct_def.name(ctx.db)?;
    let db = ctx.db;

    ctx.add_action(AssistId("fill_struct_fields"), "fill struct fields", |edit| {
        let mut buf = format!("{} {{\n", struct_name);
        let struct_fields = struct_def.fields(db);
        for field in struct_fields {
            let field_name = field.name(db).to_string();
            write!(&mut buf, "    {}: (),\n", field_name).unwrap();
        }
        buf.push_str("}");

        edit.target(struct_lit.syntax().range());
        edit.set_cursor(expr.syntax().range().start());
        edit.replace_node_and_indent(struct_lit.syntax(), buf);
    });

    ctx.build()
}

#[cfg(test)]
mod tests {
    use crate::helpers::{check_assist, check_assist_target};

    use super::fill_struct_fields;

    #[test]
    fn fill_struct_fields_empty_body() {
        check_assist(
            fill_struct_fields,
            r#"
            struct S<'a, D> {
                a: u32,
                b: String,
                c: (i32, i32),
                d: D,
                r: &'a str,
            }

            fn main() {
                let s = S<|> {}
            }
            "#,
            r#"
            struct S<'a, D> {
                a: u32,
                b: String,
                c: (i32, i32),
                d: D,
                r: &'a str,
            }

            fn main() {
                let s = <|>S {
                    a: (),
                    b: (),
                    c: (),
                    d: (),
                    r: (),
                }
            }
            "#,
        );
    }

    #[test]
    fn fill_struct_fields_target() {
        check_assist_target(
            fill_struct_fields,
            r#"
            struct S<'a, D> {
                a: u32,
                b: String,
                c: (i32, i32),
                d: D,
                r: &'a str,
            }

            fn main() {
                let s = S<|> {}
            }
            "#,
            "S {}",
        );
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use embedder_traits::EmbedderMsg;
use ipc_channel::ipc::channel;
use script_traits::{ScriptMsg, ScriptToConstellationChan};
use std::borrow::ToOwned;

pub trait ClipboardProvider {
    // blocking method to get the clipboard contents
    fn clipboard_contents(&mut self) -> String;
    // blocking method to set the clipboard contents
    fn set_clipboard_contents(&mut self, _: String);
}

impl ClipboardProvider for ScriptToConstellationChan {
    fn clipboard_contents(&mut self) -> String {
        let (tx, rx) = channel().unwrap();
        self.send(ScriptMsg::ForwardToEmbedder(
            EmbedderMsg::GetClipboardContents(tx),
        ))
        .unwrap();
        rx.recv().unwrap()
    }
    fn set_clipboard_contents(&mut self, s: String) {
        self.send(ScriptMsg::ForwardToEmbedder(
            EmbedderMsg::SetClipboardContents(s),
        ))
        .unwrap();
    }
}

pub struct DummyClipboardContext {
    content: String,
}

impl DummyClipboardContext {
    pub fn new(s: &str) -> DummyClipboardContext {
        DummyClipboardContext {
            content: s.to_owned(),
        }
    }
}

impl ClipboardProvider for DummyClipboardContext {
    fn clipboard_contents(&mut self) -> String {
        self.content.clone()
    }
    fn set_clipboard_contents(&mut self, s: String) {
        self.content = s;
    }
}
<commit_msg>Remove not needed DummyClipboardContext<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use embedder_traits::EmbedderMsg;
use ipc_channel::ipc::channel;
use script_traits::{ScriptMsg, ScriptToConstellationChan};

pub trait ClipboardProvider {
    // blocking method to get the clipboard contents
    fn clipboard_contents(&mut self) -> String;
    // blocking method to set the clipboard contents
    fn set_clipboard_contents(&mut self, _: String);
}

impl ClipboardProvider for ScriptToConstellationChan {
    fn clipboard_contents(&mut self) -> String {
        let (tx, rx) = channel().unwrap();
        self.send(ScriptMsg::ForwardToEmbedder(
            EmbedderMsg::GetClipboardContents(tx),
        ))
        .unwrap();
        rx.recv().unwrap()
    }
    fn set_clipboard_contents(&mut self, s: String) {
        self.send(ScriptMsg::ForwardToEmbedder(
            EmbedderMsg::SetClipboardContents(s),
        ))
        .unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

use errors::CryptoError;
use sodiumoxide::crypto::stream;
use hash::Hash;
use hash::tree::HashRef;
use blob::{ChunkRef, Key};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

pub struct PlainText(Vec<u8>);
pub struct PlainTextRef<'a>(&'a [u8]);
pub struct CipherText {
    chunks: Vec<Vec<u8>>,
    len: usize,
}
pub struct CipherTextRef<'a>(&'a [u8]);

pub mod authed {
    pub mod desc {
        pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{KEYBYTES, Key, MACBYTES,
                                                                   NONCEBYTES, Nonce};
    }

    pub mod imp {
        pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{gen_key, gen_nonce, open, seal};
    }
}

pub mod sealed {
    pub mod desc {
        pub use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::{MACBYTES, PUBLICKEYBYTES,
                                                                        PublicKey, SECRETKEYBYTES,
                                                                        SecretKey};

        pub const SEALBYTES: usize = PUBLICKEYBYTES + MACBYTES;

        pub fn footer_plain_bytes() -> usize {
            // Footer contains a LittleEndian u64.
            8
        }

        pub fn footer_cipher_bytes() -> usize {
            footer_plain_bytes() + SEALBYTES
        }

        pub fn overhead() -> usize {
            // MAC for the plaintext being sealed + the footer.
            SEALBYTES + footer_cipher_bytes()
        }
    }

    pub mod imp {
        pub use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::gen_keypair;
        pub use sodiumoxide::crypto::sealedbox::curve25519blake2bxsalsa20poly1305::{open, seal};
    }
}

fn wrap_key(key: authed::desc::Key) -> Key {
    Key::XSalsa20Poly1305(key)
}

impl<'a> PlainTextRef<'a> {
    pub fn new(bytes: &[u8]) -> PlainTextRef {
        PlainTextRef(bytes)
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn to_ciphertext(&self,
                         nonce: &authed::desc::Nonce,
                         key: &authed::desc::Key)
                         -> CipherText {
        CipherText::new(authed::imp::seal(&self.0, &nonce, &key))
    }
    pub fn to_sealed_ciphertext(&self, pubkey: &sealed::desc::PublicKey) -> CipherText {
        CipherText::new(sealed::imp::seal(&self.0, &pubkey))
    }
}

impl PlainText {
    pub fn new(bytes: Vec<u8>) -> PlainText {
        PlainText(bytes)
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn as_ref(&self) -> PlainTextRef {
        PlainTextRef::new(&self.0[..])
    }
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }
    pub fn into_vec(self) -> Vec<u8> {
        self.0
    }
}

impl CipherText {
    pub fn empty() -> CipherText {
        CipherText {
            chunks: vec![],
            len: 0,
        }
    }
    pub fn new(ct: Vec<u8>) -> CipherText {
        let len = ct.len();
        CipherText {
            chunks: vec![ct],
            len: len,
        }
    }
    pub fn append(&mut self, mut other: CipherText) {
        self.len += other.len();
        self.chunks.append(&mut other.chunks);
    }
    pub fn len(&self) -> usize {
        self.len
    }
    pub fn random_pad_upto(&mut self, final_len: usize) {
        let len = self.len;
        if final_len > len {
            self.append(CipherText::random_pad(final_len - len));
        }
    }
    pub fn random_pad(size: usize) -> CipherText {
        let key = stream::salsa20::gen_key();
        let nonce = stream::salsa20::gen_nonce();
        CipherText::new(stream::salsa20::stream(size, &nonce, &key))
    }
    pub fn to_vec(&self) -> Vec<u8> {
        let mut out = vec![];
        for c in &self.chunks {
            out.extend_from_slice(&c[..]);
        }
        out
    }

    pub fn slices(&self) -> Vec<&[u8]> {
        self.chunks.iter().map(|x| &x[..]).collect()
    }
}

impl<'a> CipherTextRef<'a> {
    pub fn new(bytes: &'a [u8]) -> CipherTextRef<'a> {
        CipherTextRef(bytes)
    }
    pub fn slice(&self, from: usize, to: usize) -> CipherTextRef<'a> {
        CipherTextRef(&self.0[from..to])
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn split_from_right(&self, len: usize) -> (CipherTextRef<'a>, CipherTextRef<'a>) {
        assert!(self.len() >= len);
        (self.slice(0, self.len() - len), self.slice(self.len() - len, self.len()))
    }
    pub fn to_plaintext(&self,
                        nonce: &authed::desc::Nonce,
                        key: &authed::desc::Key)
                        -> Result<PlainText, CryptoError> {
        Ok((PlainText::new(try!(authed::imp::open(&self.0, &nonce, &key)
            .map_err(|()| "Crypto failed to open authenticated message")))))
    }
    pub fn to_sealed_plaintext(&self,
                               pubkey: &sealed::desc::PublicKey,
                               seckey: &sealed::desc::SecretKey)
                               -> Result<PlainText, CryptoError> {
        Ok(PlainText::new(try!(sealed::imp::open(&self.0, &pubkey, &seckey)
            .map_err(|()| "Crypto failed to open sealed message"))))
    }
}

pub struct RefKey {}

impl RefKey {
    pub fn seal(href: &mut HashRef, pt: PlainTextRef) -> CipherText {
        let key = authed::imp::gen_key();
        href.persistent_ref.key = Some(wrap_key(key.clone()));

        let nonce = authed::desc::Nonce::from_slice(&href.hash.bytes[..authed::desc::NONCEBYTES])
            .unwrap();
        let ct = pt.to_ciphertext(&nonce, &key);
        href.persistent_ref.length = ct.len();

        ct
    }

    pub fn unseal(hash: &Hash,
                  cref: &ChunkRef,
                  ct: CipherTextRef)
                  -> Result<PlainText, CryptoError> {
        assert!(ct.len() >= cref.offset + cref.length);
        let ct = ct.slice(cref.offset, cref.offset + cref.length);
        match cref.key {
            Some(Key::XSalsa20Poly1305(ref key)) => {
                let nonce =
                    authed::desc::Nonce::from_slice(&hash.bytes[..authed::desc::NONCEBYTES])
                        .unwrap();
                Ok(try!(ct.to_plaintext(&nonce, &key)))
            }
            _ => panic!("Unknown blob key type"),
        }
    }
}

pub struct FixedKey {
    pubkey: sealed::desc::PublicKey,
    seckey: Option<sealed::desc::SecretKey>,
}

impl FixedKey {
    pub fn new(pubkey: sealed::desc::PublicKey,
               seckey_opt: Option<sealed::desc::SecretKey>)
               -> FixedKey {
        FixedKey {
            pubkey: pubkey,
            seckey: seckey_opt,
        }
    }

    pub fn seal(&self, pt: PlainTextRef) -> CipherText {
        let mut ct = pt.to_sealed_ciphertext(&self.pubkey);

        // Add ciphertext length as LittleEndian.
        let mut foot_pt = PlainText::new(Vec::with_capacity(8));
        foot_pt.0.write_u64::<LittleEndian>(ct.len() as u64).unwrap();
        assert_eq!(foot_pt.len(), sealed::desc::footer_plain_bytes());

        // Append sealed ciphertext length to full ciphertext.
        ct.append(foot_pt.as_ref().to_sealed_ciphertext(&self.pubkey));
        assert_eq!(ct.len(), pt.len() + sealed::desc::overhead());

        // Return complete ciphertext.
        ct
    }

    pub fn unseal<'a>(&self,
                      ct: CipherTextRef<'a>)
                      -> Result<(CipherTextRef<'a>, PlainText), CryptoError> {
        let seckey = self.seckey.as_ref().expect("unseal requires access to read-key");

        // Read sealed ciphertext length and unseal it.
        let (rest, foot_ct) = ct.split_from_right(sealed::desc::footer_cipher_bytes());
        let foot_pt = try!(foot_ct.to_sealed_plaintext(&self.pubkey, &seckey));
        assert_eq!(foot_pt.len(), sealed::desc::footer_plain_bytes());

        // Parse back from encoded LittleEndian.
        let ct_len = foot_pt.as_bytes().read_u64::<LittleEndian>().unwrap();

        // Read and unseal original ciphertext.
        let (rest, ct) = rest.split_from_right(ct_len as usize);
        Ok((rest, try!(ct.to_sealed_plaintext(&self.pubkey, &seckey))))
    }
}
<commit_msg>Try to avoid panics while reading corrupt blobs.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

use errors::CryptoError;
use sodiumoxide::crypto::stream;
use hash::Hash;
use hash::tree::HashRef;
use blob::{ChunkRef, Key};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

pub struct PlainText(Vec<u8>);
pub struct PlainTextRef<'a>(&'a [u8]);
pub struct CipherText {
    chunks: Vec<Vec<u8>>,
    len: usize,
}
pub struct CipherTextRef<'a>(&'a [u8]);

pub mod authed {
    pub mod desc {
        pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{KEYBYTES, Key, MACBYTES,
                                                                   NONCEBYTES, Nonce};
    }

    pub mod imp {
        pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{gen_key, gen_nonce, open, seal};
    }
}

pub mod sealed {
    pub mod desc {
        pub use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::{MACBYTES, PUBLICKEYBYTES,
                                                                        PublicKey, SECRETKEYBYTES,
                                                                        SecretKey};

        pub const SEALBYTES: usize = PUBLICKEYBYTES + MACBYTES;

        pub fn footer_plain_bytes() -> usize {
            // Footer contains a LittleEndian u64.
            8
        }

        pub fn footer_cipher_bytes() -> usize {
            footer_plain_bytes() + SEALBYTES
        }

        pub fn overhead() -> usize {
            // MAC for the plaintext being sealed + the footer.
            SEALBYTES + footer_cipher_bytes()
        }
    }

    pub mod imp {
        pub use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::gen_keypair;
        pub use sodiumoxide::crypto::sealedbox::curve25519blake2bxsalsa20poly1305::{open, seal};
    }
}

fn wrap_key(key: authed::desc::Key) -> Key {
    Key::XSalsa20Poly1305(key)
}

impl<'a> PlainTextRef<'a> {
    pub fn new(bytes: &[u8]) -> PlainTextRef {
        PlainTextRef(bytes)
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn to_ciphertext(&self,
                         nonce: &authed::desc::Nonce,
                         key: &authed::desc::Key)
                         -> CipherText {
        CipherText::new(authed::imp::seal(&self.0, &nonce, &key))
    }
    pub fn to_sealed_ciphertext(&self, pubkey: &sealed::desc::PublicKey) -> CipherText {
        CipherText::new(sealed::imp::seal(&self.0, &pubkey))
    }
}

impl PlainText {
    pub fn new(bytes: Vec<u8>) -> PlainText {
        PlainText(bytes)
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn as_ref(&self) -> PlainTextRef {
        PlainTextRef::new(&self.0[..])
    }
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }
    pub fn into_vec(self) -> Vec<u8> {
        self.0
    }
}

impl CipherText {
    pub fn empty() -> CipherText {
        CipherText {
            chunks: vec![],
            len: 0,
        }
    }
    pub fn new(ct: Vec<u8>) -> CipherText {
        let len = ct.len();
        CipherText {
            chunks: vec![ct],
            len: len,
        }
    }
    pub fn append(&mut self, mut other: CipherText) {
        self.len += other.len();
        self.chunks.append(&mut other.chunks);
    }
    pub fn len(&self) -> usize {
        self.len
    }
    pub fn random_pad_upto(&mut self, final_len: usize) {
        let len = self.len;
        if final_len > len {
            self.append(CipherText::random_pad(final_len - len));
        }
    }
    pub fn random_pad(size: usize) -> CipherText {
        let key = stream::salsa20::gen_key();
        let nonce = stream::salsa20::gen_nonce();
        CipherText::new(stream::salsa20::stream(size, &nonce, &key))
    }
    pub fn to_vec(&self) -> Vec<u8> {
        let mut out = vec![];
        for c in &self.chunks {
            out.extend_from_slice(&c[..]);
        }
        out
    }

    pub fn slices(&self) -> Vec<&[u8]> {
        self.chunks.iter().map(|x| &x[..]).collect()
    }
}

impl<'a> CipherTextRef<'a> {
    pub fn new(bytes: &'a [u8]) -> CipherTextRef<'a> {
        CipherTextRef(bytes)
    }
    pub fn slice(&self, from: usize, to: usize) -> CipherTextRef<'a> {
        CipherTextRef(&self.0[from..to])
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn split_from_right(&self,
                            len: usize)
                            -> Result<(CipherTextRef<'a>, CipherTextRef<'a>), CryptoError> {
        if self.len() < len {
            Err("crypto read failed".into())
        } else {
            Ok((self.slice(0, self.len() - len), self.slice(self.len() - len, self.len())))
        }
    }
    pub fn to_plaintext(&self,
                        nonce: &authed::desc::Nonce,
                        key: &authed::desc::Key)
                        -> Result<PlainText, CryptoError> {
        Ok((PlainText::new(try!(authed::imp::open(&self.0, &nonce, &key)
            .map_err(|()| "crypto read failed")))))
    }
    pub fn to_sealed_plaintext(&self,
                               pubkey: &sealed::desc::PublicKey,
                               seckey: &sealed::desc::SecretKey)
                               -> Result<PlainText, CryptoError> {
        Ok(PlainText::new(try!(sealed::imp::open(&self.0, &pubkey, &seckey)
            .map_err(|()| "crypto read failed"))))
    }
}

pub struct RefKey {}

impl RefKey {
    pub fn seal(href: &mut HashRef, pt: PlainTextRef) -> CipherText {
        let key = authed::imp::gen_key();
        href.persistent_ref.key = Some(wrap_key(key.clone()));

        let nonce = authed::desc::Nonce::from_slice(&href.hash.bytes[..authed::desc::NONCEBYTES])
            .unwrap();
        let ct = pt.to_ciphertext(&nonce, &key);
        href.persistent_ref.length = ct.len();

        ct
    }

    pub fn unseal(hash: &Hash,
                  cref: &ChunkRef,
                  ct: CipherTextRef)
                  -> Result<PlainText, CryptoError> {
        assert!(ct.len() > cref.offset + cref.length);
        let ct = ct.slice(cref.offset, cref.offset + cref.length);
        match cref.key {
            Some(Key::XSalsa20Poly1305(ref key)) if hash.bytes.len() >=
                                                    authed::desc::NONCEBYTES => {
                match authed::desc::Nonce::from_slice(&hash.bytes[..authed::desc::NONCEBYTES]) {
                    None => Err("crypto read failed".into()),
                    Some(nonce) => Ok(try!(ct.to_plaintext(&nonce, &key))),
                }
            }
            _ => Err("crypto read failed".into()),
        }
    }
}

pub struct FixedKey {
    pubkey: sealed::desc::PublicKey,
    seckey: Option<sealed::desc::SecretKey>,
}

impl FixedKey {
    pub fn new(pubkey: sealed::desc::PublicKey,
               seckey_opt: Option<sealed::desc::SecretKey>)
               -> FixedKey {
        FixedKey {
            pubkey: pubkey,
            seckey: seckey_opt,
        }
    }

    pub fn seal(&self, pt: PlainTextRef) -> CipherText {
        let mut ct = pt.to_sealed_ciphertext(&self.pubkey);

        // Add ciphertext length as LittleEndian.
        let mut foot_pt = PlainText::new(Vec::with_capacity(8));
        foot_pt.0.write_u64::<LittleEndian>(ct.len() as u64).unwrap();
        assert_eq!(foot_pt.len(), sealed::desc::footer_plain_bytes());

        // Append sealed ciphertext length to full ciphertext.
        ct.append(foot_pt.as_ref().to_sealed_ciphertext(&self.pubkey));
        assert_eq!(ct.len(), pt.len() + sealed::desc::overhead());

        // Return complete ciphertext.
        ct
    }

    pub fn unseal<'a>(&self,
                      ct: CipherTextRef<'a>)
                      -> Result<(CipherTextRef<'a>, PlainText), CryptoError> {
        let seckey = self.seckey.as_ref().expect("unseal requires access to read-key");

        // Read sealed ciphertext length and unseal it.
        let (rest, foot_ct) = try!(ct.split_from_right(sealed::desc::footer_cipher_bytes()));
        let foot_pt = try!(foot_ct.to_sealed_plaintext(&self.pubkey, &seckey));
        assert_eq!(foot_pt.len(), sealed::desc::footer_plain_bytes());

        // Parse back from encoded LittleEndian.
        let ct_len = try!(foot_pt.as_bytes()
            .read_u64::<LittleEndian>()
            .map_err(|_| "crypto read failed"));

        // Read and unseal original ciphertext.
        let (rest, ct) = try!(rest.split_from_right(ct_len as usize));
        Ok((rest, try!(ct.to_sealed_plaintext(&self.pubkey, &seckey))))
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

use blob::{ChunkRef, Key};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use errors::CryptoError;
use hash::Hash;
use hash::tree::HashRef;
use sodiumoxide::crypto::stream;
use std::io;

pub struct PlainText(Vec<u8>);
pub struct PlainTextRef<'a>(&'a [u8]);

pub struct CipherText {
    chunks: Vec<Vec<u8>>,
    len: usize,
}
pub struct CipherTextRef<'a>(&'a [u8]);

pub mod authed {
    pub mod desc {
        pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{KEYBYTES, Key, MACBYTES,
                                                                   NONCEBYTES, Nonce};
    }

    pub mod imp {
        pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{gen_key, gen_nonce, open, seal};
    }
}

pub mod sealed {
    pub mod desc {
        pub use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::{MACBYTES, PUBLICKEYBYTES,
                                                                        PublicKey, SECRETKEYBYTES,
                                                                        SecretKey};

        pub const SEALBYTES: usize = PUBLICKEYBYTES + MACBYTES;

        pub fn footer_plain_bytes() -> usize {
            // Footer contains a LittleEndian u64.
            8
        }

        pub fn footer_cipher_bytes() -> usize {
            footer_plain_bytes() + SEALBYTES
        }

        pub fn overhead() -> usize {
            // MAC for the plaintext being sealed + the footer.
            SEALBYTES + footer_cipher_bytes()
        }
    }

    pub mod imp {
        pub use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::gen_keypair;
        pub use sodiumoxide::crypto::sealedbox::curve25519blake2bxsalsa20poly1305::{open, seal};
    }
}

fn wrap_key(key: authed::desc::Key) -> Key {
    Key::XSalsa20Poly1305(key)
}

impl<'a> PlainTextRef<'a> {
    pub fn new(bytes: &[u8]) -> PlainTextRef {
        PlainTextRef(bytes)
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn read_i64(&self) -> Result<i64, io::Error> {
        return (&self.0[..]).read_i64::<LittleEndian>();
    }
    pub fn to_ciphertext(&self,
                         nonce: &authed::desc::Nonce,
                         key: &authed::desc::Key)
                         -> CipherText {
        CipherText::new(authed::imp::seal(self.0, nonce, key))
    }
    pub fn to_sealed_ciphertext(&self, pubkey: &sealed::desc::PublicKey) -> CipherText {
        CipherText::new(sealed::imp::seal(self.0, pubkey))
    }
    pub fn as_ref(&'a self) -> PlainTextRef<'a> {
        PlainTextRef(self.0)
    }
}

impl PlainText {
    pub fn new(bytes: Vec<u8>) -> PlainText {
        PlainText(bytes)
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn as_ref(&self) -> PlainTextRef {
        PlainTextRef::new(&self.0[..])
    }
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }
    pub fn into_vec(self) -> Vec<u8> {
        self.0
    }
    pub fn from_i64(n: i64) -> Self {
        let mut buf = PlainText::new(Vec::with_capacity(8));
        buf.0.write_i64::<LittleEndian>(n).unwrap();
        return buf;
    }
}

impl CipherText {
    pub fn empty() -> CipherText {
        CipherText {
            chunks: vec![],
            len: 0,
        }
    }
    pub fn new(ct: Vec<u8>) -> CipherText {
        let len = ct.len();
        CipherText {
            chunks: vec![ct],
            len: len,
        }
    }
    pub fn append(&mut self, mut other: CipherText) {
        self.len += other.len();
        self.chunks.append(&mut other.chunks);
    }
    pub fn len(&self) -> usize {
        self.len
    }
    pub fn random_pad_upto(&mut self, final_len: usize) {
        let len = self.len;
        if final_len > len {
            self.append(CipherText::random_pad(final_len - len));
        }
    }
    pub fn random_pad(size: usize) -> CipherText {
        let key = stream::salsa20::gen_key();
        let nonce = stream::salsa20::gen_nonce();
        CipherText::new(stream::salsa20::stream(size, &nonce, &key))
    }
    pub fn to_vec(&self) -> Vec<u8> {
        let mut out = vec![];
        for c in &self.chunks {
            out.extend_from_slice(&c[..]);
        }
        out
    }

    pub fn slices(&self) -> Vec<&[u8]> {
        self.chunks.iter().map(|x| &x[..]).collect()
    }
}

impl<'a> CipherTextRef<'a> {
    pub fn new(bytes: &'a [u8]) -> CipherTextRef<'a> {
        CipherTextRef(bytes)
    }
    pub fn slice(&self, from: usize, to: usize) -> CipherTextRef<'a> {
        CipherTextRef(&self.0[from..to])
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn split_from_right(&self,
                            len: usize)
                            -> Result<(CipherTextRef<'a>, CipherTextRef<'a>), CryptoError> {
        if self.len() < len {
            Err("crypto read failed: split_from_right".into())
        } else {
            Ok((self.slice(0, self.len() - len), self.slice(self.len() - len, self.len())))
        }
    }
    pub fn to_plaintext(&self,
                        nonce: &authed::desc::Nonce,
                        key: &authed::desc::Key)
                        -> Result<PlainText, CryptoError> {
        Ok(PlainText::new(try!(authed::imp::open(&self.0, &nonce, &key)
           .map_err(|()| "crypto read failed: to_plaintext"))))
    }
    pub fn to_sealed_plaintext(&self,
                               pubkey: &sealed::desc::PublicKey,
                               seckey: &sealed::desc::SecretKey)
                               -> Result<PlainText, CryptoError> {
        Ok(PlainText::new(try!(sealed::imp::open(&self.0, &pubkey, &seckey)
            .map_err(|()| "crypto read failed: to_sealed_plaintext"))))
    }
}

pub struct RefKey {}

impl RefKey {
    pub fn seal(href: &mut HashRef, pt: PlainTextRef) -> CipherText {
        let key = authed::imp::gen_key();
        href.persistent_ref.key = Some(wrap_key(key.clone()));

        let nonce = authed::desc::Nonce::from_slice(&href.hash.bytes[..authed::desc::NONCEBYTES])
            .unwrap();
        let ct = pt.to_ciphertext(&nonce, &key);
        href.persistent_ref.length = ct.len();

        ct
    }

    pub fn unseal(hash: &Hash,
                  cref: &ChunkRef,
                  ct: CipherTextRef)
                  -> Result<PlainText, CryptoError> {
        assert!(ct.len() > cref.offset + cref.length);
        let ct = ct.slice(cref.offset, cref.offset + cref.length);
        match cref.key {
            Some(Key::XSalsa20Poly1305(ref key)) if hash.bytes.len() >=
                                                    authed::desc::NONCEBYTES => {
                match authed::desc::Nonce::from_slice(&hash.bytes[..authed::desc::NONCEBYTES]) {
                    None => Err("crypto read failed: unseal".into()),
                    Some(nonce) => Ok(ct.to_plaintext(&nonce, &key)?),
                }
            }
            _ => Err("crypto read failed: unseal".into()),
        }
    }
}

pub struct FixedKey {
    pubkey: sealed::desc::PublicKey,
    seckey: Option<sealed::desc::SecretKey>,
}

impl FixedKey {
    pub fn new(pubkey: sealed::desc::PublicKey,
               seckey_opt: Option<sealed::desc::SecretKey>)
               -> FixedKey {
        FixedKey {
            pubkey: pubkey,
            seckey: seckey_opt,
        }
    }

    pub fn light_seal(&self, pt: PlainTextRef) -> CipherText {
        pt.to_sealed_ciphertext(&self.pubkey)
    }

    pub fn seal(&self, pt: PlainTextRef) -> CipherText {
        let mut ct = self.light_seal(pt.as_ref());

        // Add ciphertext length as LittleEndian.
        let foot_pt = PlainText::from_i64(ct.len() as i64);
        assert_eq!(foot_pt.len(), sealed::desc::footer_plain_bytes());

        // Append sealed ciphertext length to full ciphertext.
        ct.append(self.light_seal(foot_pt.as_ref()));
        assert_eq!(ct.len(), pt.len() + sealed::desc::overhead());

        // Return complete ciphertext.
        ct
    }

    pub fn light_unseal<'a>(&self, ct: CipherTextRef<'a>) -> Result<PlainText, CryptoError> {
        let seckey = self.seckey.as_ref().expect("unseal requires access to read-key");
        Ok(ct.to_sealed_plaintext(&self.pubkey, &seckey)?)
    }

    pub fn unseal<'a>(&self,
                      ct: CipherTextRef<'a>)
                      -> Result<(CipherTextRef<'a>, PlainText), CryptoError> {
        // Read sealed ciphertext length and unseal it.
        let (rest, foot_ct) = ct.split_from_right(sealed::desc::footer_cipher_bytes())?;
        let foot_pt = self.light_unseal(foot_ct)?;
        assert_eq!(foot_pt.len(), sealed::desc::footer_plain_bytes());

        // Parse back from encoded LittleEndian.
        let ct_len = foot_pt.as_ref()
            .read_i64()
            .map_err(|_| "crypto read failed: unseal")?;

        // Read and unseal original ciphertext.
        let (rest, ct) = rest.split_from_right(ct_len as usize)?;
        Ok((rest, self.light_unseal(ct)?))
    }
}
<commit_msg>Only apply seal operation once per blob.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

use blob::{ChunkRef, Key};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use errors::CryptoError;
use hash::Hash;
use hash::tree::HashRef;
use sodiumoxide::crypto::stream;
use std::io;

pub struct PlainText(Vec<u8>);
pub struct PlainTextRef<'a>(&'a [u8]);

pub struct CipherText {
    chunks: Vec<Vec<u8>>,
    len: usize,
}
pub struct CipherTextRef<'a>(&'a [u8]);

pub mod authed {
    pub mod desc {
        pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{KEYBYTES, Key, MACBYTES,
                                                                   NONCEBYTES, Nonce};
    }

    pub mod imp {
        pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{gen_key, gen_nonce, open, seal};
    }
}

pub mod sealed {
    pub mod desc {
        pub use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::{MACBYTES, PUBLICKEYBYTES,
                                                                        PublicKey, SECRETKEYBYTES,
                                                                        SecretKey};

        pub const SEALBYTES: usize = PUBLICKEYBYTES + MACBYTES;

        pub fn footer_plain_bytes() -> usize {
            // Footer encodes message length in LittleEndian i64 + a symmetric inner key.
            8 + ::crypto::authed::desc::KEYBYTES
        }

        pub fn footer_cipher_bytes() -> usize {
            // Footer plaintext + seal.
            footer_plain_bytes() + SEALBYTES
        }

        pub fn overhead() -> usize {
            // plaintext MAC + random inner nonce + the footer.
            ::crypto::authed::desc::MACBYTES + ::crypto::authed::desc::NONCEBYTES +
            footer_cipher_bytes()
        }
    }

    pub mod imp {
        pub use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::gen_keypair;
        pub use sodiumoxide::crypto::sealedbox::curve25519blake2bxsalsa20poly1305::{open, seal};
    }
}

fn wrap_key(key: authed::desc::Key) -> Key {
    Key::XSalsa20Poly1305(key)
}

impl<'a> PlainTextRef<'a> {
    pub fn new(bytes: &[u8]) -> PlainTextRef {
        PlainTextRef(bytes)
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn read_i64(&self) -> Result<i64, io::Error> {
        return (&self.0[..]).read_i64::<LittleEndian>();
    }
    pub fn slice(&self, from: usize, to: usize) -> PlainTextRef<'a> {
        PlainTextRef(&self.0[from..to])
    }
    pub fn split_from_right(&self,
                            len: usize)
                            -> Result<(PlainTextRef<'a>, PlainTextRef<'a>), CryptoError> {
        if self.len() < len {
            Err("crypto read failed: split_from_right".into())
        } else {
            Ok((self.slice(0, self.len() - len), self.slice(self.len() - len, self.len())))
        }
    }
    pub fn to_ciphertext(&self,
                         nonce: &authed::desc::Nonce,
                         key: &authed::desc::Key)
                         -> CipherText {
        CipherText::new(authed::imp::seal(self.0, nonce, key))
    }
    pub fn to_sealed_ciphertext(&self, pubkey: &sealed::desc::PublicKey) -> CipherText {
        CipherText::new(sealed::imp::seal(self.0, pubkey))
    }
}

impl PlainText {
    pub fn new(bytes: Vec<u8>) -> PlainText {
        PlainText(bytes)
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn as_ref(&self) -> PlainTextRef {
        PlainTextRef::new(&self.0[..])
    }
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }
    pub fn into_vec(self) -> Vec<u8> {
        self.0
    }
    pub fn from_i64(n: i64) -> Self {
        let mut buf = PlainText::new(Vec::with_capacity(8));
        buf.0.write_i64::<LittleEndian>(n).unwrap();
        return buf;
    }
}

impl CipherText {
    pub fn empty() -> CipherText {
        CipherText {
            chunks: vec![],
            len: 0,
        }
    }
    pub fn new(ct: Vec<u8>) -> CipherText {
        let len = ct.len();
        CipherText {
            chunks: vec![ct],
            len: len,
        }
    }
    pub fn append(&mut self, mut other: CipherText) {
        self.len += other.len();
        self.chunks.append(&mut other.chunks);
    }
    pub fn len(&self) -> usize {
        self.len
    }
    pub fn random_pad_upto(&mut self, final_len: usize) {
        let len = self.len;
        if final_len > len {
            self.append(CipherText::random_pad(final_len - len));
        }
    }
    pub fn random_pad(size: usize) -> CipherText {
        let key = stream::salsa20::gen_key();
        let nonce = stream::salsa20::gen_nonce();
        CipherText::new(stream::salsa20::stream(size, &nonce, &key))
    }
    pub fn to_vec(&self) -> Vec<u8> {
        let mut out = vec![];
        for c in &self.chunks {
            out.extend_from_slice(&c[..]);
        }
        out
    }

    pub fn slices(&self) -> Vec<&[u8]> {
        self.chunks.iter().map(|x| &x[..]).collect()
    }
}

impl<'a> CipherTextRef<'a> {
    pub fn new(bytes: &'a [u8]) -> CipherTextRef<'a> {
        CipherTextRef(bytes)
    }
    pub fn slice(&self, from: usize, to: usize) -> CipherTextRef<'a> {
        CipherTextRef(&self.0[from..to])
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn split_from_right(&self,
                            len: usize)
                            -> Result<(CipherTextRef<'a>, CipherTextRef<'a>), CryptoError> {
        if self.len() < len {
            Err("crypto read failed: split_from_right".into())
        } else {
            Ok((self.slice(0, self.len() - len), self.slice(self.len() - len, self.len())))
        }
    }
    pub fn to_plaintext(&self,
                        nonce: &authed::desc::Nonce,
                        key: &authed::desc::Key)
                        -> Result<PlainText, CryptoError> {
        Ok(PlainText::new(try!(authed::imp::open(&self.0, &nonce, &key)
           .map_err(|()| "crypto read failed: to_plaintext"))))
    }
    pub fn to_sealed_plaintext(&self,
                               pubkey: &sealed::desc::PublicKey,
                               seckey: &sealed::desc::SecretKey)
                               -> Result<PlainText, CryptoError> {
        Ok(PlainText::new(try!(sealed::imp::open(&self.0, &pubkey, &seckey)
            .map_err(|()| "crypto read failed: to_sealed_plaintext"))))
    }
}

pub struct RefKey {}

impl RefKey {
    pub fn seal(href: &mut HashRef, pt: PlainTextRef) -> CipherText {
        let key = authed::imp::gen_key();
        href.persistent_ref.key = Some(wrap_key(key.clone()));

        let nonce = authed::desc::Nonce::from_slice(&href.hash.bytes[..authed::desc::NONCEBYTES])
            .unwrap();
        let ct = pt.to_ciphertext(&nonce, &key);
        href.persistent_ref.length = ct.len();

        ct
    }

    pub fn unseal(hash: &Hash,
                  cref: &ChunkRef,
                  ct: CipherTextRef)
                  -> Result<PlainText, CryptoError> {
        assert!(ct.len() > cref.offset + cref.length);
        let ct = ct.slice(cref.offset, cref.offset + cref.length);
        match cref.key {
            Some(Key::XSalsa20Poly1305(ref key)) if hash.bytes.len() >=
                                                    authed::desc::NONCEBYTES => {
                match authed::desc::Nonce::from_slice(&hash.bytes[..authed::desc::NONCEBYTES]) {
                    None => Err("crypto read failed: unseal".into()),
                    Some(nonce) => Ok(ct.to_plaintext(&nonce, &key)?),
                }
            }
            _ => Err("crypto read failed: unseal".into()),
        }
    }
}

pub struct FixedKey {
    pubkey: sealed::desc::PublicKey,
    seckey: Option<sealed::desc::SecretKey>,
}

impl FixedKey {
    pub fn new(pubkey: sealed::desc::PublicKey,
               seckey_opt: Option<sealed::desc::SecretKey>)
               -> FixedKey {
        FixedKey {
            pubkey: pubkey,
            seckey: seckey_opt,
        }
    }

    pub fn light_seal(&self, pt: PlainTextRef) -> CipherText {
        pt.to_sealed_ciphertext(&self.pubkey)
    }

    pub fn seal(&self, pt: PlainTextRef) -> CipherText {
        // Generate inner symmetric key.
        let inner_key = ::crypto::authed::imp::gen_key();
        let nonce = ::crypto::authed::imp::gen_nonce();

        // Encrypt plaintext with inner key.
        let mut ct = pt.to_ciphertext(&nonce, &inner_key);
        ct.append(CipherText::new(nonce.0.to_vec()));

        // Construct footer of length as LittleEndian and inner key.
        let mut foot_pt = PlainText::from_i64(ct.len() as i64);
        foot_pt.0.extend_from_slice(&inner_key.0);
        assert_eq!(foot_pt.len(), sealed::desc::footer_plain_bytes());

        // Seal footer.
        let foot_ct = self.light_seal(foot_pt.as_ref());
        assert_eq!(foot_ct.len(), sealed::desc::footer_cipher_bytes());

        // Append sealed footer to symmetric cipher text.
        ct.append(foot_ct);
        assert_eq!(ct.len(), pt.len() + sealed::desc::overhead());
        ct
    }

    pub fn light_unseal<'a>(&self, ct: CipherTextRef<'a>) -> Result<PlainText, CryptoError> {
        let seckey = self.seckey.as_ref().expect("unseal requires access to read-key");
        Ok(ct.to_sealed_plaintext(&self.pubkey, &seckey)?)
    }

    pub fn unseal<'a>(&self,
                      ct: CipherTextRef<'a>)
                      -> Result<(CipherTextRef<'a>, PlainText), CryptoError> {
        // Read sealed ciphertext length and unseal it.
        let (rest, foot_ct) = ct.split_from_right(sealed::desc::footer_cipher_bytes())?;
        let foot_pt = self.light_unseal(foot_ct)?;
        assert_eq!(foot_pt.len(), sealed::desc::footer_plain_bytes());

        // Read length as LittleEndian and inner key.
        let (foot_len, inner_key) = foot_pt.as_ref()
            .split_from_right(::crypto::authed::desc::KEYBYTES)?;

        // Parse length of inner symmetric cipher text.
        let ct_len = foot_len.read_i64()
            .map_err(|_| "crypto read failed: unseal")?;
        assert!(ct_len > 0);

        // Read and unseal inner symmetric cipher text.
        let (rest, ct_and_nonce) = rest.split_from_right(ct_len as usize)?;
        let (ct, nonce) = ct_and_nonce.split_from_right(::crypto::authed::desc::NONCEBYTES)?;
        Ok((rest,
            ct.to_plaintext(&::crypto::authed::desc::Nonce::from_slice(nonce.0).unwrap(),
                              &::crypto::authed::desc::Key::from_slice(inner_key.0).unwrap())?))
    }
}
<|endoftext|>


<commit_before>use self::super::super::{http, Status};
use self::super::MAP;
use base64::{decode, encode};
use serde_json;
use std::slice;

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct Response {
    dad: u8,
    sad: u8,
    lenr: u16,
    response: String,
    #[serde(rename = "responseCode")]
    status: i8,
}

pub fn data(
    ctn: u16,
    dad: *mut u8,
    sad: *mut u8,
    lenc: u16,
    command: *const u8,
    lenr: *mut u16,
    response: *mut u8,
) -> Status {
    if !MAP.lock().contains_key(&ctn) {
        error!("Card terminal has not been opened.");
        return Status::ErrInvalid;
    }

    let safe_dad: &mut u8 = unsafe { &mut *dad };
    debug!("dad: {}", safe_dad);

    let safe_sad: &mut u8 = unsafe { &mut *sad };
    debug!("sad: {}", safe_sad);
    debug!("lenc: {}", lenc);

    let safe_command = unsafe { slice::from_raw_parts(command, lenc as usize) };
    debug!("command: {:?}", safe_command);

    let safe_lenr: &mut u16 = unsafe { &mut *lenr };
    debug!("lenr: {}", safe_lenr);

    let safe_response = unsafe { slice::from_raw_parts_mut(response, *safe_lenr as usize) };
    debug!("response with {} slices formed", safe_response.len());

    let json = format!(
        "{{\"dad\":{},\"sad\":{},\"lenc\":{},\"command\":\"{}\",\"lenr\":{}}}",
        *safe_dad,
        *safe_sad,
        lenc,
        encode(safe_command),
        *safe_lenr
    );

    let pn = match MAP.lock().get(&ctn) {
        Some(pn) => pn.clone(),
        None => {
            error!("Failed to extract pn for given ctn!");
            return Status::ErrHtsi;
        }
    };

    let path = format!("ct_data/{}/{}", ctn, pn);

    let response = http::request(&path, Some(json));
    let res = match response {
        Ok(response) => response,
        Err(why) => {
            error!("Request failed!");
            debug!("{}", why);
            return Status::ErrHtsi;
        }
    };

    if res.status != 200 {
        error!("Request failed! Server response was not OK!");
        return Status::ErrHtsi;
    }

    let json: Response = match serde_json::from_str(&res.body) {
        Ok(json) => json,
        Err(why) => {
            error!("Failed to parse server response data!");
            debug!("{}", why);
            return Status::ErrHtsi;
        }
    };

    let status: Status = json.status.into();
    match status {
        Status::OK => {
            *safe_dad = json.dad;
            *safe_sad = json.sad;
            *safe_lenr = json.lenr;

            let decoded = match decode(&json.response) {
                Ok(content) => {
                    debug!("Decoded response field {:?}", content);
                    content
                }
                Err(why) => {
                    error!("Failed to extract response.");
                    debug!("{}", why);
                    return Status::ErrHtsi;
                }
            };

            for (place, element) in safe_response.iter_mut().zip(decoded.iter()) {
                *place = *element;
            }

            status
        }
        _ => status,
    }
}

#[cfg(test)]
mod tests {

    use super::super::MAP;
    use super::data;
    use base64::encode;
    use rand;
    use serde_json;
    use std::env;
    use std::slice;
    use std::str;
    use std::u16::MAX;
    use test_server::actix_web::HttpResponse;
    use test_server::TestServer;

    fn rand_params() -> (*const u8, u16, *mut u8, u16, u8, u8, u16, u16) {
        let commands: [u8; 1] = [rand::random::<u8>(); 1];
        let commands_ptr: *const u8 = &commands[0];
        let lenc: u16 = commands.len() as u16;

        let mut response: [u8; MAX as usize] = [rand::random::<u8>(); MAX as usize];
        let response_ptr: *mut u8 = &mut response[0];
        let lenr: u16 = response.len() as u16;

        let dad = rand::random::<u8>();
        let sad = rand::random::<u8>();

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        (commands_ptr, lenc, response_ptr, lenr, dad, sad, ctn, pn)
    }

    #[test]
    fn returns_err_invalid_if_terminal_closed() {
        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, _pn) =
            rand_params();

        assert_eq!(
            -1,
            data(
                ctn,
                &mut dad,
                &mut sad,
                lenc,
                commands_ptr,
                &mut lenr,
                response_ptr,
            )
        )
    }

    #[test]
    fn returns_err_htsi_if_no_server() {
        env::set_var("K2_BASE_URL", "http://127.0.0.1:65432");

        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();

        MAP.lock().insert(ctn, pn);

        assert_eq!(
            -128,
            data(
                ctn,
                &mut dad,
                &mut sad,
                lenc,
                commands_ptr,
                &mut lenr,
                response_ptr,
            )
        )
    }

    #[test]
    fn use_ctn_and_pn_in_request_path() {
        let server = TestServer::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());

        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        MAP.lock().insert(ctn, pn);

        data(
            ctn,
            &mut dad,
            &mut sad,
            lenc,
            commands_ptr,
            &mut lenr,
            response_ptr,
        );

        let path = server.received_request().unwrap().path;
        assert_eq!(path, *format!("/ct_data/{}/{}", ctn, pn));
    }

    #[test]
    #[ignore]
    fn post_body_contains_parameter() {
        let server = TestServer::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());

        let (command, lenc, response, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        let exp_cmd = unsafe { encode(slice::from_raw_parts(command, lenc as usize)) };

        MAP.lock().insert(ctn, pn);

        assert_eq!(
            -128,
            data(ctn, &mut dad, &mut sad, lenc, command, &mut lenr, response)
        );

        #[derive(Deserialize, Debug)]
        struct Json {
            dad: u8,
            sad: u8,
            lenc: u16,
            command: String,
            lenr: u16,
        }

        let body = server.received_request().unwrap().body;
        let json: Json = serde_json::from_str(&body).unwrap();

        assert_eq!(dad, json.dad);
        assert_eq!(sad, json.sad);
        assert_eq!(exp_cmd, json.command);
        assert_eq!(lenc, json.lenc);
        assert_eq!(lenr, json.lenr);
    }

    #[test]
    fn response_is_mapped_to_parameter() {
        let server = TestServer::new(0, |_| {
            HttpResponse::Ok().body(
                "{\"dad\":39,\"sad\":63,\"lenr\":5,\"response\":\"AQIDBAU=\",\"responseCode\":0}",
            )
        });
        env::set_var("K2_BASE_URL", server.url());

        let (command, lenc, response, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        MAP.lock().insert(ctn, pn);

        data(ctn, &mut dad, &mut sad, lenc, command, &mut lenr, response);

        assert_eq!(dad, 39);
        assert_eq!(sad, 63);
        assert_eq!(5, lenr);

        let slice = unsafe { slice::from_raw_parts(response, lenr as usize) };
        assert_eq!([1, 2, 3, 4, 5], slice);
    }

    #[test]
    fn returns_err_htsi_if_server_response_is_not_200() {
        let server = TestServer::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());

        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        MAP.lock().insert(ctn, pn);

        assert_eq!(
            -128,
            data(
                ctn,
                &mut dad,
                &mut sad,
                lenc,
                commands_ptr,
                &mut lenr,
                response_ptr,
            )
        );
    }

    #[test]
    fn returns_err_htsi_if_server_response_not_contains_response_struct_as_json() {
        let server = TestServer::new(0, |_| HttpResponse::Ok().body("hello world"));
        env::set_var("K2_BASE_URL", server.url());

        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        MAP.lock().insert(ctn, pn);

        assert_eq!(
            -128,
            data(
                ctn,
                &mut dad,
                &mut sad,
                lenc,
                commands_ptr,
                &mut lenr,
                response_ptr,
            )
        );
    }

    #[test]
    fn returns_response_status_from_valid_json_response_struct() {
        let server = TestServer::new(0, |_| {
            HttpResponse::Ok()
                .body("{\"dad\":1,\"sad\":1,\"lenr\":1,\"response\":\"a\",\"responseCode\":-11}")
        });
        env::set_var("K2_BASE_URL", server.url());

        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        MAP.lock().insert(ctn, pn);

        assert_eq!(
            -11,
            data(
                ctn,
                &mut dad,
                &mut sad,
                lenc,
                commands_ptr,
                &mut lenr,
                response_ptr,
            )
        );
    }
}
<commit_msg>adjust json response<commit_after>use self::super::super::{http, Status};
use self::super::MAP;
use base64::{decode, encode};
use serde_json;
use std::slice;

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct Response {
    dad: u8,
    sad: u8,
    lenr: u16,
    response: String,
    #[serde(rename = "responseCode")]
    status: i8,
}

pub fn data(
    ctn: u16,
    dad: *mut u8,
    sad: *mut u8,
    lenc: u16,
    command: *const u8,
    lenr: *mut u16,
    response: *mut u8,
) -> Status {
    if !MAP.lock().contains_key(&ctn) {
        error!("Card terminal has not been opened.");
        return Status::ErrInvalid;
    }

    let safe_dad: &mut u8 = unsafe { &mut *dad };
    debug!("dad: {}", safe_dad);

    let safe_sad: &mut u8 = unsafe { &mut *sad };
    debug!("sad: {}", safe_sad);
    debug!("lenc: {}", lenc);

    let safe_command = unsafe { slice::from_raw_parts(command, lenc as usize) };
    debug!("command: {:?}", safe_command);

    let safe_lenr: &mut u16 = unsafe { &mut *lenr };
    debug!("lenr: {}", safe_lenr);

    let safe_response = unsafe { slice::from_raw_parts_mut(response, *safe_lenr as usize) };
    debug!("response with {} slices formed", safe_response.len());

    let json = format!(
        "{{\"dad\":{},\"sad\":{},\"lenc\":{},\"command\":\"{}\",\"lenr\":{}}}",
        *safe_dad,
        *safe_sad,
        lenc,
        encode(safe_command),
        *safe_lenr
    );

    let pn = match MAP.lock().get(&ctn) {
        Some(pn) => pn.clone(),
        None => {
            error!("Failed to extract pn for given ctn!");
            return Status::ErrHtsi;
        }
    };

    let path = format!("ct_data/{}/{}", ctn, pn);

    let response = http::request(&path, Some(json));
    let res = match response {
        Ok(response) => response,
        Err(why) => {
            error!("Request failed!");
            debug!("{}", why);
            return Status::ErrHtsi;
        }
    };

    if res.status != 200 {
        error!("Request failed! Server response was not OK!");
        return Status::ErrHtsi;
    }

    let json: Response = match serde_json::from_str(&res.body) {
        Ok(json) => json,
        Err(why) => {
            error!("Failed to parse server response data!");
            debug!("{}", why);
            return Status::ErrHtsi;
        }
    };

    let status: Status = json.status.into();
    match status {
        Status::OK => {
            *safe_dad = json.dad;
            *safe_sad = json.sad;
            *safe_lenr = json.lenr;

            let decoded = match decode(&json.response) {
                Ok(content) => {
                    debug!("Decoded response field {:?}", content);
                    content
                }
                Err(why) => {
                    error!("Failed to extract response.");
                    debug!("{}", why);
                    return Status::ErrHtsi;
                }
            };

            for (place, element) in safe_response.iter_mut().zip(decoded.iter()) {
                *place = *element;
            }

            status
        }
        _ => status,
    }
}

#[cfg(test)]
mod tests {

    use super::super::MAP;
    use super::data;
    use base64::encode;
    use rand;
    use serde_json;
    use std::env;
    use std::slice;
    use std::str;
    use std::u16::MAX;
    use test_server::actix_web::HttpResponse;
    use test_server::TestServer;

    fn rand_params() -> (*const u8, u16, *mut u8, u16, u8, u8, u16, u16) {
        let commands: [u8; 1] = [rand::random::<u8>(); 1];
        let commands_ptr: *const u8 = &commands[0];
        let lenc: u16 = commands.len() as u16;

        let mut response: [u8; MAX as usize] = [rand::random::<u8>(); MAX as usize];
        let response_ptr: *mut u8 = &mut response[0];
        let lenr: u16 = response.len() as u16;

        let dad = rand::random::<u8>();
        let sad = rand::random::<u8>();

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        (commands_ptr, lenc, response_ptr, lenr, dad, sad, ctn, pn)
    }

    #[test]
    fn returns_err_invalid_if_terminal_closed() {
        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, _pn) =
            rand_params();

        assert_eq!(
            -1,
            data(
                ctn,
                &mut dad,
                &mut sad,
                lenc,
                commands_ptr,
                &mut lenr,
                response_ptr,
            )
        )
    }

    #[test]
    fn returns_err_htsi_if_no_server() {
        env::set_var("K2_BASE_URL", "http://127.0.0.1:65432");

        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();

        MAP.lock().insert(ctn, pn);

        assert_eq!(
            -128,
            data(
                ctn,
                &mut dad,
                &mut sad,
                lenc,
                commands_ptr,
                &mut lenr,
                response_ptr,
            )
        )
    }

    #[test]
    fn use_ctn_and_pn_in_request_path() {
        let server = TestServer::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());

        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        MAP.lock().insert(ctn, pn);

        data(
            ctn,
            &mut dad,
            &mut sad,
            lenc,
            commands_ptr,
            &mut lenr,
            response_ptr,
        );

        let path = server.received_request().unwrap().path;
        assert_eq!(path, *format!("/ct_data/{}/{}", ctn, pn));
    }

    #[test]
    #[ignore]
    fn post_body_contains_parameter() {
        let server = TestServer::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());

        let (command, lenc, response, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        let exp_cmd = unsafe { encode(slice::from_raw_parts(command, lenc as usize)) };

        MAP.lock().insert(ctn, pn);

        assert_eq!(
            -128,
            data(ctn, &mut dad, &mut sad, lenc, command, &mut lenr, response)
        );

        #[derive(Deserialize, Debug)]
        struct Json {
            dad: u8,
            sad: u8,
            lenc: u16,
            command: String,
            lenr: u16,
        }

        let body = server.received_request().unwrap().body;
        let json: Json = serde_json::from_str(&body).unwrap();

        assert_eq!(dad, json.dad);
        assert_eq!(sad, json.sad);
        assert_eq!(exp_cmd, json.command);
        assert_eq!(lenc, json.lenc);
        assert_eq!(lenr, json.lenr);
    }

    #[test]
    fn response_is_mapped_to_parameter() {
        let server = TestServer::new(0, |_| {
            HttpResponse::Ok()
                .body(r#"{"dad":39,"sad":63,"lenr":5,"response":"AQIDBAU=","responseCode":0}"#)
        });
        env::set_var("K2_BASE_URL", server.url());

        let (command, lenc, response, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        MAP.lock().insert(ctn, pn);

        data(ctn, &mut dad, &mut sad, lenc, command, &mut lenr, response);

        assert_eq!(dad, 39);
        assert_eq!(sad, 63);
        assert_eq!(5, lenr);

        let slice = unsafe { slice::from_raw_parts(response, lenr as usize) };
        assert_eq!([1, 2, 3, 4, 5], slice);
    }

    #[test]
    fn returns_err_htsi_if_server_response_is_not_200() {
        let server = TestServer::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());

        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        MAP.lock().insert(ctn, pn);

        assert_eq!(
            -128,
            data(
                ctn,
                &mut dad,
                &mut sad,
                lenc,
                commands_ptr,
                &mut lenr,
                response_ptr,
            )
        );
    }

    #[test]
    fn returns_err_htsi_if_server_response_not_contains_response_struct_as_json() {
        let server = TestServer::new(0, |_| HttpResponse::Ok().body("hello world"));
        env::set_var("K2_BASE_URL", server.url());

        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        MAP.lock().insert(ctn, pn);

        assert_eq!(
            -128,
            data(
                ctn,
                &mut dad,
                &mut sad,
                lenc,
                commands_ptr,
                &mut lenr,
                response_ptr,
            )
        );
    }

    #[test]
    fn returns_response_status_from_valid_json_response_struct() {
        let server = TestServer::new(0, |_| {
            HttpResponse::Ok()
                .body(r#"{"dad":1,"sad":1,"lenr":1,"response":"a=","responseCode":-11}"#)
        });
        env::set_var("K2_BASE_URL", server.url());

        let (commands_ptr, lenc, response_ptr, mut lenr, mut dad, mut sad, ctn, pn) = rand_params();
        MAP.lock().insert(ctn, pn);

        assert_eq!(
            -11,
            data(
                ctn,
                &mut dad,
                &mut sad,
                lenc,
                commands_ptr,
                &mut lenr,
                response_ptr,
            )
        );
    }
}
<|endoftext|>


<commit_before>pub type Palindrome = u64;
pub fn get_palindrome_products(min: u64, max: u64) -> Vec<Palindrome> {
    let mut palindromes: Vec<u64> = Vec::new();
    for i in min..=max {
        for j in min..=max {
            if is_palindrome(i * j) {
                palindromes.push(i * j);
            }
        }
    }
    palindromes
}

pub fn min(palindromes: &[Palindrome]) -> Option<Palindrome> {
    palindromes.iter().min().cloned()
}

pub fn max(palindromes: &[Palindrome]) -> Option<Palindrome> {
    palindromes.iter().max().cloned()
}

fn is_palindrome(n: u64) -> bool {
    let s = n.to_string().into_bytes();
    s.iter().zip(s.iter().rev()).all(|(c1, c2)| c1 == c2)
}
<commit_msg>update example<commit_after>pub type Palindrome = u64;

pub fn palindrome_products(min: u64, max: u64) -> Option<(Palindrome, Palindrome)> {
    let mut palindromes: Vec<u64> = Vec::new();
    for i in min..=max {
        for j in min..=max {
            if is_palindrome(i * j) {
                palindromes.push(i * j);
            }
        }
    }

    palindromes.iter().cloned().fold(None, |prev, pal| match prev {
        None => Some((pal, pal)),
        Some((pmin, pmax)) => Some((if pal < pmin {pal} else {pmin}, if pal > pmax {pal} else {pmax})),
    })
}

fn is_palindrome(n: u64) -> bool {
    let s = n.to_string().into_bytes();
    s.iter().zip(s.iter().rev()).all(|(c1, c2)| c1 == c2)
}
<|endoftext|>