StronglyUniversalStringHashing | Benchmark showing the we can randomly hash strings | Hashing library
kandi X-RAY | StronglyUniversalStringHashing Summary
Support
Quality
Security
License
Reuse
Currently covering the most popular Java, JavaScript and Python libraries. See a Sample Here
StronglyUniversalStringHashing Key Features
StronglyUniversalStringHashing Examples and Code Snippets
Trending Discussions on Hashing
Trending Discussions on Hashing
QUESTION
I am using Perceptual hashing technique to find near-duplicate and exact-duplicate images. The code is working perfectly for finding exact-duplicate images. However, finding near-duplicate and slightly modified images seems to be difficult. As the difference score between their hashing is generally similar to the hashing difference of completely different random images.
To tackle this, I tried to reduce the pixelation of the near-duplicate images to 50x50 pixel and make them black/white, but I still don't have what I need (small difference score).
This is a sample of a near duplicate image pair:
Image 1 (a1.jpg):
Image 2 (b1.jpg):
The difference between the hashing score of these images is : 24
When pixeld (50x50 pixels), they look like this:
rs_a1.jpg
rs_b1.jpg
The hashing difference score of the pixeled images is even bigger! : 26
Below two more examples of near duplicate image pairs as requested by @ann zen:
Pair 1
Pair 2
The code I use to reduce the image size is this :
from PIL import Image
with Image.open(image_path) as image:
reduced_image = image.resize((50, 50)).convert('RGB').convert("1")
And the code for comparing two image hashing:
from PIL import Image
import imagehash
with Image.open(image1_path) as img1:
hashing1 = imagehash.phash(img1)
with Image.open(image2_path) as img2:
hashing2 = imagehash.phash(img2)
print('difference : ', hashing1-hashing2)
ANSWER
Answered 2022-Mar-22 at 12:48Rather than using pixelisation to process the images before finding the difference/similarity between them, simply give them some blur using the cv2.GaussianBlur()
method, and then use the cv2.matchTemplate()
method to find the similarity between them:
import cv2
import numpy as np
def process(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
return cv2.GaussianBlur(img_gray, (43, 43), 21)
def confidence(img1, img2):
res = cv2.matchTemplate(process(img1), process(img2), cv2.TM_CCOEFF_NORMED)
return res.max()
img1s = list(map(cv2.imread, ["img1_1.jpg", "img1_2.jpg", "img1_3.jpg"]))
img2s = list(map(cv2.imread, ["img2_1.jpg", "img2_2.jpg", "img2_3.jpg"]))
for img1, img2 in zip(img1s, img2s):
conf = confidence(img1, img2)
print(f"Confidence: {round(conf * 100, 2)}%")
Output:
Confidence: 83.6%
Confidence: 84.62%
Confidence: 87.24%
Here are the images used for the program above:
img1_1.jpg
& img2_1.jpg
:
img1_2.jpg
& img2_2.jpg
:
img1_3.jpg
& img2_3.jpg
:
To prove that the blur doesn't produce really off false-positives, I ran this program:
import cv2
import numpy as np
def process(img):
h, w, _ = img.shape
img = cv2.resize(img, (350, h * w // 350))
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
return cv2.GaussianBlur(img_gray, (43, 43), 21)
def confidence(img1, img2):
res = cv2.matchTemplate(process(img1), process(img2), cv2.TM_CCOEFF_NORMED)
return res.max()
img1s = list(map(cv2.imread, ["img1_1.jpg", "img1_2.jpg", "img1_3.jpg"]))
img2s = list(map(cv2.imread, ["img2_1.jpg", "img2_2.jpg", "img2_3.jpg"]))
for i, img1 in enumerate(img1s, 1):
for j, img2 in enumerate(img2s, 1):
conf = confidence(img1, img2)
print(f"img1_{i} img2_{j} Confidence: {round(conf * 100, 2)}%")
Output:
img1_1 img2_1 Confidence: 84.2% # Corresponding images
img1_1 img2_2 Confidence: -10.86%
img1_1 img2_3 Confidence: 16.11%
img1_2 img2_1 Confidence: -2.5%
img1_2 img2_2 Confidence: 84.61% # Corresponding images
img1_2 img2_3 Confidence: 43.91%
img1_3 img2_1 Confidence: 14.49%
img1_3 img2_2 Confidence: 59.15%
img1_3 img2_3 Confidence: 87.25% # Corresponding images
Notice how only when matching the images with their corresponding images does the program output high confidence levels (84+%).
For comparison, here are the results without blurring the images:
import cv2
import numpy as np
def process(img):
h, w, _ = img.shape
img = cv2.resize(img, (350, h * w // 350))
return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
def confidence(img1, img2):
res = cv2.matchTemplate(process(img1), process(img2), cv2.TM_CCOEFF_NORMED)
return res.max()
img1s = list(map(cv2.imread, ["img1_1.jpg", "img1_2.jpg", "img1_3.jpg"]))
img2s = list(map(cv2.imread, ["img2_1.jpg", "img2_2.jpg", "img2_3.jpg"]))
for i, img1 in enumerate(img1s, 1):
for j, img2 in enumerate(img2s, 1):
conf = confidence(img1, img2)
print(f"img1_{i} img2_{j} Confidence: {round(conf * 100, 2)}%")
Output:
img1_1 img2_1 Confidence: 66.73%
img1_1 img2_2 Confidence: -6.97%
img1_1 img2_3 Confidence: 11.01%
img1_2 img2_1 Confidence: 0.31%
img1_2 img2_2 Confidence: 65.33%
img1_2 img2_3 Confidence: 31.8%
img1_3 img2_1 Confidence: 9.57%
img1_3 img2_2 Confidence: 39.74%
img1_3 img2_3 Confidence: 61.16%
QUESTION
I'm implementing my own class, with custom __eq__
. And I'd like to return True
for things that are not "equal" in a mathematical sense, but "match" in a fuzzy way.
An issue with this is, however, that this leads to loss of transitivity in a mathematical sense, i.e. a == b && b ==c
, while a
may not be equal to c
.
Question: is Python dependent on __eq__
being transitive? Will what I'm trying to do break things, or is it possible to do this as long as I'm careful myself not to assume transitivity?
I want to match telephone numbers with one another, while those may be either formatted internationally, or just for domestic use (without a country code specified). If there's no country code specified, I'd like a number to be equal to a number with one, but if it is specified, it should only be equal to numbers with the same country-code, or without one.
So:
- Of course,
+31 6 12345678
should equal+31 6 12345678
, and06 12345678
should equal06 12345678
+31 6 12345678
should equal06 12345678
(and v.v.)+49 6 12345678
should equal06 12345678
(and v.v.)- But
+31 6 12345678
should not be equal to+49 6 12345678
Edit: I don't have a need for hashing (and so won't implement it), so that at least makes life easier.
ANSWER
Answered 2022-Mar-14 at 18:06There is no MUST but a SHOULD relation for comparisons being consistent with the commonly understood relations. Python expressively does not enforce this and float
is an inbuilt type with different behaviour due to float("nan")
.
Expressions: Value comparisons[…]
User-defined classes that customize their comparison behavior should follow some consistency rules, if possible:
- […]
- Comparison should be symmetric. In other words, the following expressions should have the same result:
x == y
andy == x
x != y
andy != x
x < y
andy > x
x <= y
andy >= x
- Comparison should be transitive. The following (non-exhaustive) examples illustrate that:
- x > y and y > z implies x > z
- x < y and y <= z implies x < z
Python does not enforce these consistency rules. In fact, the not-a-number values are an example for not following these rules.
Still, keep in mind that exceptions are incredibly rare and subject to being ignored: most people would treat float
as having total order, for example. Using uncommon comparison relations can seriously increase maintenance effort.
Canonical ways to model "fuzzy matching" via operators are as subset, subsequence or containment using unsymmetric operators.
- The
set
andfrozenset
support>
,>=
and so on to indicate that one set encompases all values of another.
>>> a, b = {1, 5, 6, 8}, {5, 6}
>>> a >= a, a >= b, b >= a
(True, True, False)
str
and bytes
support in
to indicate that subsequences are covered. >>> a, b = "+31 6 12345678", "6 12345678"
>>> a in b, b in a
(False, True)
range
and ipaddress
Networks support in
to indicate that specific items are covered. >>> IPv4Address('192.0.2.6') in IPv4Network('192.0.2.0/28')
True
Notably, while these operators may be transitive they are not symmetric. For example, a >= b and c >= b
does not imply b >= c
and thus not a >= c
or vice versa.
Practically, one could model "number without country code" as the superset of "number with country code" for the same number. This means that 06 12345678 >= +31 6 12345678
and 06 12345678 >= +49 6 12345678
but not vice versa. In order to do a symmetric comparison, one would use a >= b or b >= a
instead of a == b
.
QUESTION
I know that in hashing you, by definition, lose information. However, as email addresses can be restricted - such as with the information available I would know a potential domain of the email, and that it must have an @. Do these constraints change anything about the problem? Or is the best way to simply make a guess and see if the hash is the same? Also MD5 is no longer as secure as it once was.
Thanks
ANSWER
Answered 2022-Feb-15 at 15:55That is the point of Md5 hashing that even a minute change in the string can change the hash completely. So these constraints change nothing about the problem.
However since you said that its an email and that you know about the potential domain then you can try this technique.
- Generate a list of potential emails it will be within 26 letters and lets say of maximum size 10.
Then you can generate an md5 for all of these possibilities and check if it is equal to the one you have.
import hashlib
from itertools import combinations
import time
start=time.time()
your_md5_hash='your_md5_hash'
letters='abcdefghijklmnopqrstuvwxyz'
possible_words=[]
for r in range(1,10): #change 10 to the maximum size of your email
for combo in combinations(list(letters), r=r):
res=''.join(combo)
possible_words.append(res)
possible_words=[''.join(x)+'@domain.com' for x in possible_words]
print (len(possible_words))
for x in possible_words:
res=hashlib.md5(x.encode())
if res==your_md5_hash:
print (res)
print (x)
print ("RESULT_FOUND")
exit(0)
print (time.time()-start)
This is brute force approach and if you know the size of your email then this could work. Secondly please note that if you do not know the size then the size of possibilities will increase exponentially.
For instance the length of combinations as of now is 5658536 and it took my basic laptop 6 seconds to process.
QUESTION
I'm trying to learn Go while writing a small program. The program should parse a PATH recursivelys as efficient and fast as possible and output the full filename (with the path included) and the sha256 file hash of the file.
If the file hashing generates fails, I wanna keep the error and add it to the string (at the hash position).
The result should return a string on the console like: fileXYZ||hash
Unfortunately, the programs hangs at some point. I guess some of my channels are not closing properly and waiting indefinitely for input. I've been trying for quite some time to fix the problem, but without success.
Does anyone have an idea why the output hangs? Many many thx in advance, any input/advice for a Go newcomer is welcome too ;-).
(I wrote separate functions as I wanna add additional features after having fixed this issue.)
Thanks a lot! Didier
Here is the code:
import (
"crypto/sha256"
"encoding/hex"
"flag"
"fmt"
"io"
"log"
"os"
"path/filepath"
"time"
)
func main() {
pathParam := flag.String("path", ".", "Enter Filesystem Path to list folders")
flag.Parse()
start := time.Now()
run(*pathParam)
elapsed := time.Since(start)
log.Printf("Time elapsed: %v", elapsed)
}
func run(path string) {
chashes := make(chan string, 50)
cfiles := make(chan string)
go func() {
readfs(path, cfiles)
defer close(cfiles)
}()
go func() {
generateHash(cfiles, chashes)
}()
defer close(chashes)
for hash := range chashes {
fmt.Println(hash)
}
}
func readfs(path string, cfiles chan string) {
files, err := os.ReadDir(path)
if err != nil {
log.Fatalln(err)
}
for _, file := range files {
filename := filepath.Join(path, file.Name())
if file.IsDir() {
readfs(filename, cfiles)
continue
} else {
cfiles <- filename
}
}
}
func generateHash(cfiles chan string, chashes chan string) {
for filename := range cfiles {
go func(filename string) {
var checksum string
var oError bool = false
file, err := os.Open(filename)
if err != nil {
oError = true
errorMsg := "ERROR: " + err.Error()
log.Println(errorMsg)
checksum = errorMsg
}
defer file.Close()
if !oError {
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
errorMsg := "ERROR: " + err.Error()
log.Println(errorMsg)
checksum = errorMsg
}
if len(checksum) == 0 {
checksum = hex.EncodeToString(hash.Sum(nil))
}
}
chashes <- filename + "||" + checksum
}(filename)
} //for files
}
ANSWER
Answered 2022-Jan-29 at 19:46The following loop hangs because chashes
is not closed.
for hash := range chashes {
fmt.Println(hash)
}
Fix by closing chashes
after all the hashers are completed. Use a sync.WaitGroup to wait for the hashers to complete.
func generateHash(cfiles chan string, chashes chan string) {
var wg sync.WaitGroup
for filename := range cfiles {
wg.Add(1)
go func(filename string) {
defer wg.Done()
var checksum string
var oError bool = false
file, err := os.Open(filename)
if err != nil {
oError = true
errorMsg := "ERROR: " + err.Error()
log.Println(errorMsg)
checksum = errorMsg
}
defer file.Close()
if !oError {
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
errorMsg := "ERROR: " + err.Error()
log.Println(errorMsg)
checksum = errorMsg
}
if len(checksum) == 0 {
checksum = hex.EncodeToString(hash.Sum(nil))
}
}
chashes <- filename + "||" + checksum
}(filename)
} //for files
// Wait for the hashers to complete.
wg.Wait()
// Close the channel to cause main() to break
// out of for range on chashes.
close(chashes)
}
Remove defer close(chashes)
from run()
.
QUESTION
Assume we have two tables (think as in SQL tables), where the primary key in one of them is the foreign key in the other. I'm supposed to write a simple algorithm that would imitate the joining of these two tables. I thought about iterating over each element in the primary key column in the first table, having a second loop where it checks if the foreign key matches, then store it in an external array or list. However, this would take O(N*M) and I need to find something better. There is a hint in the textbook that it involves hashing, however, I'm not sure how hashing could be implemented here or how it would make it better?
Editing to add an example:
Table Employees
|ID (Primary Key)| Name | Department|
|:---------------|:----:|----------:|
| 1 | Jack | IT |
| 2 | Amy | Finance |
Table Transactions
|Sold Product| Sold By(Foreign Key)| Sold To|
|:-----------|:-------------------:|-------:|
| TV | 1 | Mary |
| Radio | 1 | Bob |
| Mobile | 2 | Lisa |
What I want to do is write an algorithm that joins these two tables using hashing, and not anything complex, just a simple idea on how to do that.
ANSWER
Answered 2021-Dec-24 at 22:18Read the child table's primary and foreign keys into a map where the keys are the foreign keys and the values are the primary keys. Keep in mind that one foreign key can map to multiple primary keys if this is a one to many relationship.
Now iterate over the primary keys of the mother table and for each primary key check whether it exists in the map. If so, you add a tuple of the primary keys of the rows that have a relation to the array (or however you want to save it).
The time complexity is O(n + m)
. Iterate over the rows of each table once. Since the lookup in the map is constant, we don't need to add it.
Space complexity is O(m)
where m
is the number of rows in the child table. This is some additional space you use in comparison to the naive solution to improve the time complexity.
QUESTION
I'm seeking advice from people deeply familiar with the binary layout of Apache Parquet:
Having a data transformation F(a) = b
where F
is fully deterministic, and same exact versions of the entire software stack (framework, arrow & parquet libraries) are used - how likely am I to get an identical binary representation of dataframe b
on different hosts every time b
is saved into Parquet?
In other words how reproducible Parquet is on binary level? When data is logically the same what can cause binary differences?
- Can there be some uninit memory in between values due to alignment?
- Assuming all serialization settings (compression, chunking, use of dictionaries etc.) are the same, can result still drift?
I'm working on a system for fully reproducible and deterministic data processing and computing dataset hashes to assert these guarantees.
My key goal has been to ensure that dataset b
contains an idendital set of records as dataset b'
- this is of course very different from hashing a binary representation of Arrow/Parquet. Not wanting to deal with the reproducibility of storage formats I've been computing logical data hashes in memory. This is slow but flexible, e.g. my hash stays the same even if records are re-ordered (which I consider an equivalent dataset).
But when thinking about integrating with IPFS
and other content-addressable storages that rely on hashes of files - it would simplify the design a lot to have just one hash (physical) instead of two (logical + physical), but this means I have to guarantee that Parquet files are reproducible.
I decided to continue using logical hashing for now.
I've created a new Rust crate arrow-digest that implements the stable hashing for Arrow arrays and record batches and tries hard to hide the encoding-related differences. The crate's README describes the hashing algorithm if someone finds it useful and wants to implement it in another language.
I'll continue to expand the set of supported types as I'm integrating it into the decentralized data processing tool I'm working on.
In the long term, I'm not sure logical hashing is the best way forward - a subset of Parquet that makes some efficiency sacrifices just to make file layout deterministic might be a better choice for content-addressability.
ANSWER
Answered 2021-Dec-05 at 04:30At least in arrow's implementation I would expect, but haven't verified the exact same input (including identical metadata) in the same order to yield deterministic outputs (we try not to leave uninitialized values for security reasons) with the same configuration (assuming the compression algorithm chosen also makes the deterministic guarantee). It is possible there is some hash-map iteration for metadata or elsewhere that might also break this assumption.
As @Pace pointed out I would not rely on this and recommend against relying on it). There is nothing in the spec that guarantees this and since the writer version is persisted when writing a file you are guaranteed a breakage if you ever decided to upgrade. Things will also break if additional metadata is added or removed ( I believe in the past there have been some big fixes for round tripping data sets that would have caused non-determinism).
So in summary this might or might not work today but even if it does I would expect this would be very brittle.
QUESTION
I have an Angular 12 application that has different build environments (dev/staging/prod) and I have configured these with output hashing on in angular.json
:
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all" <-----
The output files do include a hash, but I am still seeing the old version unless I do a hard refresh in the browser.
main.07258fce7f84f8b6013e.js
polyfills.4cc5b416b55531e38cd8.js
runtime.734c276f75a5d81bc54b.js
The landing page is just a login form but the version is shown beneath the form. It shows the old version until the hard-refresh in the browser, at which point it correctly shows the new version.
Is this due to index.html
being cached along with all of it's old JS references?
If so how do I cache bust this?
ANSWER
Answered 2021-Nov-25 at 08:51In case you're using a service worker (eg @angular/pwa
which installs @angular/service-worker
along), you're entire angular app is being cached by the browser. This includes index.html
+ all javascript files + all stylesheets.
To have a new version of your application pushed to your users, you have to do 2 things:
Update your ngsw-config.json
on each new release:
{
"version": 1, // Or ascending
...
}
Call SwUpdate
:
constructor(private swUpdate: SwUpdate) {
...
//#region Check for updates
if (this.swUpdate.isEnabled) {
this.swUpdate.activated.subscribe((upd) => {
window.location.reload();
});
this.swUpdate.available.subscribe((upd) => {
this.swUpdate.activateUpdate();
}, (error) => {
console.error(error);
});
this.swUpdate.checkForUpdate().then(() => {
}).catch((error) => {
console.error('Could not check for app updates', error);
});
}
//#endregion
}
QUESTION
Trying to understand how to get and then save user in client (using JWT token in Http only cookie), so that I can do conditional rendering. What I'm having difficulty with is how to continously know if the user is logged in or not, without having to send a request to the server each time the user changes/refresh page. (Note: the problem is not how do I get the token in the Http only cookie, I know that this is done through withCredentials: true
)
So my problem is how do you get/store the access token so that the client will not have to make a request to the server each time the user does something on the website. For example the Navbar should do conditional renderingen depending on if the user is logged in or not, then I don't want to do "ask the server if the user has a access token, then if not check if user has refresh token, then return a new access token if true else redirect to login page" every single time the user switches page.
Client:
UserContext.js
import { createContext } from "react";
export const UserContext = createContext(null);
App.js
const App = () => {
const [context, setContext] = useState(null);
return (
);
};
export default App;
Profile.js
import { GetUser } from "../api/AuthenticateUser";
const Profile = () => {
const { context, setContext } = useContext(UserContext);
return (
{context}
GetUser()}>Change context
);
};
export default Profile;
AuthenticateUser.js
import axios from "axios";
export const GetUser = () => {
try {
axios
.get("http://localhost:4000/get-user", {
withCredentials: true,
})
.then((response) => {
console.log(response);
});
} catch (e) {
console.log(`Axios request failed: ${e}`);
}
};
Server:
AuthenticateUser.js
const express = require("express");
const app = express();
require("dotenv").config();
const cors = require("cors");
const mysql = require("mysql");
const jwt = require("jsonwebtoken");
const cookieParser = require("cookie-parser");
// hashing algorithm
const bcrypt = require("bcrypt");
const salt = 10;
// app objects instantiated on creation of the express server
app.use(
cors({
origin: ["http://localhost:3000"],
methods: ["GET", "POST"],
credentials: true,
})
);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
const db = mysql.createPool({
host: "localhost",
user: "root",
password: "password",
database: "mysql_db",
});
//create access token
const createAccessToken = (user) => {
// create new JWT access token
const accessToken = jwt.sign(
{ id: user.id, email: user.email },
process.env.ACCESS_TOKEN_SECRET,
{
expiresIn: "1h",
}
);
return accessToken;
};
//create refresh token
const createRefreshToken = (user) => {
// create new JWT access token
const refreshToken = jwt.sign(
{ id: user.id, email: user.email },
process.env.REFRESH_TOKEN_SECRET,
{
expiresIn: "1m",
}
);
return refreshToken;
};
// verify if user has a valid token, when user wants to access resources
const authenticateAccessToken = (req, res, next) => {
//check if user has access token
const accessToken = req.cookies["access-token"];
// if access token does not exist
if (!accessToken) {
return res.sendStatus(401);
}
// check if access token is valid
// use verify function to check if token is valid
jwt.verify(accessToken, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
return next();
});
};
app.post("/token", (req, res) => {
const refreshToken = req.cookies["refresh-token"];
// check if refresh token exist
if (!refreshToken) return res.sendStatus(401);
// verify refresh token
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(401);
// check for refresh token in database and identify potential user
sqlFindUser = "SELECT * FROM user_db WHERE refresh_token = ?";
db.query(sqlFindUser, [refreshToken], (err, user) => {
// if no user found
if (user.length === 0) return res.sendStatus(401);
const accessToken = createAccessToken(user[0]);
res.cookie("access-token", accessToken, {
maxAge: 10000*60, //1h
httpOnly: true,
});
res.send(user[0]);
});
});
});
/**
* Log out functionality which deletes all cookies containing tokens and deletes refresh token from database
*/
app.delete("/logout", (req, res) => {
const refreshToken = req.cookies["refresh-token"];
// delete refresh token from database
const sqlRemoveRefreshToken =
"UPDATE user_db SET refresh_token = NULL WHERE refresh_token = ?";
db.query(sqlRemoveRefreshToken, [refreshToken], (err, result) => {
if (err) return res.sendStatus(401);
// delete all cookies
res.clearCookie("access-token");
res.clearCookie("refresh-token");
res.end();
});
});
// handle user sign up
app.post("/sign-up", (req, res) => {
//request information from frontend
const { first_name, last_name, email, password } = req.body;
// hash using bcrypt
bcrypt.hash(password, salt, (err, hash) => {
if (err) {
res.send({ err: err });
}
// insert into backend with hashed password
const sqlInsert =
"INSERT INTO user_db (first_name, last_name, email, password) VALUES (?,?,?,?)";
db.query(sqlInsert, [first_name, last_name, email, hash], (err, result) => {
res.send(err);
});
});
});
/*
* Handel user login
*/
app.post("/sign-in", (req, res) => {
const { email, password } = req.body;
sqlSelectAllUsers = "SELECT * FROM user_db WHERE email = ?";
db.query(sqlSelectAllUsers, [email], (err, user) => {
if (err) {
res.send({ err: err });
}
if (user && user.length > 0) {
// given the email check if the password is correct
bcrypt.compare(password, user[0].password, (err, compareUser) => {
if (compareUser) {
//req.session.email = user;
// create access token
const accessToken = createAccessToken(user[0]);
const refreshToken = createRefreshToken(user[0]);
// create cookie and store it in users browser
res.cookie("access-token", accessToken, {
maxAge: 10000*60, //1h
httpOnly: true,
});
res.cookie("refresh-token", refreshToken, {
maxAge: 2.63e9, // approx 1 month
httpOnly: true,
});
// update refresh token in database
const sqlUpdateToken =
"UPDATE user_db SET refresh_token = ? WHERE email = ?";
db.query(
sqlUpdateToken,
[refreshToken, user[0].email],
(err, result) => {
if (err) {
res.send(err);
}
res.sendStatus(200);
}
);
} else {
res.send({ message: "Wrong email or password" });
}
});
} else {
res.send({ message: "Wrong email or password" });
}
});
});
app.get("/get-user", (req, res) => {
const accessToken = req.cookies["acceess-token"];
const refreshToken = req.cookies["refresh-token"];
//if (!accessToken && !refreshToken) res.sendStatus(401);
// get user from database using refresh token
// check for refresh token in database and identify potential user
sqlFindUser = "SELECT * FROM user_db WHERE refresh_token = ?";
db.query(sqlFindUser, [refreshToken], (err, user) => {
console.log(user);
return res.json(user);
});
});
app.listen(4000, () => {
console.log("running on port 4000");
});
I began experimenting with useContext as you can see in the client code above. My initial idea was to use useEffect in the App component where I make a call to the function GetUser() which makes a request to "/get-user" which will user the refreshToken to find the user (don't know if it is bad practice to use refreshToken to find user in db, maybe I should store access token in db as well and use it to find user in db instead?) and then save things like id, first name, last name and email so that it may be displayed in the navbar or any other component if necessary.
However, I don't know if this is the right thing to do as I have heard a lot about using localStorge, memory or sessionStorage is better for keeping the JWT access token in, while you should keep the refresh token in the server and save it in the mySQL database I have created, only to be used once the user has lost their access token. How should I get access to my access token and how do I keep track of the user logged in? Do I really need to do a request to the server each time the user switches page or refresh page?
Also I have a question about when I should be calling "/token" in the server to create new access tokens. Should I always try to use the access token to do things that require authentication and if it for example returns null
at some point then I make request to "/token" and after that repeat what the user was trying to do?
ANSWER
Answered 2021-Nov-16 at 08:54Do I really need to do a request to the server each time the user switches page or refresh page?
That is the safest way. If you want to keep with the current security best practices for SPAs, then using http-only, secure, same-site cookies is the best option. Refreshes won't happen that often on your page, so it shouldn't be a problem.
My initial idea was to use useEffect in the App component where I make a call to the function GetUser() which makes a request to "/get-user" which will user the refreshToken to find the user
What I would do is to first verify the access token, if it's valid then take the userId out of the access token (if you don't have it there you can easily add it as you're creating the tokens manually) and read the user data from the database. If the access token is invalid then return an error to the website and let the user use the refresh token to get a new access token. So I wouldn't mix responsibilities here - I wouldn't use refresh token to get information about the logged in user.
Also I have a question about when I should be calling "/token" in the server to create new access tokens. Should I always try to use the access token to do things that require authentication and if it for example returns null at some point then I make request to "/token" and after that repeat what the user was trying to do?
Yes, that's how it usually is implemented. You make a call with the access token to a protected endpoint. It would be best if the endpoint returned 401 response if the token is expired or invalid. Then your app knows that it should use the refresh token to get a new access token. Once you have a new access token you try to make the call to the protected endpoint again. If you don't manage to get a new access token (e.g. because the refresh token has expired), then you ask the user to log in again.
QUESTION
I need web app with base url as
https://example.com/mojjo-test/index.html#/
I updated my base url as documented in flutter website: https://flutter.dev/docs/development/ui/navigation/url-strategies
in index.html
As per flutter documentation Hashing is already enabled
Observations:
1.Flutter web app loads, shows url while loading,
http://example.com/mojjo-test/index.html
2.And after some seconds it redirects to
http://example.com/mojjo-test/#/
- Now if we do a refresh, browser will try to load
http://example.com/mojjo-test/#/
and shows an access denied
I am assuming that instead of redirecting to http://example.com/mojjo-test/#/
, it should redirect to http://example.com/mojjo-test/index.html#/
Please provide suggestions on how to achieve it. I would like to keep the initial path to be https://example.com/mojjo-test/index.html#/
(with index.html)
ANSWER
Answered 2021-Oct-22 at 07:31I'd advice you commenting out href
in 'web/index.html' (platform project automatically generated when adding Web). That's how I did it: https://github.com/maxim-saplin/flutter_web_spa_sample/blob/main/web/index.html
And here's the example of this app working under virtual directory: https://maxim-saplin.github.io/flutter_web_spa_sample/html/#/
Flutter Web somehow has these silly issues in scaffolding for the web project (href
in index.html, wrong paths for service worker etc.) - discovered this while playing with GitHub pages.
QUESTION
I have an Ionic project I'm working with that is having trouble building to Android. I inherited this project, so that's why I'm not 100% familiar with Fastlane and how it's building the java files. Additionally, I'm on WSL2 and using sdkmanager with the following installed packages:
Installed packages:=====================] 100% Fetch remote repository...
Path | Version | Description | Location
------- | ------- | ------- | -------
build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2
emulator | 30.8.4 | Android Emulator | emulator
patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4
platform-tools | 31.0.3 | Android SDK Platform-Tools | platform-tools
platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29
When I run bundle exec fastlane android build
it does a whole lot of magic, but in the end, results in the following error:
> Task :app:compileReleaseJavaWithJavac FAILED
/home/zonyx/git/gitlab/studio/platforms/android/app/src/main/java/org/apache/cordova/camera/CameraLauncher.java:42: error: package android.support.v4.content does not exist
import android.support.v4.content.FileProvider;
^
/home/zonyx/git/gitlab/studio/platforms/android/app/src/main/java/org/apache/cordova/camera/FileProvider.java:21: error: package android.support.v4.content does not exist
public class FileProvider extends android.support.v4.content.FileProvider {}
^
/home/zonyx/git/gitlab/studio/platforms/android/app/src/main/java/org/apache/cordova/camera/CameraLauncher.java:297: error: cannot find symbol
this.imageUri = FileProvider.getUriForFile(cordova.getActivity(),
^
symbol: method getUriForFile(Activity,String,File)
location: class FileProvider
/home/zonyx/git/gitlab/studio/platforms/android/app/src/main/java/org/apache/cordova/camera/CameraLauncher.java:824: error: cannot find symbol
Uri tmpFile = FileProvider.getUriForFile(cordova.getActivity(),
^
symbol: method getUriForFile(Activity,String,File)
location: class FileProvider
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
4 errors
I've seen some thoughts about newer SDK versions using androidx.core.content.FileProvider
instead of android.support.v4.content.FileProvider
. Since the entire Android portion is built / generated automatically, I obviously can't change the java file because it will just get overwritten.
Here's a line of the Fastfile that may be helpful:
desc 'Compile a new build for Android'
lane :build do |options|
Dir.chdir('..') do
before_build(options)
ionic_build
sh("ionic cordova build android --device --release --aot false --environment prod --output-hashing all \
--sourcemaps false --extract-css true --named-chunks false --build-optimizer true --minifyjs=true \
--minifycss=true --optimizejs=true")
deeplinks(action: 'uninstall')
end
end
ANSWER
Answered 2021-Sep-19 at 15:32cordova-plugin-androidx-adapter will migrate older libraries to use AndroidX Support Libraries automatically. I believe this is needed when you target Android 10 or higher, which is when the switch was made. Once all of your plugins support AndroidX, you can remove the adapter plugin.
Community Discussions, Code Snippets contain sources that include Stack Exchange Network
Vulnerabilities
No vulnerabilities reported
Install StronglyUniversalStringHashing
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