Local storage variable scope per tab in Google Chrome extensions - google-chrome-extension

I wanted to store variables per tab scope. This same question was raised already and the suggestion was to use localStorage. But how to use localStorage to save associative arrays?
For example: A user is logging in a site. I want to create a variable to refer to that user. This way the user will open many tabs and he will log in to many sites. So I need to maintain the domain name and the user reference in localStorage, so if I use the username as a unique field then I can maintain an association with reference to the username, and finally I will need to store this information in the database.
So, how to maintain a data structure in a Google Chrome extension? The above is just an example, but it could be any case where we need the same variable name in various tabs with different values.
The documentation states to use JSON format. But still I want the users' suggestion on this.
So any kind of response will he helpful, like answers, suggestions, references and comments.

It is not very clear from your question what do you mean by "tab scope".
If you really need the tab scope, that is store values for this specific tab even when user navigates to a new site, then you can take tabid as a key (only tab id is not persistent between browser restarts).
If you actually mean "domain scope" - then it comes "for free" with content scripts. If you use localStorage inside a content script it would store the value only for this domain. You only need to make sure your keys don't collide with potential site's keys as the site might use the same localStorage.
If you are just asking how to create a data structure that would have domain names as keys, then it could be something like this:
var data = {};
data["google.com"] = {
username: "user1",
password: "pass1"
};
data["yahoo.com"] = {
username: "user2",
password: "pass2"
};
//store it
localStorage["data"] = JSON.stringify(data);
//load
data = JSON.parse(localStorage["data"]);
//read google username
console.log(data["google.com"].username);

Related

How to store multiple Profile Pictures in NodeJS & Mongodb?

I'm new to mongodb, so pls go easy.
Let's say that I am creating a website where, in creating profile, users can provide multiple profile images which would be presented in a way of carousel later when other check their profile. Let's say the first picture user uploaded should be the first image in the carousel.
And user are allowed to alter the order of images showing by dragging forward or backward in editing session in order to decide which image to be showed first. The key is the order is editable
According to what I learnt so far, I have created a simple document structure to store user's information as below, where username and profile_image were stored.
But, in this way, I am stuck with one picture only. May I know how should I alter the table, so that it allow to store multiple images, as well as the order of images.
May I know what I should do to implement my original function? Is it should be done by making another table to store order?
When I'm saying the order is editable, I'm saying something like this https://i2.wp.com/www.techjunkie.com/wp-content/uploads/2020/11/4-2-scaled.jpg?resize=690%2C1401&ssl=1
[ { username: 'username_1',
profile_image: 'path_of_the_image',
},
{ username: 'username_2',
profile_image: 'path_of_the_image',
}
]

How to pass a unique user ID to a page with user-specific, personal data

I'm sending a mass email though Emma (3rd party vendor) that will contain a link to a landing page. The landing page will be personalized and display some of the user's identifying info (name, title, email). Additionally, there will be a form collecting a few of the user's preferences that will be saved back to that user's record in Emma's database.
The user ID column in the 3rd party's database is incremental so I obviously can't just append that value through the query string otherwise user 522, for example, would get a link such as www.example.com?landing/?uid=522 allowing him (or anyone with the link)cto take a wild guess at other values for uid (such as 523... or 444) and change other users' preferences as well as view their personal data quite easily.
Bottom line is that I'm trying to find a secure way to pass an ID (or other unique value) that I can look up via API and use to dynamically display and then resubmit personal info/data on this landing page on a user-to-user basis.
I had an idea to add a custom column to my list in Emma for a unique identifier. I would then write a script (accessing Emma's API) to BASE64 Encode the ID (or possibly email address, as that would be unique as well) and add that to the list for each user. In my email, I could then pass that to the landing page in for the form of ?xy=ZGF2ZUBidWRvbmsuY29t, but I know this is encoding and not encrypting so not all that secure... or secure at all for that matter.
To my knowledge, there's no remote risk of anyone receiving the mailing having the ability and/or inclination to know what those extra characters in the link are, BASE64 Decode, BASE64 ENCODE another email address or integer an make a request with the newly BASE64 encoded value in order to manipulate my system in an an unintended way.
BUT for the purpose of this question, I'd like to know the "right" way to do this or what levels of security are currently being taken in similar circumstances. I've read about JWT tokens and some OOth stuff, but I'm not quite sure that's possible given that I've got the Emma API to deal with as well... and/or if that is overkill.
What is appropriate/standard for passing values to a page that are in turn used for a form to be resubmitted along with other user-supplied values when giving the user the ability to submit a "compromised" (intentionally or not) form could, at worst, could cause one of their competitors to have bad preference and opt-in saved data in our Emma mailing list?
Security on the web is all about "acceptable risk". You can reduce risk in various ways, but ultimately there's always some risk exposure you must be willing to accept.
Your very best option would be to force users to be logged-in to view the page, and to avoid using any querystring parameters. That way the backend for the page can pull the ID (or whatever it might need) out of the server's session.
Your next best option still involves forcing the user to be logged in, but leave the uid in the URL -- just be sure to validate that the user has access to the uid (i.e. don't let a user access another user's info).
If you can't do that... then you could create random keys/ids that you store in a database, and use those values (rather than uid or email or real data) in the URL. BUT let's be clear: this isn't secure, as it's technically possible to guess/deduce the scheme.
Absolutely DO NOT try passing the info in the URL as base64 encoded data, that's likely to be the first thing a hacker will figure out.
Keep in mind that any unsecured API that returns PII of any kind will be abused by automated tools... not just a user farting around with your form.
To my knowledge, there's no remote risk of anyone receiving the
mailing having the ability and/or inclination to know
^ That's always always always a bad assumption. Even if the result is at worst something you think is trivial, it opens the door for escalation attacks and literally exposes the company to risks it likely doesn't want to accept.
If you're stuck between bad options, my professional advice is to have a meeting where you record the minutes (either video, or in a document) and have someone with "authority" approve the approach you take.
In case anyone needs a working example, I found this at https://bhoover.com/using-php-openssl_encrypt-openssl_decrypt-encrypt-decrypt-data/. It uses PHP's openssl_encrypt and openssl_decrypt, and it seems to work perfectly for my purposes
<?php
$key = base64_encode(openssl_random_pseudo_bytes(32));
function my_encrypt($data, $key) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// Generate an initialization vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
// Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, 0, $iv);
// The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
return base64_encode($encrypted . '::' . $iv);
}
function my_decrypt($data, $key) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// To decrypt, split the encrypted data from our IV - our unique separator used was "::"
list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);
}
I first ran my_encrypt in a loop to encrypt the uid of each member in the list.
$members[$uid] = array('unique-identifier' => my_encrypt($uid, $key));
Next, through the API, I modified each member's record with the new value.
$ret = update_members_batch($members);
That only had to be done once.
Now in my email, I can pass the uid through the query string like this www.example.com/landing/?UID=<% unique-identifier %>, which will look something like www.example.com/landing/?UID= XXXXX2ovR2xrVmorbjlMMklYd0RNSDNPMUp0dmVLNVBaZmd3TDYyTjBFMjRkejVHRjVkSEhEQmlYaXVIcGxVczo6Dm3HmE3IxGRO1HkLijQTNg==
And in my page, I'll decrypt the query string value and use it via the API to get the email address with something like:
$member_email = get_member(my_decrypt($_GET['UID']))['email'];
and display it in the appropriate location(s) on my page.
I think this covers all my bases, but I am going to have a stakeholder meeting to get sign-off. What potential vulnerabilities does this expose that I should warn them about?

How to get data from other intent? (pass data for intents to other intents)

I'm making a actions on google project that will use basic functionality of remembering what the user says and using it for another intent.
So for example, this is what the conversation might look like:
1 User: Hello
2 Bot: Hey! What's your name?
3 User: Joel
4 Bot: Your name is Joel, is that correct?
5 User: Yes that is correct
6 Bot: Awesome, it's great to meet you Joel.
I know how to get the information initially, but I am having trouble with getting the information (the name 'Joel') passed to another intent that is used purely for confirmation.
Here is what I have:
app.intent('greeting', (conv, params) => {
const context = conv.contexts.set('context'); // working good
conv.ask(`I got ${params.name}, is that right?`);
});
app.intent('greeting_1', (conv,params) => {
const context1 = conv.contexts.get('context'); //not working
conv.ask(`Awesome, it's great to meet yoy ${params.name}`);
});
If this helps, specifically the error I'm getting reads:
TypeError: Cannot read property 'userDecision' of undefined
How do I get this to work? I have a feeling I have to save the data in userStorage but I've only really had to do that is very basic cases so I'm not to familiar with that.
Thanks for the help!
First of all, hi!
Your initial thought of storing the data in UserStorage might be correct depending on your use case. Let me elaborate:
Two Ways of Saving Data with Actions On Google Node.JS Client Library
Storing Data In A Conversation
You can use conv.data.name = 'Joel' to save the data between the turns of a conversation. But this data won't be available the next time user comes back.
Storing Data Permanently (As Long As The User Allows It)
This is where userStorage comes into play. You can use conv.user.storage.name = 'Joel' to remember the user's name every time they come back. Keep in mind that this type of permanent storage may require consent from the user depending on where they live.
Legal note: Obtaining consent prior to accessing userStorage. Some
countries have regulations that require developers to obtain consent
from the user before they can access, or save certain information
(e.g. personal information) in the userStorage. If you operate in one
of these countries and you want to access, or save such information in
userStorage, you must use the Confirmation helper to ask consent to
the user and obtain the consent before you can start storing such
information in userStorage.
You also need to explain the data you're saving in your Privacy Policy.
As for you specific use case, storing data that won't change (i.e. name) in userStorage is a much better method. Since if you only save it for one conversation, you'll need to ask for permission again the next time.
These should cover your basic needs of saving data on the platform. However, if you do need a more complex state management solution, you may want to check Dialogflow Contexts.
EDIT: I overlooked that you were already using contexts. But the answer still stands, you don't need to use contexts if all you want to do is to save data during a conversation.
But I think the reason you're having a problem is that you're not setting or getting the context parameters correctly. Take a look at the examples here and here:
The context.set() method gets three parameters; name, lifespan and parameters. You're only passing the name of the context in your code.
And, using only contexts.get() method isn't enough to read parameters of a context. You need to read them like this:
app.intent('Tell Greeting', conv => {
const context1 = conv.contexts.get('context1')
const { color, num } = context1.parameters
})
But, I repeat my original point. You shouldn't make things so complicated for yourself if you don't really need to. Try using conv.data and conv.user.storage if possible.

xpages open pages using [NRIC] Field

Question here, may i know using this way to open existing document is totally wrong, or i miss out some part?
Cuz currently not be able to open existing document.
Let say i already have the "document" inside with NRIC 851013-13-5125
Below is the code to get DocumentID
var vw:notesView = database.getView("Request sort by nric used for docID");
var doc:NotesDocument = vw.getDocumentByKey(document1.getValue("NRIC"), true)
if (doc!=null){
return doc.getItemValue("docID")
}
Desmond,
beside a HUGE security hole - displaying data based on an NRIC only (which is almost public data, since you use it everywhere to sign up for membership, discount cards etc.
You should change a few things:
Bind you entry box to a scope variable, not a document, so instead of document1.getValue("NRIC") you use viewScope.NRIC
You don't need to go after an item, but use doc.universalid, or better have that as a column in the view, so you could use #DbLookup(....)
Even better: you could simply redirect the URL to open /yourdb.nsf/byNRIC/[S12345678X] having a view byNRIC that is sorted by NRIC and has in the form property the XPage to open
Having said that: PLEASE(!!!) implement proper security. Singapore's legislation is VERY specific on data protection. You might want to read up on it here: https://www.pdpc.gov.sg/legislation-and-guidelines/overview

Sitecore Custom User Profile - where is it stored how can it be queried

I have created a custom User profile template and object in the core database in Sitecore (as per the Security API Cookbook).
I can select this programmatically (as per the Security API Cookbook) so that my extranet users have an extended profile, that covers all the usual suspects (Address, phone, email format etc.)
However, where is this data stored? And how do I access it if I want to query the database to return a subset of users based on this profile data.
A typical requirement for an extranet member system is to extract a list of users to contact either in an email or a phone type campaign. Can this be done with the Sitecore membership system?
UPDATE>
I'm going to take a guess and say the profile data is stored in aspnet_Profile.PropertyValuesBinary .. which would make it nigh on impossible to query and not suited to my purpose. That is unfortunate. So to extend my question, if that is the case, is it possible to get Sitecore to store those values in the text field so they are searchable?
The standard Microsoft implementation of the SqlProfileProvider (which is used in Sitecore by default) stores the user profile information in the aspnet_Profile table. All the properties are serialized into the PropertyNames / PropertyValuesString columns. The PropertyValuesBinary is used to store the binary data (images). You can find more details if you look at the code of System.Web.Profile.SqlProfileProvider, SetPropertyValues method.
Next, all the custom properties you define in the user profile, are serialized to the SerializedData property of the Profile class, and it is again serialized to the PropertyNames / PropertyValuesString columns like any other property.
Also, couple of properties are stored in aspnet_Membership table (for some reason) - Email and Comment.
So, if you are going to query the users by Email, you can use FindUsersByEmail method of MembershipProvider. Otherwise, if you plan to filter by another property value, I suppose, you'll have to get all users and filter the obtained collection.
Hope this helps.
I faced this exact problem last week, didn't come up with a permanent solution, but to solve my particular issue, I wrote a little helper page and added it as a Sitecore application to be accessed from the CMS interface. All it did was query all users, and determine if they had any of like 5-6 profile properties assigned.
var userList = Sitecore.Security.Accounts.UserManager.GetUsers();
That is the relevant line to grab the users, it returns Sitecore.Common.IFilterable
So if you need to do something where you're grabbing profile info from all users, you cn do something like this:
foreach (Sitecore.Security.Accounts.User user in userList)
{
Sitecore.Security.UserProfile profile = user.Profile;
string whatever = profile["Whatever"];
//add whatever to a list or something
}
This worked out very well for my purposes, but I don't know how feasible it will be in your situation.

Resources