salt | Software to automate the management and configuration of any infrastructure or application at scale. | Infrastructure Automation library
kandi X-RAY | salt Summary
Support
Quality
Security
License
Reuse
Currently covering the most popular Java, JavaScript and Python libraries. See a Sample Here
salt Key Features
salt Examples and Code Snippets
from itsdangerous.url_safe import URLSafeSerializer
s1 = URLSafeSerializer("secret-key", salt="activate") s1.dumps(42) 'NDI.MHQqszw6Wc81wOBQszCrEE_RlzY'
s2 = URLSafeSerializer("secret-key", salt="upgrade") s2.dumps(42) 'NDI.c0MpsD6gzpilOAeUPra3NShPXsE'
s2.loads(s1.dumps(42)) Traceback (most recent call last): ... BadSignature: Signature does not match
s2.loads(s2.dumps(42)) 42
public String hash(String passwordToHash, byte[] salt){ String generatedPassword = null; try { MessageDigest md = MessageDigest.getInstance("SHA-512"); md.update(salt); byte[] bytes = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); for(int i=0; i< bytes.length ;i++){ sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1)); } generatedPassword = sb.toString(); } catch (NoSuchAlgorithmException e){ e.printStackTrace(); } return generatedPassword; }
public static int mergeStones(int[] stones, int k) { int len = stones.length; if ((len - 1) % (k - 1) != 0) { return -1; } int[] prefixSum = new int[len + 1]; int i; for (i = 1; i <= len; i++) { prefixSum[i] = prefixSum[i - 1] + stones[i - 1]; } // dp[a][b][c] = Cost of merging 'c' piles of stones from index 'a' to 'b' Integer[][][] dp = new Integer[len + 1][len + 1][k + 1]; // Cost of merging k stones into one pile. Integer result = helper(prefixSum, 1, len, 1, k, dp); return result == null || result == max ? -1 : result; }
public static SecretKey getKeyFromPassword(String password, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException { SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256); SecretKey secret = new SecretKeySpec(factory.generateSecret(spec) .getEncoded(), "AES"); return secret; }
Trending Discussions on salt
Trending Discussions on salt
QUESTION
Based on the example provided here on how to establish a shared secret and derived key between JS (Crypto-JS) and Python, I can end up with the same shared secret and derived key on both ends.
However, when I try to encrypt as below, I cannot find a way to properly decrypt from Python. My understanding is that probably I am messing with the padding or salts and hashes.
const payload = "hello"
var iv = CryptoJS.enc.Utf8.parse("1020304050607080");
var test = CryptoJS.AES.encrypt(
payload,
derived_key,
{iv: iv, mode: CryptoJS.mode.CBC}
).toString();
console.log(test)
Output "y+In4kriw0qy4lji6/x14g=="
Python (one of the attempts):
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad,unpad
iv = "1020304050607080"
test_enc = "y+In4kriw0qy4lji6/x14g=="
enc = base64.b64decode(test_enc)
cipher = AES.new(derived_key, AES.MODE_CBC, iv.encode('utf-8'))
print(base64.b64decode(cipher.decrypt(enc)))
print(unpad(cipher.decrypt(enc),16))
Any guidance here would be greatly appreciated as I am stuck for quite some time.
(I have encryption working using a password, but struggling with HKDF).
EDIT:
Here is the full Python code:
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad,unpad
def deriveKey():
server_pkcs8 = b'''-----BEGIN PRIVATE KEY-----
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBReGpDVmoVTzxNbJx6
aL4L9z1EdB91eonAmAw7mKDocLfCJITXZPUAmM46c6AipTmhZANiAAR3t96P0ZhU
jtW3rHkHpeGu4e+YT+ufMiMeanE/w8p+d9aCslvIbZyBBzeZ/266yqTUUoiYDzqv
Hb5q8rz7vEgr3DG4XfHYpCqfE2nttQGK3emHKGnvY239AteZkdwMpcs=
-----END PRIVATE KEY-----'''
client_x509 = b'''-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm0xeyy3nVnYpOpx/CV/FnlNEdWUZaqtB
AGf7flKxXEjmlSUjseYzCd566sLpNg56Gw6hcFx+rWTLGR4eDRWfmwlXhyUasuEg
mb0BQf8XJLBdvadb9eFx2CP1yjBsiy8e
-----END PUBLIC KEY-----'''
client_public_key = serialization.load_pem_public_key(client_x509)
server_private_key = serialization.load_pem_private_key(server_pkcs8, password=None)
shared_secret = server_private_key.exchange(ec.ECDH(), client_public_key)
print('Shared secret: ' + base64.b64encode(shared_secret).decode('utf8')) # Shared secret: xbU6oDHMTYj3O71liM5KEJof3/0P4HlHJ28k7qtdqU/36llCizIlOWXtj8v+IngF
salt_bytes = "12345678".encode('utf-8')
info_bytes = "abc".encode('utf-8')
derived_key = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=salt_bytes,
info=info_bytes,
).derive(shared_secret)
print('Derived key: ' + base64.b64encode(derived_key).decode('utf8'))
return derived_key
derived_key = deriveKey()
iv = "1020304050607080"
test_enc = "y+In4kriw0qy4lji6/x14g=="
enc = base64.b64decode(test_enc)
cipher = AES.new(derived_key, AES.MODE_CBC, iv.encode('utf-8'))
print(base64.b64decode(cipher.decrypt(enc)))
print(unpad(cipher.decrypt(enc),16))
ANSWER
Answered 2022-Mar-28 at 11:29The issue is that the key is not passed correctly in the CryptoJS code.
The posted Python code generates LefjQ2pEXmiy/nNZvEJ43i8hJuaAnzbA1Cbn1hOuAgA=
as Base64-encoded key. This must be imported in the CryptoJS code using the Base64 encoder:
const payload = "hello"
var derived_key = CryptoJS.enc.Base64.parse("LefjQ2pEXmiy/nNZvEJ43i8hJuaAnzbA1Cbn1hOuAgA=")
var iv = CryptoJS.enc.Utf8.parse("1020304050607080");
var test = CryptoJS.AES.encrypt(payload, derived_key, {iv: iv, mode: CryptoJS.mode.CBC}).toString();
document.getElementById("ct").innerHTML = test; // bLdmGA+HLLyFEVtBEuCzVg==
The hereby generated ciphertext bLdmGA+HLLyFEVtBEuCzVg==
can be decrypted with the Python code:
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
test_enc = "bLdmGA+HLLyFEVtBEuCzVg=="
enc = base64.b64decode(test_enc)
derived_key = base64.b64decode("LefjQ2pEXmiy/nNZvEJ43i8hJuaAnzbA1Cbn1hOuAgA=")
iv = "1020304050607080"
cipher = AES.new(derived_key, AES.MODE_CBC, iv.encode('utf-8'))
print(unpad(cipher.decrypt(enc),16)) # b'hello'
Note that for security reasons, a static IV should not be used so that key/IV pairs are not repeated.
QUESTION
I'm new to Cassandra and I've been having some issues trying to delete multiple rows in table. I have a table defined as follows:
CREATE TABLE aze.isis_users (
identifier text PRIMARY KEY,
iteration_count int,
password_expires_on date,
passwordword blob,
roleidentifier text,
salt blob
) WITH additional_write_policy = '99p'
AND bloom_filter_fp_chance = 0.01
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND cdc = false
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
AND compression = {'chunk_length_in_kb': '16', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND crc_check_chance = 1.0
AND default_time_to_live = 0
AND extensions = {}
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair = 'BLOCKING'
AND speculative_retry = '99p';
ANSWER
Answered 2022-Feb-02 at 09:56It doesn't work this way in Cassandra. You need to have a full or partial primary key specified in the DELETE
command. If you want to delete by non-primary/partition key, then you need first to find rows with that value, extract primary key, and then delete by primary key.
You can find ways to do that in this answer.
QUESTION
I have some long saltstack orchestration states and i want to add some informational messages to it (for example: Gonna apply some state on minion foo) ,and this messages must be printed immediately ( not after all actions completed).
Jinja log message {% do salt.log.error("Some message) %}
is not suitable (they printed before state actually runs).
test.echo
module also not suitable (prints message after all actions completed)
test_blabla:
salt.runner:
- name: salt.cmd
- arg:
- test.echo
- some_blabla
Is there any way to print messages during states execution? Maybe I'm missing something?
ANSWER
Answered 2021-Nov-18 at 18:38There are ways to cheat. As long as you are talking about orchestration AND you are running said orchestration through salt-run
.
And you almost had it. except to conflated the answer into jinja and the wrong module into the state. the reason the log message comes before anything runs is because you are calling it in jinja. but you don't have to call it through jinja. you can call it in a state.
test_blabla:
module.run:
- name: log.error
- message: some_blabla
test_oh:
salt.runner:
- name: salt.cmd
- arg:
- test.sleep
- 10
This is all kind of hacky as salt was not meant to do this. salt runs async which means it doesn't return until it is finished. or may not return directly at all and you are meant to check the results else where. another way to do this is have a state fire an event and watch the event bus instead of the state run.
QUESTION
This code below returns the input password as undefined, but all other inputs are fine. I don't know what to do, if anyone can help please do.
I am using bcrypt.js with knex for psql.
app.post("/register", (req, res) => {
const { email, name, password } = req.body;
let salt = bcrypt.genSaltSync(10);
let hash = bcrypt.hashSync(password, salt);
knex
.transaction((trx) => {
trx
.insert({
hash: bcrypt.hashSync(password, salt),
email: email,
})
.into("login")
.returning("email")
.then((loginEmail) => {
return trx("users")
.returning("*")
.insert({
email: loginEmail[0].email,
name: name,
joined: new Date(),
})
.then((user) => {
res.json(user[0]);
});
})
.then(trx.commit)
.catch(trx.rollback);
})
.catch((err) => res.status(400).json("E-mail is already in use"));
});
*P.S. Using postman gives no errors. The error that comes in on the back-end terminal is Error: Illegal arguments: undefined, string
meaning hash is undefined
ANSWER
Answered 2022-Jan-19 at 01:12I fixed it, was apparently a variable naming issue :) such a goof.
password was actually being received as "hash" from the front-end, changed it to hash & changed hash to hashedPassword.
const { email, name, hash } = req.body;
let salt = bcrypt.genSaltSync(10);
let hashedPassword = bcrypt.hashSync(hash, salt);
knex
.transaction((trx) => {
trx
.insert({
hash: hashedPassword,
email: email,
})
QUESTION
I never thought I would have to turn to SO to solve this.
Alright so for more insight I am making my own encryption program. I'm not trying to make it good or anything it's just a personal project. What this program is doing is that it's flipping certain bits in every single byte of the character making it unreadable.
However every time I run the program and decrypt I get weird characters on the output. These characters seem to match the amount of lines as following:
^^ text that I want to encrypt
^^ after encrypting. (a lot of the text got cut off)
^^ after decrypting. there's 10 null character corresponding to the amount of newlines. there also seems to be another weird '�' character. Where are these bytes coming from??
I've tried a lot of stuff. Here is my code if anyone needs it (it's compiled with default flags):
#include
#include
#include
#include
#define ENCRYPTFILE "Encrypted.oskar"
typedef unsigned char BYTE;
char saltFunc(BYTE salt, char chr) {
for(int i = 0; i < 8; i++) {
if((salt >> i) & 1U) {
chr ^= 1UL << i;
}
}
return chr;
}
int main () {
std::ofstream encryptFile(ENCRYPTFILE, std::ifstream::in);
std::ifstream inputFile(ENCRYPTFILE, std::ifstream::in);
unsigned int length;
unsigned int lineLength;
BYTE salt = 0b00000001;
std::string line;
std::cin.unsetf(std::ios::dec);
std::cin.unsetf(std::ios::hex);
std::cin.unsetf(std::ios::oct);
//std::cout << "input salt in hex with a prefix 0x so for example. 0xA2" << std::endl;
//std::cin >> std::hex >> salt;
inputFile.seekg(0, inputFile.end);
length = inputFile.tellg();
inputFile.seekg(0, inputFile.beg);
std::cout << lineLength << std::endl;
char* fileBuffer = new char[length];
char* encryptFileBuffer = new char[length];
memset(fileBuffer, 0, length);
memset(encryptFileBuffer, 0, length);
while (inputFile.good()) { // just get file length in bytes.
static int i = 0;
fileBuffer[i] = inputFile.get();
i++;
}
while (std::getline(inputFile, line))
++lineLength;
inputFile.clear();
encryptFile.clear();
std::cout << "file size: " << length << std::endl;
for(int i = 0; i < length; i++) {
encryptFileBuffer[i] = saltFunc(salt, fileBuffer[i]);
encryptFile << encryptFileBuffer[i];
}
inputFile.close();
encryptFile.close();
delete[] encryptFileBuffer;
delete[] fileBuffer;
return 0;
}
ANSWER
Answered 2022-Jan-10 at 01:05The problem is that you are measuring the length of the file in bytes, which, for text files, is not the same as the length in characters. But you are then reading it as characters, so you end up reading too many characters and then writing extra garbage after then end in the output file.
Since you are getting one extra character per line, it is likely you are running on Windows, where line ending characters are two bytes in the file. That's where the extra incorrect length you are seeing is coming from.
For encryption/decryption what you probably want to do is read and write the file in binary mode, so you are reading and writing bytes not characters. You do this by adding std::ios::binary
into the flags when opening the file(s):
std::ofstream encryptFile(ENCRYPTFILE, std::ifstream::in | std::ios::binary);
std::ifstream inputFile(ENCRYPTFILE, std::ifstream::in | std::ios::binary);
QUESTION
I have a shared key that I need to derive an iv from so I can decipher.
The apple business chat docs state:
Generate the Derived Key and Initial Vector Run the shared key through the X9.63 Key Derivation Function with SHA256 hash function. This results in a 48-byte payload. Your results should be rV3qrszd0PMPgeRhNnlOYA==
Heres what I tried. I used scryptSync and pbkdf2Sync crypto functions with many 'salt' configurations. I'm unsure if these are the correct functions for this job.
const crypto = require('crypto');
const keyLength = 48;
// sharedKey is a base64 string
const sharedKey = "2lvSJsBO2keUHRfvPG6C1RMUmGpuDbdgNrZ9YD7RYnvAcfgq/fjeYr1p0hWABeif";
// publicKey is a base64 string
const publicKey = "BDiRKNnPiPUb5oala31nkmCaXMB0iyWy3Q93p6fN7vPxEQSUlFVsInkJzPBBqmW1FUIY1KBA3BQb3W3Qv4akZ8kblqbmvupE/EJzPKbROZFBNvxpvVOHHgO2qadmHAjHSg=="
const key1 = crypto.scryptSync(sharedKey, 'salt', keyLength);
console.log(key2.toString('base64'));
const key2 = crypto.pbkdf2Sync(sharedKey, 'salt', 10000, keyLength, 'sha256');
console.log(key2.toString('base64'));
// results should be:
// mAzkYatDlz4SzrCyM23NhgL/+mE3eGgfUz9h1CFPhZM=
// iv: rV3qrszd0PMPgeRhNnlOYA==
Below is the Apple sample code for Deriving the Key and Initial Vector with a X9.63 Key Derivation Function.
def ITOSP(self, longint, length):
"""ITOSP, short for Integer-to-Octet-String Primitive, converts a non-negative integer
to an octet string of a specified length. This particular function is defined in the
PKCS #1 v2.1: RSA Cryptography Standard (June 14, 2002)
https://www.cryptrec.go.jp/cryptrec_03_spec_cypherlist_files/PDF/pkcs-1v2-12.pdf"""
hex_string = "%X" % longint
assert len(hex_string) <= 2 * length, "ITOSP function: Insufficient length for encoding"
return binascii.a2b_hex(hex_string.zfill(2 * length))
def KDFX963(self, inbyte_x, shared_data, key_length, hashfunct=sha256, hash_len=32):
"""KDFX963 is a key derivation function (KDF) that takes as input byte sequence inbyte_x
and additional shared data shared_data and outputs a byte sequence key of length
key_length. This function is defined in ANSI-X9.63-KDF, and this particular flavor of
KDF is known as X9.63. You can read more about it from:
http://www.secg.org/sec1-v2.pdf"""
assert key_length >= 0, "KDFX963 function: key_length should be positive integer"
k = key_length / float(hash_len)
k = int(ceil(k))
acc_str = ""
for i in range(1, k+1):
h = hashfunct()
h.update(inbyte_x)
h.update(self.ITOSP(i, 4))
h.update(shared_data)
acc_str = acc_str + h.hexdigest()
return acc_str[:key_length * 2]
ANSWER
Answered 2022-Jan-04 at 11:46X9.63 KDF is a key derivation function, described e.g. here and here. scrypt and PBKDF2 are also KDFs, but different ones, so of course the expected result cannot be reproduced with them.
So you need a NodeJS library that supports X.963 KDF. If you can't find one, you could also implement your own.
X9.63 KDF expects a shared secret and a shared info and determines a keysize large key as follows:
- Create a 4 byte counter ci which is incremented starting with 0x0000001.
- Concatenate the data conci = shared secret | ci | shared info
- Hash the result hashi = hash(conci)
- Concatenate the hashes hash1 | hash2 | ... until an output of length keysize has been generated.
More formally, including various checks, the algorithm is described in the links above. The Python code posted later in the question also implements this logic.
One possible NodeJS implementation (omitting the checks from the specification) is:
var crypto = require('crypto');
var digest = 'sha256';
var digestLen = 32;
function X963KDF(sharedSecret, sharedInfo, keySize){
var maxCount = Math.ceil(keySize/digestLen);
var result = Buffer.allocUnsafe(0);
for (var count = 1; count < maxCount + 1; count++){
var counter = Buffer.allocUnsafe(4);
counter.writeUInt32BE(count, 0);
var current = Buffer.concat([sharedSecret, counter, sharedInfo]);
var hash = crypto.createHash(digest).update(current).digest();
result = Buffer.concat([result, hash]);
}
return result.slice(0, keySize);
}
Test:
In the question the shared secret is posted, but not the shared info. An internet search reveals that the posted problem is described e.g. here, so that the shared info can also be determined (nevertheless it would be better if you add this information to your question):
var sharedSecret = Buffer.from('2lvSJsBO2keUHRfvPG6C1RMUmGpuDbdgNrZ9YD7RYnvAcfgq/fjeYr1p0hWABeif', 'base64')
var sharedInfo = Buffer.from('04389128d9cf88f51be686a56b7d6792609a5cc0748b25b2dd0f77a7a7cdeef3f111049494556c227909ccf041aa65b5154218d4a040dc141bdd6dd0bf86a467c91b96a6e6beea44fc42733ca6d139914136fc69bd53871e03b6a9a7661c08c74a', 'hex');
var keyiv = X963KDF(sharedSecret, sharedInfo, 48);
var key = keyiv.slice(0,32).toString('base64');
var iv = keyiv.slice(32, 48).toString('base64');
console.log("Key: ", key); // Key: mAzkYatDlz4SzrCyM23NhgL/+mE3eGgfUz9h1CFPhZM=
console.log("IV: ", iv); // IV: rV3qrszd0PMPgeRhNnlOYA==
The generated key and IV are equal to the expected values.
QUESTION
I've been using Flyway in my application, where each use has their own persistent H2 database.
Due to the databases persisting, and Flyway being upgraded from v4 to v5, some users have a schema_version
table, while others have a flyway_schema_history
table.
Obviously Flyway v6 will not work for the databases with a schema_version
table.
Initially I was blocked, but then discovered callbacks that allow SQL to be run at arbritrary points. So the obvious solution was a beforeMigrate.sql
that renamed the schema_version
table to flyway_schema_history
.
However when I try this, even though I can see from the debug logs the command is executed, I get the following erorr. I even get the error when I manually rename the table in the database outside of the callback functionality.
org.flywaydb.core.api.FlywayException: Found non-empty schema(s) "PUBLIC" but no schema history table. Use baseline() or set baselineOnMigrate to true to initialize the schema history table.
I'm getting this whether I tentatively upgrade to Flyway v6 or the latest v8.
Is there something obvious I'm missing? Or is there a smarter way to move these existing databases to a format compatible with the latest flyway versions?
I've created an MVCE using Maven but it's obviously slightly complex as it involves a database etc.
Directory structure:
flywaytest
src
main
java
com
me
flywaytest
FlywayTest.java
resources
db
migration
beforeMigrate.sql
V1__Intial.sql
pom.xml
FlywayTest.java
:
package com.me.flywaytest;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.text.MessageFormat;
import org.flywaydb.core.Flyway;
import org.h2.engine.Constants;
public class FlywayTest {
private static final String databaseName = "fruits";
private static final String h2URL = MessageFormat.format("jdbc:h2:~/{0}", databaseName);
private static final Path databaseLocation = Paths.get(System.getProperty("user.home"))
.resolve(databaseName + Constants.SUFFIX_MV_FILE);
public static void main(final String[] args) throws Exception {
Files.deleteIfExists(databaseLocation);
createOldDatabase();
Flyway.configure().dataSource(h2URL, null, null).load().migrate();
}
private static Connection getConnection() throws Exception {
return DriverManager.getConnection(h2URL, null, null);
}
/** Creates an example database as created by Flyway v4.2.0 */
private static void createOldDatabase() throws Exception {
// Old Flyway database generated by rolling back Flyway and running an initial
// migration and dumping it's SQL using the following:
// Flyway flyway = new Flyway();
// flyway.setDataSource(h2URL, null, null);
// flyway.migrate();
// try (Connection connection = getConnection()) {
// Script.process(connection,
// Paths.get(System.getProperty("user.home")).resolve(databaseName +
// ".sql").toString(), "", "");
// }
// Which created the following:
final String fruitsSQL = """
;
CREATE USER IF NOT EXISTS "" SALT '' HASH '' ADMIN;
CREATE CACHED TABLE "PUBLIC"."schema_version"(
"installed_rank" INT NOT NULL,
"version" VARCHAR(50),
"description" VARCHAR(200) NOT NULL,
"type" VARCHAR(20) NOT NULL,
"script" VARCHAR(1000) NOT NULL,
"checksum" INT,
"installed_by" VARCHAR(100) NOT NULL,
"installed_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
"execution_time" INT NOT NULL,
"success" BOOLEAN NOT NULL
);
ALTER TABLE "PUBLIC"."schema_version" ADD CONSTRAINT "PUBLIC"."schema_version_pk" PRIMARY KEY("installed_rank");
-- 1 +/- SELECT COUNT(*) FROM PUBLIC.schema_version;
INSERT INTO "PUBLIC"."schema_version" VALUES
(1, '1', 'Initial', 'SQL', 'V1__Initial.sql', 691111646, '', TIMESTAMP '2021-12-26 00:07:37.878797', 0, TRUE);
CREATE INDEX "PUBLIC"."schema_version_s_idx" ON "PUBLIC"."schema_version"("success");
CREATE CACHED TABLE "PUBLIC"."FRUITS"(
"NAME" CHARACTER VARYING
);
-- 0 +/- SELECT COUNT(*) FROM PUBLIC.FRUITS;
""";
try (Statement statement = getConnection().createStatement()) {
statement.execute(fruitsSQL);
}
}
}
beforeMigrate.sql
:
ALTER TABLE IF EXISTS "schema_version" RENAME CONSTRAINT "schema_version_pk" TO "flyway_schema_history_pk";
ALTER TABLE IF EXISTS "schema_version" RENAME TO "flyway_schema_history";
ALTER INDEX IF EXISTS "schema_version_s_idx" RENAME TO "flyway_schema_history_s_idx";
V1__Initial.sql
:
CREATE TABLE FRUITS(
NAME CHARACTER VARYING
);
pom.xml
:
4.0.0
com.me
flywaytest
0.0.1-SNAPSHOT
com.h2database
h2
1.4.200
org.flywaydb
flyway-core
8.3.0
ANSWER
Answered 2021-Dec-26 at 15:55I personally have never used Flyway's callbacks but please, be aware that, according to the library source code, the beforeMigrate
callback will be run in DbMigrate
after the schema history table existence is checked in the Flyway
class, so try renaming the history table may not work.
As a possible solution, you could try providing explicitly the table
name for your databases, keeping the previous one, schema_version
. For example:
Flyway.configure()
.table("schema_version")
.dataSource(h2URL, null, null)
.load()
.migrate()
;
Probably using the beforeValidate
callback could work as well, as that callback seems to be executed before the actual schema history table existence check. I renamed your script from beforeMigrate.sql
to beforeValidate.sql
and it worked properly. Just be sure that validation on migrate is enabled - it should be by default.
QUESTION
Like the question says, I am trying to import a CSV with the following function:
def import_users
path = Rails.root.join('somePath')
CSV.foreach(path, headers: true) do |row|
usr = User.new(row.to_hash)
usr.skip_callbacks = true
usr.save
end
puts "inserts on table users complete"
end
As you can tell, it is a simple function.
Issue:All the columns with the correct data are imported correctly but in the User Class
the password= function (setter)
is triggered:
class User < ApplicationRecord
attr_accessor :skip_callbacks
validates :password, presence: true, unless: :skip_callbacks
def password= password
self[:password] = hash_password password
end
private
def hash_password password
Digest::MD5.hexdigest "#{Digest::MD5.hexdigest password}#{salt}"
end
end
This causes the password column in the database to be rewritten again with new hashes as passwords which then prevents login because the column values have changed. The password column in the database does not contain the same info as in the CSV File.
Normally I implemented a skip_callback
to bypass password validation
but does not seem to work.
I would really appreciate any kind of help as I have been trying to solve this for a couple of days now and can't seem to figure out why.
ANSWER
Answered 2021-Dec-23 at 05:30Looks like you want to add passwords to database as is without hashing, and validations have nothing to do with it because they will not change the behavior of the password=
function. You may patch it with another instance variable like:
class User < ApplicationRecord
attr_accessor :skip_callbacks
attr_accessor :skip_password_hashing
validates :password, presence: true, unless: :skip_callbacks
def password= password
self[:password] = skip_password_hashing ? password : hash_password(password)
end
private
def hash_password password
Digest::MD5.hexdigest "#{Digest::MD5.hexdigest password}#{salt}"
end
end
and then patch import like:
def import_users
path = Rails.root.join('somePath')
CSV.foreach(path, headers: true) do |row|
usr = User.new(row.to_hash)
usr.skip_password_hashing = true
usr.save
end
puts "inserts on table users complete"
end
I am not sure if it is a good idea to have this possibility in deployed application, but it should work.
QUESTION
I'm using a string Encryption/Decryption class similar to the one provided here as a solution.
This worked well for me in .Net 5.
Now I wanted to update my project to .Net 6.
When using .Net 6, the decrypted string does get cut off a certain point depending on the length of the input string.
▶️ To make it easy to debug/reproduce my issue, I created a public repro Repository here.
- The encryption code is on purpose in a Standard 2.0 Project.
- Referencing this project are both a .Net 6 as well as a .Net 5 Console project.
Both are calling the encryption methods with the exact same input of "12345678901234567890"
with the path phrase of "nzv86ri4H2qYHqc&m6rL"
.
.Net 5 output: "12345678901234567890"
.Net 6 output: "1234567890123456"
The difference in length is 4
.
I also looked at the breaking changes for .Net 6, but could not find something which guided me to a solution.
I'm glad for any suggestions regarding my issue, thanks!
Encryption Class
public static class StringCipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 128;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate128BitsOfRandomEntropy();
var ivStringBytes = Generate128BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = Aes.Create())
{
symmetricKey.BlockSize = 128;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [16 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 16 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 16 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = Aes.Create())
{
symmetricKey.BlockSize = 128;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
private static byte[] Generate128BitsOfRandomEntropy()
{
var randomBytes = new byte[16]; // 16 Bytes will give us 128 bits.
using (var rngCsp = RandomNumberGenerator.Create())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
Calling code
var input = "12345678901234567890";
var inputLength = input.Length;
var inputBytes = Encoding.UTF8.GetBytes(input);
var encrypted = StringCipher.Encrypt(input, "nzv86ri4H2qYHqc&m6rL");
var output = StringCipher.Decrypt(encrypted, "nzv86ri4H2qYHqc&m6rL");
var outputLength = output.Length;
var outputBytes = Encoding.UTF8.GetBytes(output);
var lengthDiff = inputLength - outputLength;
ANSWER
Answered 2021-Nov-10 at 10:25The reason is this breaking change:
DeflateStream, GZipStream, and CryptoStream diverged from typical Stream.Read and Stream.ReadAsync behavior in two ways:
They didn't complete the read operation until either the buffer passed to the read operation was completely filled or the end of the stream was reached.
And the new behaviour is:
Starting in .NET 6, when Stream.Read or Stream.ReadAsync is called on one of the affected stream types with a buffer of length N, the operation completes when:
At least one byte has been read from the stream, or The underlying stream they wrap returns 0 from a call to its read, indicating no more data is available.
In your case you are affected because of this code in Decrypt
method:
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
You do not check how much bytes Read
actually read and whether it read them all. You could get away with this in previous versions of .NET because as mentioned CryptoStream
behaviour was different from other streams, and because your buffer length is enough to hold all data. However, this is no longer the case and you need to check it as you would do for other streams. Or even better - just use CopyTo
:
using (var plainTextStream = new MemoryStream())
{
cryptoStream.CopyTo(plainTextStream);
var plainTextBytes = plainTextStream.ToArray();
return Encoding.UTF8.GetString(plainTextBytes, 0, plainTextBytes.Length);
}
Or even better as another answer suggests, since you decrypt UTF8 text:
using (var plainTextReader = new StreamReader(cryptoStream))
{
return plainTextReader.ReadToEnd();
}
QUESTION
I am building a Create a Recipe form using crispy forms and I am trying to use a datalist input field for users to enter their own ingredients, like 'Big Tomato' or select from GlobalIngredients already in the database like 'tomato' or 'chicken'. However, regardless of whether I enter a new ingredient or select a pre-existing one, I am getting the following error: "Select a valid choice. That choice is not one of the available choices.". How do I fix this error?
models.py
class Recipe(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
websiteURL = models.CharField(max_length=200, blank=True, null=True)
image = models.ImageField(upload_to='image/', blank=True, null=True)
name = models.CharField(max_length=220) # grilled chicken pasta
description = models.TextField(blank=True, null=True)
notes = models.TextField(blank=True, null=True)
serves = models.CharField(max_length=30, blank=True, null=True)
prepTime = models.CharField(max_length=50, blank=True, null=True)
cookTime = models.CharField(max_length=50, blank=True, null=True)
class Ingredient(models.Model):
name = models.CharField(max_length=220)
def __str__(self):
return self.name
class GlobalIngredient(Ingredient):
pass # pre-populated ingredients e.g. salt, sugar, flour, tomato
class UserCreatedIngredient(Ingredient): # ingredients user adds, e.g. Big Tomatoes
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class RecipeIngredient(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
ingredient = models.ForeignKey(Ingredient, null=True, on_delete=models.SET_NULL)
description = models.TextField(blank=True, null=True)
quantity = models.CharField(max_length=50, blank=True, null=True) # 400
unit = models.CharField(max_length=50, blank=True, null=True) # pounds, lbs, oz ,grams, etc
forms.py
class RecipeIngredientForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(RecipeIngredientForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
#self.helper.form_id = 'id-entryform'
#self.helper.form_class = 'form-inline'
self.helper.layout = Layout(
Div(
Div(Field("ingredient", placeholder="Chickpeas - only write the ingredient here"), css_class='col-6 col-lg-4'),
Div(Field("quantity", placeholder="2 x 400"), css_class='col-6 col-md-4'),
Div(Field("unit", placeholder="grams"), css_class='col-5 col-md-4'),
Div(Field("description", placeholder="No added salt tins - All other information, chopped, diced, whisked!", rows='3'), css_class='col-12'),
css_class="row",
),
)
class Meta:
model = RecipeIngredient
fields = ['ingredient', 'quantity', 'unit', 'description']
labels = {
'ingredient': "Ingredient",
"quantity:": "Ingredient Quantity",
"unit": "Unit",
"description:": "Ingredient Description"}
widgets={'ingredient': forms.TextInput(attrs={
'class': 'dropdown',
'list' : 'master_ingredients',
'placeholder': "Chickpeas - only write the ingredient here"
})}
views.py
@login_required
def recipe_create_view(request):
ingredient_list = Ingredient.objects.all()
form = RecipeForm(request.POST or None)
# Formset = modelformset_factory(Model, form=ModelForm, extra=0)
RecipeIngredientFormset = formset_factory(RecipeIngredientForm)
formset = RecipeIngredientFormset(request.POST or None)
RecipeInstructionsFormset = formset_factory(RecipeInstructionForm, extra=0)
instructionFormset = RecipeInstructionsFormset(request.POST or None, initial=[{'stepName': "Step 1"}], prefix="instruction")
context = {
"form": form,
"formset": formset,
"instructionFormset": instructionFormset,
"ingredient_list": ingredient_list
}
if request.method == "POST":
print(request.POST)
if form.is_valid() and formset.is_valid() and instructionFormset.is_valid():
parent = form.save(commit=False)
parent.user = request.user
parent.save()
# formset.save()
#recipe ingredients
for form in formset:
child = form.save(commit=False)
print(child.ingredient)
globalIngredient = Ingredient.objects.filter(name=child.ingredient.lower()) # not truly global as this will return user ingredients too
if (globalIngredient):
pass
else:
newIngredient = UserCreatedIngredient(user=request.user, name=child.ingredient.lower())
newIngredient.save()
if form.instance.ingredient.strip() == '':
pass
else:
child.recipe = parent
child.save()
# recipe instructions
for instructionForm in instructionFormset:
instructionChild = instructionForm.save(commit=False)
if instructionForm.instance.instructions.strip() == '':
pass
else:
instructionChild.recipe = parent
instructionChild.save()
context['message'] = 'Data saved.'
return redirect(parent.get_absolute_url())
else:
form = RecipeForm(request.POST or None)
formset = RecipeIngredientFormset()
instructionFormset = RecipeInstructionsFormset()
return render(request, "recipes/create.html", context)
create.html
{% if formset %}
Ingredients
{{ formset.management_form|crispy }}
{% for ingredient in formset %}
{% crispy ingredient %}
{% endfor %}
{% for k in ingredient_list %}
{% endfor %}
{{ formset.empty_form.ingredient|as_crispy_field }}
{{ formset.empty_form.quantity|as_crispy_field }}
{{ formset.empty_form.unit|as_crispy_field }}
{{ formset.empty_form.description|as_crispy_field }} Hide
Description Add a
Description Field
Add more ingredients
{% endif %}
ANSWER
Answered 2021-Dec-12 at 17:37You can create your own TextInput
and TypedModelListField
field to handle this. I think what you're looking for is something which allows the user to both search and provide a recommended selection of choices but validate the input against a model (Ingredient
).
I've created one here:
class TypedModelListField(forms.ModelChoiceField):
def to_python(self, value):
if self.required:
if value == '' or value == None:
raise forms.ValidationError('Cannot be empty')
validate_dict = {self.validate_field: value}
try:
value = type(self.queryset[0]).objects.get(**validate_dict))
except:
raise forms.ValidationError('Select a valid choice. That choice is not one of the available choices.')
value = super().to_python(value)
return value
def __init__(self, *args, **kwargs):
self.validate_field= kwargs.pop('validate_field', None)
super().__init__(*args, **kwargs)
class ListTextWidget(forms.TextInput):
def __init__(self, dataset, name, *args, **kwargs):
super().__init__(*args)
self._name = name
self._list = dataset
self.attrs.update({'list':'list__%s' % self._name,'style': 'width:100px;'})
if 'width' in kwargs:
width = kwargs['width']
self.attrs.update({'style': 'width:{}px;'.format(width)})
if 'identifier' in kwargs:
self.attrs.update({'id':kwargs['identifier']})
def render(self, name, value, attrs=None, renderer=None):
text_html = super().render(name, value, attrs=attrs)
data_list = '' % self._name
for item in self._list:
data_list += '' % item
data_list += ''
return (text_html + data_list)
Within the RecipeIngredientForm
add the following definition:
ingredient = TypedModelListField(
queryset=Ingredient.objects.all(),
validate_field='name')
And then in RecipeIngredientForm
within the __init__
function. Include the following after the super()
is called.
self.fields['ingredient'].widget = ListTextWidget(
dataset=Ingredient.objects.all(),
name='ingredient_list')
Community Discussions, Code Snippets contain sources that include Stack Exchange Network
Vulnerabilities
No vulnerabilities reported
Install salt
You can use salt like any standard Python library. You will need to make sure that you have a development environment consisting of a Python distribution including header files, a compiler, pip, and git installed. Make sure that your pip, setuptools, and wheel are up to date. When using pip it is generally recommended to install packages in a virtual environment to avoid changes to the system.
Support
Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from over 650 million Knowledge Items
Find more librariesExplore Kits - Develop, implement, customize Projects, Custom Functions and Applications with kandi kits
Save this library and start creating your kit
Share this Page