mirror of
https://github.com/chatmail/core.git
synced 2026-05-07 08:56:30 +03:00
Add API for passphrase-protected accounts
To create encrypted account with account manager, call dc_accounts_add_closed_account(). Open this account with dc_context_open() using the passphrase you want to use for encryption. When application is loaded next time and account manager is created, it will open all accounts that have no passphrase set. For encrypted accounts dc_context_is_open() will return 0. To open them, call dc_context_open() with the correct passphrase. After opening, call dc_context_start_io() on this account or just dc_accounts_start_io() to start all accounts that are not started yet. Support for legacy SQLite-based backup format is removed in this commit.
This commit is contained in:
@@ -179,24 +179,66 @@ typedef struct _dc_accounts_event_emitter dc_accounts_event_emitter_t;
|
||||
// create/open/config/information
|
||||
|
||||
/**
|
||||
* Create a new context object. After creation it is usually
|
||||
* opened, connected and mails are fetched.
|
||||
* Create a new context object and try to open it without passphrase. If
|
||||
* database is encrypted, the result is the same as using
|
||||
* dc_context_new_closed() and the database should be opened with
|
||||
* dc_context_open() before using.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param os_name is only for decorative use.
|
||||
* You can give the name of the app, the operating system,
|
||||
* the used environment and/or the version here.
|
||||
* @param os_name Deprecated, pass NULL or empty string here.
|
||||
* @param dbfile The file to use to store the database,
|
||||
* something like `~/file` won't work, use absolute paths.
|
||||
* @param blobdir Deprecated, pass NULL or an empty string here.
|
||||
* @return A context object with some public members.
|
||||
* The object must be passed to the other context functions
|
||||
* and must be freed using dc_context_unref() after usage.
|
||||
*/
|
||||
dc_context_t* dc_context_new (const char* os_name, const char* dbfile, const char* blobdir);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new context object. After creation it is usually opened with
|
||||
* dc_context_open() and started with dc_start_io() so it is connected and
|
||||
* mails are fetched.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param dbfile The file to use to store the database,
|
||||
* something like `~/file` won't work, use absolute paths.
|
||||
* @return A context object with some public members.
|
||||
* The object must be passed to the other context functions
|
||||
* and must be freed using dc_context_unref() after usage.
|
||||
*
|
||||
* If you want to use multiple context objects at the same time,
|
||||
* this can be managed using dc_accounts_t.
|
||||
*/
|
||||
dc_context_t* dc_context_new (const char* os_name, const char* dbfile, const char* blobdir);
|
||||
dc_context_t* dc_context_new_closed (const char* dbfile);
|
||||
|
||||
|
||||
/**
|
||||
* Opens the database with the given passphrase. This can only be used on
|
||||
* closed context, such as created by dc_context_new_closed(). If the database
|
||||
* is new, this operation sets the database passphrase. For existing databases
|
||||
* the passphrase should be the one used to encrypt the database the first
|
||||
* time.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object.
|
||||
* @param passphrase The passphrase to use with the database. Pass NULL or
|
||||
* empty string to use no passphrase and no encryption.
|
||||
* @return 1 if the database is opened with this passphrase, 0 if the
|
||||
* passphrase is incorrect and on error.
|
||||
*/
|
||||
int dc_context_open (dc_context_t *context, const char* passphrase);
|
||||
|
||||
|
||||
/**
|
||||
* Returns 1 if database is open.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object.
|
||||
* @return 1 if database is open, 0 if database is closed
|
||||
*/
|
||||
int dc_context_is_open (dc_context_t *context);
|
||||
|
||||
|
||||
/**
|
||||
@@ -2470,6 +2512,7 @@ void dc_str_unref (char* str);
|
||||
* To make this possible, some dc_context_t functions must not be called
|
||||
* when using the account manager:
|
||||
* - use dc_accounts_add_account() and dc_accounts_get_account() instead of dc_context_new()
|
||||
* - use dc_accounts_add_closed_account() instead of dc_context_new_closed()
|
||||
* - use dc_accounts_start_io() and dc_accounts_stop_io() instead of dc_start_io() and dc_stop_io()
|
||||
* - use dc_accounts_maybe_network() instead of dc_maybe_network()
|
||||
* - use dc_accounts_get_event_emitter() instead of dc_get_event_emitter()
|
||||
@@ -2527,6 +2570,22 @@ void dc_accounts_unref (dc_accounts_t* accounts);
|
||||
*/
|
||||
uint32_t dc_accounts_add_account (dc_accounts_t* accounts);
|
||||
|
||||
/**
|
||||
* Add a new closed account to the account manager.
|
||||
* Internally, dc_context_new_closed() is called using a unique database-name
|
||||
* in the directory specified at dc_accounts_new().
|
||||
*
|
||||
* If the function succeeds,
|
||||
* dc_accounts_get_all() will return one more account
|
||||
* and you can access the newly created account using dc_accounts_get_account().
|
||||
* Moreover, the newly created account will be the selected one.
|
||||
*
|
||||
* @memberof dc_accounts_t
|
||||
* @param accounts Account manager as created by dc_accounts_new().
|
||||
* @return Account-id, use dc_accounts_get_account() to get the context object.
|
||||
* On errors, 0 is returned.
|
||||
*/
|
||||
uint32_t dc_accounts_add_closed_account (dc_accounts_t* accounts);
|
||||
|
||||
/**
|
||||
* Migrate independent accounts into accounts managed by the account manager.
|
||||
|
||||
@@ -27,6 +27,7 @@ use async_std::sync::RwLock;
|
||||
use async_std::task::{block_on, spawn};
|
||||
use deltachat::qr_code_generator::get_securejoin_qr_svg;
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use rand::Rng;
|
||||
|
||||
use deltachat::chat::{ChatId, ChatVisibility, MuteDuration, ProtectionStatus};
|
||||
use deltachat::constants::DC_MSG_ID_LAST_SPECIAL;
|
||||
@@ -75,7 +76,6 @@ pub unsafe extern "C" fn dc_context_new(
|
||||
}
|
||||
|
||||
let ctx = if blobdir.is_null() || *blobdir == 0 {
|
||||
use rand::Rng;
|
||||
// generate random ID as this functionality is not yet available on the C-api.
|
||||
let id = rand::thread_rng().gen();
|
||||
block_on(Context::new(as_path(dbfile).to_path_buf().into(), id))
|
||||
@@ -86,12 +86,63 @@ pub unsafe extern "C" fn dc_context_new(
|
||||
match ctx {
|
||||
Ok(ctx) => Box::into_raw(Box::new(ctx)),
|
||||
Err(err) => {
|
||||
eprintln!("failed to create context: {}", err);
|
||||
eprintln!("failed to create context: {:#}", err);
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_context_new_closed(dbfile: *const libc::c_char) -> *mut dc_context_t {
|
||||
setup_panic!();
|
||||
|
||||
if dbfile.is_null() {
|
||||
eprintln!("ignoring careless call to dc_context_new_closed()");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
let id = rand::thread_rng().gen();
|
||||
match block_on(Context::new_closed(
|
||||
as_path(dbfile).to_path_buf().into(),
|
||||
id,
|
||||
)) {
|
||||
Ok(context) => Box::into_raw(Box::new(context)),
|
||||
Err(err) => {
|
||||
eprintln!("failed to create context: {:#}", err);
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_context_open(
|
||||
context: *mut dc_context_t,
|
||||
passphrase: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_context_open()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
let ctx = &*context;
|
||||
let passphrase = to_string_lossy(passphrase);
|
||||
block_on(ctx.open(passphrase))
|
||||
.log_err(ctx, "dc_context_open() failed")
|
||||
.map(|b| b as libc::c_int)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_context_is_open(context: *mut dc_context_t) -> libc::c_int {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_context_is_open()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
let ctx = &*context;
|
||||
block_on(ctx.is_open()) as libc::c_int
|
||||
}
|
||||
|
||||
/// Release the context structure.
|
||||
///
|
||||
/// This function releases the memory of the `dc_context_t` structure.
|
||||
@@ -3965,6 +4016,30 @@ pub unsafe extern "C" fn dc_accounts_add_account(accounts: *mut dc_accounts_t) -
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_accounts_add_closed_account(accounts: *mut dc_accounts_t) -> u32 {
|
||||
if accounts.is_null() {
|
||||
eprintln!("ignoring careless call to dc_accounts_add_closed_account()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
let accounts = &mut *accounts;
|
||||
|
||||
block_on(async move {
|
||||
let mut accounts = accounts.write().await;
|
||||
match accounts.add_closed_account().await {
|
||||
Ok(id) => id,
|
||||
Err(err) => {
|
||||
accounts.emit_event(EventType::Error(format!(
|
||||
"Failed to add account: {:#}",
|
||||
err
|
||||
)));
|
||||
0
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_accounts_remove_account(
|
||||
accounts: *mut dc_accounts_t,
|
||||
|
||||
Reference in New Issue
Block a user