Public Key Encryption in Microsoft Edge - encryption

I have the following JavaScript code to implement public key encryption using the Web Cryptography API. It works for Firefox and Chrome but fails for Microsoft Edge. The error I am getting from Edge is "Could not complete the operation due to error 80700011." What have I missed?
<script>
var data = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
var crypto = window.crypto || window.msCrypto;
var cryptoSubtle = crypto.subtle;
cryptoSubtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: { name: "SHA-256" },
},
true,
["encrypt", "decrypt"]
).then(function (key) {
console.log(key);
console.log(key.publicKey);
return cryptoSubtle.encrypt(
{
name: "RSA-OAEP"
},
key.publicKey,
data
);
}).then(function (encrypted) {
console.log(new Uint8Array(encrypted));
}).catch(function (err) {
console.error(err);
});
</script>

I've found the cause of this issue. I have to add the hash field when invoking the encrypt function:
return cryptoSubtle.encrypt(
{
name: "RSA-OAEP",
hash: { name: "SHA-256" }
},
key.publicKey,
data
);
This does not match the Web Cryptography API Spec but it works.

Same problem with crypto.subtle.sign. Needed to add the hashing algorithm (same issue in Safari)
Replace
crypto.subtle.sign(
{
name: "RSASSA-PKCS1-v1_5"
},
cryptoKey,
digestToSignBuf);
with
crypto.subtle.sign(
{
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256"
},
cryptoKey,
digestToSignBuf);

Related

How to fix 'RealmObject cannot be called as a function' realm-js error?

In a react-native project using Realm-js, I've just created a clone of the app, integrated all libs, and copied over all src directories.
The app builds installs and runs on Android.
When i go through the authentication flow (which utilizes realm to store auth data), i ultimately get an error:
[ Error: RealmObject cannot be called as a function ]
login function:
async function login(username, password) {
try {
const result = await Api.login({
username: username,
pass: password,
});
const userAuthResult = await Db.updateAuth(result);
setUserAuth(userAuthResult);
} catch (err) {
console.log('[ ERROR ]:', err)
if (!err.message || err.message.includes('Network Error')) {
throw new Error('Connection error');
}
throw new Error('Wrong username or password');
}
}
and ive narrowed down the issue to Db.updateAuth(...)
updateAuth:
export const updateAuth = (params) => {
console.log(' [ HERE 1 ]')
const auth = {
id: params.id,
token: params.token,
refreshToken: params.refresh_token,
tokenExpiresAt: Math.floor(Date.now() / 1000) + 600, //params.expires_at,
federatedToken: params.federatedToken ?? '',
federatedTokenExpiresAt: params.federatedTokenExpiresAt ?? 0,
username: params.username,
name: params.name,
roleName: params.role_name,
roleId: params.role_id,
lastLogin: Math.floor(Date.now() / 1000),
};
console.log(' [ HERE 2 ]')
realm.write(() => {
console.log(' [ HERE 3 ]')
realm.create('Authorizations', auth, 'modified'); // PROBLEM
});
return auth;
};
inspecting the schema, i found theres no federatedToken propereties, yet in the auth update object, there are two. not sure why it wouldnt be throwing an error in the original non-cloned app.
authorizations schema:
AuthorizationsSchema.schema = {
name: 'Authorizations',
primaryKey: 'id',
properties: {
id: 'int',
token: 'string',
refreshToken: 'string',
tokenExpiresAt: 'int',
username: 'string',
name: 'string',
roleName: 'string',
roleId: 'int',
lastLogin: 'int',
},
};
Realm.js (class declaration) -> https://pastebin.pl/view/c903b2e2
from realm instantiation:
let realm = new Realm({
schema: [
schema.AccountSchema,
schema.AuthorizationsSchema,
schema.AvailableServiceSchema,
schema.FederatedTokensSchema,
schema.NoteSchema,
schema.PhotoSchema,
schema.PhotoUploadSchema,
schema.PrintQueueSchema,
schema.ProductSchema,
schema.ReportSchema,
schema.ServicesSchema,
schema.UploadQueueJobSchema,
schema.InvoicesSchema,
schema.TestSchema
],
schemaVersion: 60,
deleteRealmIfMigrationNeeded: true,
//path: './myrealm/data',
});
this logs the 1, 2, and 3 statements. The issue seems to come from the 'problem' line. Im not sure what exactly this error means, as there doesnt seem to be anything in realm's repo about it, and in the app this was cloned from, there was no issue with this line. I can also see other lines are throwing similar errors later on the user flows
Anyone know what this is about? or where i can learn more?
React-native: v64.2
realm-js: 10.6.0 (app cloned from was v10.2.0)
MacOS: 11.3 (M1 architecture)
in order to create you have the first call, the realm.write a method like this.
const storeInDataBase = (res,selectedfile) => {
try{
realm.write(() => {
var ID =
realm.objects(DocumentConverstionHistory).sorted('HistoryID', true).length > 0
? realm.objects(DocumentConverstionHistory).sorted('HistoryID', true)[0]
.HistoryID + 1
: 1;
realm.create(DocumentConverstionHistory, {
HistoryID: ID,
Name:`${selectedfile.displayname}.pdf`,
Uri:`file://${res.path()}`,
Date: `${new Date()}`
});
})
}catch(err){
alert(err.message)
}
}
Here is the schema file
export const DATABASENAME = 'documentconverter.realm';
export const DocumentConverstionHistory = "DocumentConverstionHistory"
export const DocumentConverstionHistorySchema = {
name: "DocumentConverstionHistory",
primaryKey: 'HistoryID',
properties: {
HistoryID: {type: 'int'},
Name: {type: 'string'},
Uri: {type: 'string?'},
Type: {type: 'string?'},
Size: {type: 'string?'},
Date: {type: 'date?'}
}
};

how to get JSON data in from firebase, and then use it in angular 6, firebase return the data with value tag

I am using firebase functions to get data from db, this is how I am doing it,
exports.getTopPlayers = (request,response)=> {
SavePlayers(function(data,err){
if(err) console.log(err);
response.header('Access-Control-Allow-Origin', '*');
response.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
const dbRef = admin.database().ref().child('topplayers/-LISMykRqLrVcc7xrK60');
dbRef.on('value', snap => {
var dbPlayer = snap.val();
response.send(dbPlayer);
});
});
Then I am using it in my website built in angular 6
getTopPlayers() {
return this.http.get(this.topPlayerURL);
}
It the be data in the below format,
{value: "[{"name":"WHYALWAYSME","tag":"9P08LYLL","rank":1,"…na":"League 8","arenaID":20,"trophyLimit":6100}}]"}
I want to get rid of this value tag. How can I? When I try to loop on this using
ngFor (*ngFor="let tp of topPlayer$) it return error, Cannot loop
[object,object]
I want the data in the below format,
[
{
name: "Leslie",
tag: "RPP89PVY",
rank: 1,
previousRank: 3,
expLevel: 13,
trophies: 6361,
donationsDelta: null,
clan: {
tag: "9CU2PQ2J",
name: "不正经的养老院",
badge: {
name: "Cherry_Blossom_04",
category: "01_Symbol",
id: 16000131,
image: "https://royaleapi.github.io/cr-api-assets/badges/Cherry_Blossom_04.png"
}
},
arena: {
name: "Grand Champion",
arena: "League 8",
arenaID: 20,
trophyLimit: 6100
}
},
I found the solution,
In angular in component init method, I did the following,
Call the service and read the data in a string array,
topPlayer$: string[];
ngOnInit() {
this.topPlayerSrvice.getTopPlayers()
.subscribe(response => {
let topPlayer: string[];
topPlayer = response.json();
this.topPlayer$ = JSON.parse(topPlayer['value']);
});
}

Understanding HTTP in Angular 2 tutorial

I've been going through the Angular 2 Tour of Heroes tutorial and I'm not understanding the lesson on using HTTP to fetch data from a service.
In this lesson in the Hero Service a variable heroesUrl is declared as 'app/heroes'.
private heroesUrl = 'app/heroes'; // URL to web api
constructor(private http: Http) { }
getHeroes(): Promise<Hero[]> {
return this.http.get(this.heroesUrl)
.toPromise()
.then(response => response.json().data as Hero[])
.catch(this.handleError);
}
The data is declared in the in-memory-data service as a static array:
import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService {
createDb() {
let heroes = [
{ id: 11, name: 'Mr. Nice (api)' },
{ id: 12, name: 'Narco' },
{ id: 13, name: 'Bombasto' },
{ id: 14, name: 'Celeritas' },
{ id: 15, name: 'Magneta' },
{ id: 16, name: 'RubberMan' },
{ id: 17, name: 'Dynama' },
{ id: 18, name: 'Dr IQ' },
{ id: 19, name: 'Magma' },
{ id: 20, name: 'Tornado' },
{ id: 21, name: 'Mister Man' }
];
return { heroes };
}
}
But in the routing module 'heroes' (which I assume is the same as 'app/heroes') points to the HeroesComponent.
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'detail/:id', component: HeroDetailComponent },
{ path: 'heroes', component: HeroesComponent }
];
In the HeroesComponent the getHeroes() function calls the this.heroService.getHeroes() function:
getHeroes(): void {
//Result of heroService.getHeroes is a Promise
this.heroService.getHeroes().then(heroesresult => this.heroes = heroesresult);
}
On the surface it looks like HeroesComponent.getHeroes() calls HeroService.getHeroes() which then does a http.get back to the HeroesComponent, not to the data source.
It all works for me (like magic) but there is no explanation of how the data which is in the in-memory-data service is fetched by the call from HeroesService to this.http.get(this.heroesUrl).
Could somebody please help me understand?
The 'app/heroes' URL is not referring to the routing module 'heroes'. It is referring to the heroes data object in in-memory-data-service.ts. So it is not magic; the URL is just referring to a data object, not a path.
The documentation at https://angular.io/tutorial/toh-pt6 is too terse to be clear and I've made suggestions for what needs to be improved at https://github.com/angular/angular.io/issues/3559
It's definitely not magic.
What's happening is you're calling a get request to a in memory api !
Have a look at in-memory-api
Basically , the class InMemoryDataService , extends from a InMemoryDbService which creates a in memory api observable .
Think of it as a stub that has been created on the fly and then when you call get method the call will be redirected to that package (via xhrbackend) and then you get that hero list . .

How to change a schema key?

I have a schema defined below and how can I change the predefined schema key (summary: key) via meteor template?
Schemas.Books = new SimpleSchema(
{
summary: {
type: String
}
}
);
For instance, I want to change this key through a session variable that was defined by router or through a user input.
Not Sure, Try this
If your schema is like this
Books = new SimpleSchema(
{
summary: {
type: String
}
}
);
then in tempalte helpers,
Books._schema.summary.type = function() {
return Session.get("typeValue");
};
In my project I have schema like this
RegisterSchema = new SimpleSchema({
name: {
type: String
},
email: {
type: String,
regEx: SimpleSchema.RegEx.Email
},
password: {
type: String,
label: "Password",
min: 8
},
confirmPassword: {
type: String,
label: "Confirm Password",
min: 8,
custom: function () {
if (this.value !== this.field('password').value) {
return "passwordMismatch";
}
}
}
});
and I'm dynamically setting optional value for email like
RegisterSchema._schema.email.optional = function() { return true };
this worked for me.
All d best
This is not the thing that I'm trying to do but I have learned a new trick : )
I want to change the schema key that I described above like this.
Books = new SimpleSchema(
{
bookName: {
type: String
}
}
);
Changing summary: with bookName:
Actually I want to define schema keys dynamically with respect to user information (userId, userName etc.).

How to use encryption in ydn-db database library?

I am trying to implement setSecret to encrypt the values in indexeddb but get the error:
"unable to call method setSecret of undefined"
Code Below:
$(window).load(function () {
//Database Schema
var db_schema = {
stores: [
{
name: "Employees",
}
]
}
var secret = "Test";
db.setSecret(secret);
db = new ydn.db.Storage('Database', db_schema);
});
Following the link, but not sure where I'm going wrong any ideas:
Anyone encrpyted there indexddb values before?
Thanks
Sorry for documentation behind. I have updated the documentation. Now you have to put encryption key in database options.
var schema = {
version: 1,
stores: [{
name: 'encrypt-store',
encrypted: true
}]
};
var options = {
Encryption: {
expiration: 1000*15, // optional data expiration in ms.
secrets: [{
name: 'aaaa',
key: 'aYHF6vfuGHpfWSeRLrPQxZjS5c6HjCscqDqRtZaspJWSMGaW'
}]
}
};
var db = new ydn.db.Storage('encrypted-db-name', schema, options);
You have to use "-crypt" module to get that feature. It supports transparent data encryption using sha256 crypto, per record salting and key rotation. You still need server to generate encryption key and send to the client securely. There is also a demo app.
//Database Creation
//Database Schema
var db_schema = {
stores: [{
name: "DataTable",
encrypted: true
}
]
};
var options = {
Encryption: {
//expiration: 1000 * 15, // optional data expiration in ms.
secrets: [{
name: 'aaaa',
key: 'aYHF6vfuGHpfWS*eRLrPQxZjSó~É5c6HjCscqDqRtZasp¡JWSMGaW'
}]
}
};
//Create the database with the relevant tables using the schema above
db = new ydn.db.Storage('Database', db_schema,options);
$.ajax({
type: "POST",
url: "/home/DownloadData",
data: { File: file },
success: function (result) {
var Key = result.Data.Key;
var DownloadedData= {
Data: result.Data,
Data1: result.Data1,
Data2: result.Data2,
Data3: result.Data3
};
db.put('DataTable', DownloadedData, Key);
return false;
},
error: function (error) {
alert("fail");
}
});

Resources