A store has customers. Each customer logs into the store using their userID and password.
I want to create an Alloy function (fun) that, when passed credentials (userID and password), returns the customer possessing those credentials:
fun customerWithTheseCredentials[userID: UserID, password: Password]: Customer {
???
}
I have convinced myself that, to accomplish this, I must declare the customer signature this way:
sig Customer {
credentials: UserID lone -> lone Password
}
By creating the signature that way, I can implement the function this way:
fun customerWithTheseCredentials[userID: UserID, password: Password]: Customer {
credentials.password.userID
}
Had I created the customer signature this way:
sig Customer {
userID: UserID,
password: Password
}
then I could not have implemented the function. Do you agree?
I am coming to the conviction that it is always better to design signature fields with values that are relations (e.g., credentials: UserID lone -> lone Password) rather than sets (e.g., userID: UserID). Have you also come to that conviction?
Below is my Alloy model:
sig UserID {}
sig Password {}
sig Customer {
credentials: UserID lone -> lone Password
}
fun customerWithTheseCredentials[userID: UserID, password: Password]: Customer {
credentials.password.userID
}
run {}
fact Every_customer_has_a_different_password_userID {
// Every customer has a different userID
no disj c, c': Customer |
c.credentials.Password = c'.credentials.Password
// Every customer has one userID/password pair
all c: Customer |
one id: UserID |
one p: Password |
c.credentials = id -> p
}
I disagree, You could use set comprehension to easily retrieve the set of customers having the id and password given as parameter.
Have a look at this model (I took the liberty to not assume that each customer has different password ("password123" is only too common ;-)).
sig UserID {}
sig Password {}
sig Customer {
id :disj UserID,
password: Password
}
fun customerWithTheseCredentials[userID: UserID, pass: Password]: Customer {
{c:Customer| c.id=userID and c.password=pass}
}
run {}
Well, this is an area I work in so I could not show an example where the password would not be treated with more care :-) I know it is just an example but people died because of an insecure password model! (I like the hyperbole.) As a modularity freak I also think you should separate the task of authentication from the retrieval of the Customer, they are not inherently coupled so should be separate.
My model would therefore be:
sig UserId, PasswordDigest {}
sig Password { digest : disj PasswordDigest }
sig Customer {
identity : disj UserId
}
one sig Authenticator {
db : UserId lone -> one PasswordDigest
}
pred authenticate[ id : UserId, password : Password ] {
password.digest in Authenticator.db[id]
}
fun customerWithTheseCredentials[ userid: UserId, password : Password ] : lone Customer {
authenticate[ userid, password ] => identity.userid else none
}
run { #Customer = 3 and #Password=3}
Related
I have UserEntity and AddressEntity, they are related as OneToOne, that's one user may have only one address. UserEntity has fields firstName, secondName, address. AddressEntity has fields country and city.
If I wanted to update UserEntity without doing it to its relations I would do this:
await entityManager.getRepository(UserEntity)
.createQueryBuilder('users')
.update(UserEntity)
.set(updateUserObject)
.where('users.id = :userId', { userId })
.execute();
where updateUserObject is formed from a request body. That's to say, if I need to update firstName, the object would look like this: { firstName: 'Joe' }. Now what is unclear is how to use that builder if I have the following updateUserObject:
{
firstName: "Bob",
address: {
"city": "Ottawa"
}
}
The official documentation does not address such cases.
You can achieve this using preload and save methods.
Update your UserEntity similar to below:
#Entity('user')
export class UserEntity {
...
#OneToOne(
() => AddressEntity,
{
// Make sure that when you delete or update a user, it will affect the
// corresponding `AddressEntity`
cascade: true,
// Make sure when you use `preload`, `AddressEntity` of the user will also
// return (This means whenever you use any kind of `find` operations on
// `UserEntity`, it would load this entity as well)
eager: true
}
)
#JoinColumn()
address: AddressEntity;
}
Now using entityManager, you can update all the fields that you want using the following way:
const partialUserEntity = {
id: userId,
firstName: "Bob",
address: {
"city": "Ottawa"
}
};
const userRepository = await entityManager.getRepository(UserEntity);
// Here we load the current user entity value from the database and replace
// all the related values from `partialUserEntity`
const updatedUserEntity = userRepository.preload(partialUserEntity);
// Here we update (create if not exists) `updatedUserEntity` to the database
await userRepository.save(updatedUserEntity);
However, you need to make sure that your UserEntity has an AddressEntity associated always. Otherwise, you will have to generate an id for AddressEntity like below before you execute save method.
/*
* If `updatedUserEntity.address.id` is `undefined`
*/
// `generateIDForAddress` is a function which would return an `id`
const generatedIDForAddress = generateIDForAddress();
const partialUserEntity = {
id: userId,
firstName: "Bob",
address: {
"id": generatedIDForAddress,
"city": "Ottawa"
}
};
Please note that under the hood, typeorm will run UPDATE statements separately for UserEntity and AddressEntity. This is just an encapsulation of multiple join statements (when executing preload method) and update statements (when executing save method) such that the developer can easily implement this scenario.
Hope this helps you. Cheers 🍻!
How can I automatically append a property from a relation to the root object, as if it were a column from the same table but actually it is coming from another table.
Supose I have an User model that hasMany Emails.
How can I only append the email from the first Email of the User model, so that everytime I query the User model I get it like a property?
Example:
What I'm doing:
(await User.query().where('id', id).with('emails').first()).toJSON()
{
"name": "Eleandro Duzentos",
"emails": [
{ "email": "eleandro#inbox.ru" },
{ "email": "eleandro#mail.ru" }
]
}
What I want:
(await User.find(id)).toJSON()
{
"name": "Eleandro Duzentos",
"email": "eleandro#inbox.ru"
}
Obs: I'm not putting the email on the same table because, there's a chance that a user may need more then one email in a long future, but for now, it has only one.
How can I do that?
For the customized JSON response i would suggest the use of serializers.
You can override the default serializers to get the desired result.
You can refer to this - https://adonisjs.com/docs/4.0/serializers
Here is my code. You could be inspired by it:
Model User:
...
const Email = use('App/Models/Email')
class User extends Model {
async getEmails() {
let list = []
let emails = await Email.query().where('user_id', this.id).fetch()
emails.rows.forEach(email => {
list.push({ name: this.username, email: email.email })
});
return list
}
emails() {
return this.hasMany('App/Models/Email')
}
}
module.exports = User
Controller :
...
let user = await User.find(1)
return await user.getEmails()
Output :
[
{"name":"CrBast","email":"test#crbast.ch"},
{"name":"CrBast","email":"test2#crbast.ch"}
]
Feel free to correct me if that's not what you want :)
Does it consider security problem when I pass req.body directly to the database (I use mongoose and nodejs)?
Let's say I have a person schema (name: string, age: number) and in req.body, someone tries to add an extra field to it. Do I need to extract only field that I need before passing it to db
const {name, age} = req.body
const person = new Person({name, age})
person.save()...
OR this is ok because mongoose already take care of that
const person = new Person(req.body)
person.save()...
Note: I am asking about extra fields, not about whether or not we should santinize the field that declared in schema
No, it's not a security problem in itself.
And that's not related with Mongoose either. That's pure JavaScript.
You are using destructuring assignment on the req.body params, so you are extracting exactly specified arguments.
const body = { name: 'bob', age: 12, malicious_entry: "rm -rf" };
let {name, age} = body;
console.log(name, age, malicious_entry) // ReferenceError: malicious_entry is not defined
And if you pass it to a constructor:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
let {name, age, malicious_entry} = body;
let person = new Person(name, age, malicious_entry);
console.log(person) // Person { name: 'bob', age: 12 }
I let you choose if you want to record an internet request directly in your database without checking it, but clearly extra parameters are not the problem.
I am using the following code querying a dynamodb instance from within a node.js/express framework. The code is querying a table called User which has a hash key primary key of username with no range. It has no local secondary indexes, and 3 global secondary indexes (last_name-first_name, email_last-name, and company_[no range]).
I want to prevent duplicate usernames and duplicate email addresses. I can successfully prevent duplicate usernames but not duplicate email addresses. The docs state the
"ComparisonOperator": "NULL" or Exists: false lines should do it (they are mutually exclusive and I do NOT try them at same time). But, only the username validation is 'honored' by the AWS sdk, ie. the code below prevents duplicate usernames from being entered in to the system but duplicate email still occurs.
If I leave both "Expected:" keys out (username and email) the putitem simply adds a new record or updates the existing record with the same username (as documentation states and as I expect) but leaving both in, or just the email key in will NOT prevent duplicate emails in the database. Please help.
thanks
var d = new Date();
var dt = d.getTime();
params = {
TableName: 'User',
Expected: {
"username": {
Exists: false
// tried this also -> "ComparisonOperator": "NULL"
},
"email": {
Exists: false
// tried this also -> "ComparisonOperator": "NULL"
}
},
Item: {
username: {S: req.body.username},
created: {N: "" + dt + ""},
company: {S: req.body.company},
fname: {S: req.body.fname},
lname: {S: req.body.lname},
companies: {SS: [req.body.company]},
email: {S: req.body.email},
is_admin: {S: req.body.is_admin},
is_vendor: {S: req.body.is_vendor},
password: {S: req.body.pass}
}
};
dynamodb.putItem(params, function(err, data) {
var obj = new Object();
obj.data = {};
obj.data.username = req.body.username;
obj.data.fname = req.body.fname;
obj.data.lname = req.body.lname;
obj.data.company = req.body.company;
obj.data.email = req.body.email;
obj.data.is_admin = req.body.is_admin;
obj.data.is_vendor = req.body.is_vendor;
if (err) {
obj.status = "false";
obj.error = err;
}
else{
obj.status = "true";
}
res.send(JSON.stringify(obj));
});
I recommend first doing a query against the email index to check for existence of the email address before creating the new user.
It sounds like you are expecting the update condition to act as a global unique key constraint, similar to what a relational database might offer. DynamoDB only really enforces uniqueness on the primary key attributes. The update condition is only evaluated against the item attributes that are matched by the key. Your conditional update strategy works for username, since username is the primary hash key and a duplicate username would match the same row. The condition on email only guarantees that the email field is null on the one row that matches the username key.
Say I have a user domain class with fields username and password. For simplicity say I would like to store the passwords as a SHA-512 hash. I also want to validate the password prior to hashing it, but also transparently hash the password before saving it. Is there a way to do this in the domain object?
static constraints =
{
username(blank: false, unique: true);
password(minSize: 10);
}
Instead of saying:
def user = new User(username: "joe", password: createHash("joepass"));
where I can't validate the hash
def user = new User(username: "joe", password: "joepass");
if(user.validate())
{
user.save(); // Would then turn password into a hash on save
}
else
{
// Handle validation errors
}
Following GORM Events I've come up with the following:
def beforeInsert = { doHash(); }
def beforeUpdate = { doHash(); }
void doHash()
{
if(this.password.size() != 32)
{
this.password = this.password.encodeAsHash(); // I wrote a codec for this
}
}
Now this works fine when creating new users. However, if I create a user, give them a password, and save them, then change the password and re-save neither of these methods gets called and the plain test password gets stored.
Use the GORM Events
On the save or update events you can do the create hash
def beforeInsert = {
// do hash magic
}
def beforeUpdate = {
// do hash magic
}