parent
da44f49c56
commit
f8ae7d4e0e
8 changed files with 106 additions and 117 deletions
67
Cargo.lock
generated
67
Cargo.lock
generated
|
@ -10,14 +10,13 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.7.5"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
||||
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -122,21 +121,14 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "block-modes"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.2.1"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
|
||||
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
|
@ -162,6 +154,15 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||
|
||||
[[package]]
|
||||
name = "cbc"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
|
@ -195,11 +196,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.3.0"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -366,6 +368,16 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cssparser"
|
||||
version = "0.27.2"
|
||||
|
@ -842,6 +854,16 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
|
@ -1139,12 +1161,6 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d11de466f4a3006fe8a5e7ec84e93b79c70cb992ae0aa0eb631ad2df8abfe2"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
|
@ -2214,7 +2230,7 @@ dependencies = [
|
|||
"aes",
|
||||
"anyhow",
|
||||
"base64",
|
||||
"block-modes",
|
||||
"cbc",
|
||||
"clap",
|
||||
"clap_complete",
|
||||
"cookie 0.14.4",
|
||||
|
@ -2222,6 +2238,7 @@ dependencies = [
|
|||
"dirs",
|
||||
"gethostname",
|
||||
"hmac-sha1",
|
||||
"inout",
|
||||
"lazy_static 1.4.0",
|
||||
"log",
|
||||
"phonenumber",
|
||||
|
|
|
@ -50,9 +50,8 @@ lazy_static = "1.4.0"
|
|||
uuid = { version = "0.8", features = ["v4"] }
|
||||
steamguard = { version = "^0.9.0", path = "./steamguard" }
|
||||
dirs = "3.0.2"
|
||||
ring = "0.16.20"
|
||||
aes = "0.7.4"
|
||||
block-modes = "0.8.1"
|
||||
ring = { version = "0.16.20", features = ["std"] }
|
||||
aes = "0.8.3"
|
||||
thiserror = "1.0.26"
|
||||
crossterm = { version = "0.23.2", features = ["event-stream"] }
|
||||
qrcode = { version = "0.12.0", optional = true }
|
||||
|
@ -62,6 +61,8 @@ zeroize = "^1.4.3"
|
|||
serde_path_to_error = "0.1.11"
|
||||
update-informer = { version = "1.0.0", optional = true, default-features = false, features = ["github"] }
|
||||
phonenumber = "0.3"
|
||||
cbc = { version = "0.1.2", features = ["std"] }
|
||||
inout = { version = "0.1.3", features = ["std"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
|
|
|
@ -412,21 +412,11 @@ pub enum ManifestAccountLoadError {
|
|||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
impl From<block_modes::BlockModeError> for ManifestAccountLoadError {
|
||||
fn from(error: block_modes::BlockModeError) -> Self {
|
||||
Self::Unknown(anyhow::Error::from(error))
|
||||
}
|
||||
}
|
||||
impl From<base64::DecodeError> for ManifestAccountLoadError {
|
||||
fn from(error: base64::DecodeError) -> Self {
|
||||
Self::Unknown(anyhow::Error::from(error))
|
||||
}
|
||||
}
|
||||
impl From<block_modes::InvalidKeyIvLength> for ManifestAccountLoadError {
|
||||
fn from(error: block_modes::InvalidKeyIvLength) -> Self {
|
||||
Self::Unknown(anyhow::Error::from(error))
|
||||
}
|
||||
}
|
||||
impl From<std::io::Error> for ManifestAccountLoadError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
Self::Unknown(anyhow::Error::from(error))
|
||||
|
@ -639,11 +629,10 @@ mod tests {
|
|||
manifest: "src/fixtures/maFiles/manifest-v1/1-account/manifest.json",
|
||||
passkey: None,
|
||||
},
|
||||
// FIXME: disabled because of #233
|
||||
// Test {
|
||||
// manifest: "src/fixtures/maFiles/manifest-v1/1-account-encrypted/manifest.json",
|
||||
// passkey: Some(SecretString::new("password".into())),
|
||||
// },
|
||||
Test {
|
||||
manifest: "src/fixtures/maFiles/manifest-v1/1-account-encrypted/manifest.json",
|
||||
passkey: Some(SecretString::new("password".into())),
|
||||
},
|
||||
Test {
|
||||
manifest: "src/fixtures/maFiles/manifest-v1/2-account/manifest.json",
|
||||
passkey: None,
|
||||
|
|
|
@ -374,11 +374,10 @@ mod tests {
|
|||
dir: "src/fixtures/maFiles/compat/1-account/",
|
||||
passkey: None,
|
||||
},
|
||||
// FIXME: disabled because of #233
|
||||
// Test {
|
||||
// manifest: "src/fixtures/maFiles/compat/1-account-encrypted/",
|
||||
// passkey: Some(SecretString::new("password".into())),
|
||||
// },
|
||||
Test {
|
||||
dir: "src/fixtures/maFiles/compat/1-account-encrypted/",
|
||||
passkey: Some(SecretString::new("password".into())),
|
||||
},
|
||||
Test {
|
||||
dir: "src/fixtures/maFiles/compat/2-account/",
|
||||
passkey: None,
|
||||
|
@ -402,9 +401,7 @@ mod tests {
|
|||
for file in std::fs::read_dir(case.dir)? {
|
||||
let file = file?;
|
||||
let path = file.path();
|
||||
eprintln!("copying {:?}", path);
|
||||
let dest = temp.path().join(path.file_name().unwrap());
|
||||
eprintln!("to {:?}", dest);
|
||||
std::fs::copy(&path, dest)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use aes::cipher::block_padding::Pkcs7;
|
||||
use aes::cipher::{BlockDecryptMut, BlockEncryptMut, InvalidLength, KeyIvInit};
|
||||
use aes::Aes256;
|
||||
use block_modes::block_padding::{NoPadding, Padding, Pkcs7};
|
||||
use block_modes::{BlockMode, Cbc};
|
||||
use ring::pbkdf2;
|
||||
use ring::rand::SecureRandom;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -78,38 +78,22 @@ impl LegacySdaCompatible {
|
|||
}
|
||||
}
|
||||
|
||||
type Aes256Cbc = Cbc<Aes256, NoPadding>;
|
||||
impl EntryEncryptor for LegacySdaCompatible {
|
||||
// ngl, this logic sucks ass. its kinda annoying that the logic is not completely symetric.
|
||||
|
||||
fn encrypt(
|
||||
passkey: &str,
|
||||
params: &EntryEncryptionParams,
|
||||
plaintext: Vec<u8>,
|
||||
) -> anyhow::Result<Vec<u8>, EntryEncryptionError> {
|
||||
let key = Self::get_encryption_key(passkey, ¶ms.salt)?;
|
||||
let iv = base64::decode(¶ms.iv)?;
|
||||
let cipher = Aes256Cbc::new_from_slices(&key, &iv)?;
|
||||
let mut iv = [0u8; IV_LENGTH];
|
||||
base64::decode_config_slice(¶ms.iv, base64::STANDARD, &mut iv)?;
|
||||
|
||||
let origsize = plaintext.len();
|
||||
let buffersize: usize = (origsize / 16 + (if origsize % 16 == 0 { 0 } else { 1 })) * 16;
|
||||
let mut buffer = vec![];
|
||||
for chunk in plaintext.as_slice().chunks(128) {
|
||||
let chunksize = chunk.len();
|
||||
let buffersize = (chunksize / 16 + (if chunksize % 16 == 0 { 0 } else { 1 })) * 16;
|
||||
let mut chunkbuffer = vec![0xffu8; buffersize];
|
||||
chunkbuffer[..chunksize].copy_from_slice(chunk);
|
||||
if buffersize != chunksize {
|
||||
// pad the last chunk
|
||||
chunkbuffer = Pkcs7::pad(&mut chunkbuffer, chunksize, buffersize)
|
||||
.unwrap()
|
||||
.to_vec();
|
||||
}
|
||||
buffer.append(&mut chunkbuffer);
|
||||
}
|
||||
let ciphertext = cipher.encrypt(&mut buffer, buffersize)?;
|
||||
let final_buffer = base64::encode(ciphertext);
|
||||
return Ok(final_buffer.as_bytes().to_vec());
|
||||
let cipher = cbc::Encryptor::<Aes256>::new_from_slices(&key, &iv)?;
|
||||
|
||||
let ciphertext = cipher.encrypt_padded_vec_mut::<Pkcs7>(&plaintext);
|
||||
|
||||
let encoded = base64::encode(ciphertext);
|
||||
Ok(encoded.as_bytes().to_vec())
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
|
@ -118,46 +102,51 @@ impl EntryEncryptor for LegacySdaCompatible {
|
|||
ciphertext: Vec<u8>,
|
||||
) -> anyhow::Result<Vec<u8>, EntryEncryptionError> {
|
||||
let key = Self::get_encryption_key(passkey, ¶ms.salt)?;
|
||||
let iv = base64::decode(¶ms.iv)?;
|
||||
let cipher = Aes256Cbc::new_from_slices(&key, &iv)?;
|
||||
|
||||
let mut iv = [0u8; IV_LENGTH];
|
||||
base64::decode_config_slice(¶ms.iv, base64::STANDARD, &mut iv)?;
|
||||
let cipher = cbc::Decryptor::<Aes256>::new_from_slices(&key, &iv)?;
|
||||
let decoded = base64::decode(ciphertext)?;
|
||||
let size: usize = decoded.len() / 16 + (if decoded.len() % 16 == 0 { 0 } else { 1 });
|
||||
let mut buffer = vec![0xffu8; 16 * size];
|
||||
buffer[..decoded.len()].copy_from_slice(&decoded);
|
||||
let decrypted = cipher.decrypt(&mut buffer)?;
|
||||
let unpadded = Pkcs7::unpad(decrypted)?;
|
||||
Ok(unpadded.to_vec())
|
||||
let decrypted = cipher.decrypt_padded_mut::<Pkcs7>(&mut buffer)?;
|
||||
Ok(decrypted.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum EntryEncryptionError {
|
||||
#[error("Invalid ciphertext length. The ciphertext must be a multiple of 16 bytes.")]
|
||||
InvalidCipherTextLength,
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
/// For some reason, these errors do not get converted to `ManifestAccountLoadError`s, even though they get converted into `anyhow::Error` just fine. I am too lazy to figure out why right now.
|
||||
impl From<block_modes::BlockModeError> for EntryEncryptionError {
|
||||
fn from(error: block_modes::BlockModeError) -> Self {
|
||||
impl From<InvalidLength> for EntryEncryptionError {
|
||||
fn from(error: InvalidLength) -> Self {
|
||||
Self::Unknown(anyhow::Error::from(error))
|
||||
}
|
||||
}
|
||||
impl From<block_modes::InvalidKeyIvLength> for EntryEncryptionError {
|
||||
fn from(error: block_modes::InvalidKeyIvLength) -> Self {
|
||||
|
||||
impl From<inout::NotEqualError> for EntryEncryptionError {
|
||||
fn from(error: inout::NotEqualError) -> Self {
|
||||
Self::Unknown(anyhow::Error::from(error))
|
||||
}
|
||||
}
|
||||
impl From<block_modes::block_padding::PadError> for EntryEncryptionError {
|
||||
fn from(_error: block_modes::block_padding::PadError) -> Self {
|
||||
Self::Unknown(anyhow!("PadError"))
|
||||
|
||||
impl From<inout::PadError> for EntryEncryptionError {
|
||||
fn from(error: inout::PadError) -> Self {
|
||||
Self::Unknown(anyhow::Error::from(error))
|
||||
}
|
||||
}
|
||||
impl From<block_modes::block_padding::UnpadError> for EntryEncryptionError {
|
||||
fn from(_error: block_modes::block_padding::UnpadError) -> Self {
|
||||
Self::Unknown(anyhow!("UnpadError"))
|
||||
|
||||
impl From<inout::block_padding::UnpadError> for EntryEncryptionError {
|
||||
fn from(error: inout::block_padding::UnpadError) -> Self {
|
||||
Self::Unknown(anyhow::Error::from(error))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<base64::DecodeError> for EntryEncryptionError {
|
||||
fn from(error: base64::DecodeError) -> Self {
|
||||
Self::Unknown(anyhow::Error::from(error))
|
||||
|
@ -178,14 +167,18 @@ mod tests {
|
|||
#[test]
|
||||
fn test_encryption_key() {
|
||||
assert_eq!(
|
||||
LegacySdaCompatible::get_encryption_key("password", "GMhL0N2hqXg=").unwrap(),
|
||||
LegacySdaCompatible::get_encryption_key("password", "GMhL0N2hqXg=")
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
base64::decode("KtiRa4/OxW83MlB6URf+Z8rAGj7CBY+pDlwD/NuVo6Y=")
|
||||
.unwrap()
|
||||
.as_slice()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
LegacySdaCompatible::get_encryption_key("password", "wTzTE9A6aN8=").unwrap(),
|
||||
LegacySdaCompatible::get_encryption_key("password", "wTzTE9A6aN8=")
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
base64::decode("Dqpej/3DqEat0roJaHmu3luYgDzRCUmzX94n4fqvWj8=")
|
||||
.unwrap()
|
||||
.as_slice()
|
||||
|
@ -194,12 +187,22 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_ensure_encryption_symmetric() -> anyhow::Result<()> {
|
||||
let cases = [
|
||||
"foo",
|
||||
"tactical glizzy",
|
||||
"glizzy gladiator",
|
||||
"shadow wizard money gang",
|
||||
"shadow wizard money gang, we love casting spells, shadow wizard money gang, we love casting spells, shadow wizard money gang, we love casting spells, shadow wizard money gang, we love casting spells, shadow wizard money gang, we love casting spells, shadow wizard money gang, we love casting spells, shadow wizard money gang, we love casting spells, shadow wizard money gang, we love casting spells, shadow wizard money gang, we love casting spells, shadow wizard money gang, we love casting spells, shadow wizard money gang, we love casting spells",
|
||||
];
|
||||
let passkey = "password";
|
||||
let params = EntryEncryptionParams::generate();
|
||||
let orig = "tactical glizzy".as_bytes().to_vec();
|
||||
let encrypted = LegacySdaCompatible::encrypt(passkey, ¶ms, orig.clone()).unwrap();
|
||||
let result = LegacySdaCompatible::decrypt(passkey, ¶ms, encrypted).unwrap();
|
||||
assert_eq!(orig, result.to_vec());
|
||||
for case in cases {
|
||||
eprintln!("testing case: {} (len {})", case, case.len());
|
||||
let orig = case.as_bytes().to_vec();
|
||||
let encrypted = LegacySdaCompatible::encrypt(passkey, ¶ms, orig.clone()).unwrap();
|
||||
let result = LegacySdaCompatible::decrypt(passkey, ¶ms, encrypted).unwrap();
|
||||
assert_eq!(orig, result.to_vec());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Z0HJDSN9EuFOpKEeBzftCWxTsh0sV6QQriLTVrn37FyGNaXhGgzeHlvPfHgkXKCYbALTgx/B2fLh1CEojKO1/eqEgN+982CadR3EXk+vH1k5AMuGhMXPpsEeIh27ltxrdAEzWdlPlAyentBgOKlTCoN6iF+EZVORvp2pPaMrebyHi8/5Y+XC3HrMgfgmP7lFGpUgZK8f0mKB/pGaW+0/3oVikggBK3MIWlh4s9bC9LlMy5H+oU0n/Iu3P9dpbko1bDMKIbUKEPzS3wHXyQRg32zPIfONR0bswb7QTfAhoKixZrAenQluX3lXRL0JFafNEPzUY4r/DJ1pIMLK9cEvbzqwsPth6jrIZRd+zvgnshfNnGLCblYkPo4fGwePuhX2W2w6qgFMpo69rkSp1Zz6JKC/gH9YyL4a8N768ml9H1so5XBm7eB+fMRIL7bHof+V1CxGXX3z1RvjGRHPwKcrKLvffxTTs/dBHb9UDFtTprk=
|
||||
Z0HJDSN9EuFOpKEeBzftCWxTsh0sV6QQriLTVrn37FyGNaXhGgzeHlvPfHgkXKCYbALTgx/B2fLh1CEojKO1/eqEgN+982CadR3EXk+vH1k5AMuGhMXPpsEeIh27ltxrdAEzWdlPlAyentBgOKlTCoN6iF+EZVORvp2pPaMrebyHi8/5Y+XC3HrMgfgmP7lFGpUgZK8f0mKB/pGaW+0/3oVikggBK3MIWlh4s9bC9LlMy5H+oU0n/Iu3P9dpbko1bDMKIbUKEPzS3wHXyQRg32zPIfONR0bswb7QTfAhoKixZrAenQluX3lXRL0JFafNEPzUY4r/DJ1pIMLK9cEvbzqwsPth6jrIZRd+zvgnshfNnGLCblYkPo4fGwePuhX2W2w6qgFMpo69rkSp1Zz6JKC/gH9YyL4a8N768ml9H1so5XBm7eB+fMRIL7bHof+V1CxGXX3z1RvjGRHPwKcrKLvffxTTs/dBHb9UDFtTprlymLZf6C53c5vMBQ/hk4fm
|
|
@ -1 +0,0 @@
|
|||
ZQqJk4KW7pb5bndkra244z3ttIks58UplODn5IgljrOK3bKORSwrnZYb9Iv6YsirmrT0hQ3tx381GhQu4Nyj/PFHHCfFTrduaCoMLRrHDsmsexOW93Yo02acHXNfPSvxtjGfZpsuIZVlhVy8JDH/ESXp88cKn2zqjXQWu6pLnah1YPlpZuTfArw69+Em7V1OH1CoKnsYuhCo/x4u7fXhMNgDlRBvDbO4enGzaixonPu9er5Zp6iNEeuAUqmD0DHASygNmzBhUBHv8Avng8YKbvu611yQVT2KybnIoL+Q11Y36GoFhWskmG3lLwh/1OlReGwJ1iX0lDDthoel/Ygj6EC2+wkR8V7eMQf48R15xdBILYTzcrjtiuLCr9MBc/HM/ToEa3QCGwGkXvshR/meJ1BiqaRARKfvJcj4eMSpiUvhDe1QFXXjfXRdetJcknyJ8Pv6v10G/OV3ELYwdx2dYL5C+Ao4qj9QCjoD8bb/juCjtZoSxMncbm4T7ORbXs/Ulx+TEuOUmRAjxr+zaWzzO7ZfYJMhIPz+LSixKpaVmxP89DEK5LJ1T6jA50QmPft6AbOMuoq99haWH9lMgqrIfBB+ZNNHSEE9PwMUxhX/TQP3oJgmrnZcMV4nBOcovbWM5s+odu2mvzoAcRMHVxEztASbMBwdJ7amJvoRRrXTtp642FQHAe8pFPlW14x1hShXAO4YfYkmmAhLqlujammuQ6bRg7XjBvh0zE88i5UBRiRsH+MV35u3c0ciugUmbrAZ0u9Yfv19MNSMVNMsREDuxQ==
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"encrypted": true,
|
||||
"first_run": true,
|
||||
"entries": [
|
||||
{
|
||||
"encryption_iv": "ifChnv66eA+/dYqGsQMIOA==",
|
||||
"encryption_salt": "O2K8FAOWK9c=",
|
||||
"filename": "1234.maFile",
|
||||
"steamid": 1234
|
||||
}
|
||||
],
|
||||
"periodic_checking": false,
|
||||
"periodic_checking_interval": 5,
|
||||
"periodic_checking_checkall": false,
|
||||
"auto_confirm_market_transactions": false,
|
||||
"auto_confirm_trades": false
|
||||
}
|
Loading…
Reference in a new issue