GCP api key restrictions - api

In my GCP project, I created a new api key. I restricted the key to IOS apps, and properly set my IOS application bundle id.
The api key is being used in an Ionic 5 app, which has been built in Xcode and is running on an IOS device.
The api key is being passed on a Google Maps static API request.
To test the api key restriction I crafted a url that looks like this:
https://maps.googleapis.com/maps/api/staticmap?center=290%20Bremner%20Blvd%2C%20Toronto%2C%20ON%20M5V%203L9&key=[restricted key here]&zoom=12&size=400x400
When I load this url from my laptop web browser a map is returned, but I expected this not to work, and instead that I would receive an http 403 error.
Any insight into what I'm missing here appreciated; how do I properly restrict my maps api key when using it in an Ionic 5 app?

I found the answer to my question: in addition to using a restricted API key, each Maps Static API request must be digitally signed when making the request.
Here's sample Node js code from Google on how to do this:
'use strict'
const crypto = require('crypto');
const url = require('url');
/**
* Convert from 'web safe' base64 to true base64.
*
* #param {string} safeEncodedString The code you want to translate
* from a web safe form.
* #return {string}
*/
function removeWebSafe(safeEncodedString) {
return safeEncodedString.replace(/-/g, '+').replace(/_/g, '/');
}
/**
* Convert from true base64 to 'web safe' base64
*
* #param {string} encodedString The code you want to translate to a
* web safe form.
* #return {string}
*/
function makeWebSafe(encodedString) {
return encodedString.replace(/\+/g, '-').replace(/\//g, '_');
}
/**
* Takes a base64 code and decodes it.
*
* #param {string} code The encoded data.
* #return {string}
*/
function decodeBase64Hash(code) {
// "new Buffer(...)" is deprecated. Use Buffer.from if it exists.
return Buffer.from ? Buffer.from(code, 'base64') : new Buffer(code, 'base64');
}
/**
* Takes a key and signs the data with it.
*
* #param {string} key Your unique secret key.
* #param {string} data The url to sign.
* #return {string}
*/
function encodeBase64Hash(key, data) {
return crypto.createHmac('sha1', key).update(data).digest('base64');
}
/**
* Sign a URL using a secret key.
*
* #param {string} path The url you want to sign.
* #param {string} secret Your unique secret key.
* #return {string}
*/
function sign(path, secret) {
const uri = url.parse(path);
const safeSecret = decodeBase64Hash(removeWebSafe(secret));
const hashedSignature = makeWebSafe(encodeBase64Hash(safeSecret, uri.path));
return url.format(uri) + '&signature=' + hashedSignature;
}
More information / documentation here:
https://developers.google.com/maps/documentation/maps-static/get-api-key#gen-sig

Related

How to upload PDF files from femanager extension TYPO3 11.5

I am tryng to upload pdf files from the frontend with the user profile form (femanager), it only allows me to use the "Image" field, but for this case more pdf file fields are needed.
I have the following custom field for it
<f:form.upload
id="femanager_field_pdf"
property="pdf.0"
class="custom-file-input" />
In the extended User class
/**
* #var ObjectStorage<FileReference>
*/
protected $pdf;
/**
* Gets the pdf value
*
* #return ObjectStorage<FileReference>
*/
public function getPdf()
{
return $this->pdf;
}
/**
* Sets the pdf value
*
* #param ObjectStorage<FileReference> $pdf
*/
public function setpdf(ObjectStorage $pdf)
{
$this->pdf = $pdf;
}
I expected that when saving the user profile form the file would be saved in the "pdf" field but it generates an error
Exception while property mapping at property path "pdf.0": Property "name" was not found in target object of type "TYPO3\CMS\Extbase\Domain\Model\FileReference".

error when sending a notification 'Call to undefined method App\Models\Role::routeNotificationFor()'

I am building a web app whereby after an admin(with the role of a manager) approves a booking, the booking passes to another admin(with the role of an accountant) who then starts working on it.I want the manager to send a notification to only the accountant after approving the booking.i tried this code below and it sends to all admins which is not what I want to achieve
$users=User::where('is_admin','1')->get();
Notification::send($users,new Newbookingrecieved($bookingstatus));
then i tried getting the email from the role model
$users=Role::where('Role_name','The Accountant')->get();
Notification::send($users,new Newbookingrecieved($bookingstatus));
but it responded with an error
BadMethodCallException
Call to undefined method App\Models\Role::routeNotificationFor()
here is my notification
<?php
namespace App\Notifications;
use App\Models\Bookings;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class Newbookingrecieved extends Notification
{
use Queueable;
public $bookingstatus;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($bookingstatus)
{
$this->bookingstatus = $bookingstatus;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->greeting('Hello there sir/madam')
->subject('New Booking by' .$this->bookingstatus->full_name)
->line('We have received a new Booking and approved it to you to request payment from the client' . $this->bookingstatus->email)
->action('Review This Booking', route('changestatus', $this->bookingstatus->id));
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
here are all the roles
how can i achieve this such that i send the notification to the only adminand the notification wont be sent to other admins.
As I don't know the structure of your User model, I will assume that there is a role_id field.
Here is a piece of my code from one of my old projects that I will modify to your liking (it works for me) :
$users = User::where('role_id', 3)->get(); //3 is the id of The Accountant role
Notification::send($users, new Newbookingrecieved($bookingstatus));

Generate and validate session in node.js

What is a correct way to generate session and than validate it on every request?
Registration and initial authentication (user identity check for generating session) is handled by external service, so it's out of the question.
To simplify a question, what is the native secure way to generate and encrypt session with secret.
Requirements (alternatives is welcomed):
Session should be of two parts, one stored in cookies, second in database.
User check handled by server using database session part, cookies part and validate function.
Session generating and validating functions stored on server side and not accessible to user.
If database session part or functions is compromised, hacker couldn't make request pretending to be user. For this he will need to steal user cookies or session generate function and database session part.
Multiple device support with the same database session part.
JWT is not usable as logout is needed on server side (database session part will be deleted and all devices wouldn't be able to login with old cookies session part). User had some trust level that can change and it's will require JWT invalidation, so sessions is better choice.
I was thinking of using Crypto AES for this, but after asking "is it ok?" - answer was no, i'm not an expert in crypto, so i didn't fully understood a reason.
Here is my initial idea of implementation:
/**
* #param {string} data dummy
* #param {string} userKey from database or create new
* #return {object} {iv, key, encryptedData}
*/
function encrypt(data, userKey) {
let key = userKey ? Buffer.from(userKey, 'hex') : crypto.randomBytes(32)
let iv = crypto.randomBytes(16)
let cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv)
let encrypted = cipher.update(data)
encrypted = Buffer.concat([encrypted, cipher.final()])
return { iv: iv.toString('hex'), key: key.toString('hex'), encryptedData: encrypted.toString('hex') }
}
/**
* #param {string} iv
* #param {string} key
* #param {string} encryptedData
* #return {string} decrupted dummy data
*/
function decrypt(iv, key, encryptedData) {
try {
iv = Buffer.from(iv, 'hex')
key = Buffer.from(key, 'hex')
encryptedData = Buffer.from(encryptedData, 'hex')
let decipher = crypto.createDecipheriv('aes-256-cbc', key, iv)
let decrypted = decipher.update(encryptedData)
decrypted = Buffer.concat([decrypted, decipher.final()])
return decrypted.toString()
} catch (err) {
return false
}
}
A way to make it, is that user generate RSA and use crypto with public and private keys, but the public key must always be sent by the user('device')
'use strict';
const express = require('express');
const fs = require('fs');
const nodersa = require('node-rsa');
const bodyParser = require('body-parser');
let app = express();
app.use(bodyParser.urlencoded({ extended : false }));
app.use(bodyParser.json());
// req.body.value is public key, this never write in database or file
app.post('/', (req, res)=>{
let value = req.body.value;
const privateKey = fs.readFileSync('./store/privateKey.pem', 'utf8');
const original = new nodersa(privateKey).decrypt(value, 'utf8');
res.end(original);
});
app.listen(8000, ()=>{
console.log('on 8000');
});
if you use a public certificate authority with node, use aditional file called "certification file", node example here, this file is issue by C.A. you could work as C.A. and generarte this file, but It is recommended for closed systems, if you not need a gubernamental allow

vuex actions and jsdoc: how to mark injected function parameter

Typical vuex action is:
const actions = {
/**
* #param {ActionContext} context passed by vuex
* #param {Object} payload
* #return {void}
*/
myAction(vuexContext, payload) {...}
}
Where vuexContext would be injected for me, and in app I would use this function just as myAction(payload). But for that case my WebStorm IDE complains about invalid number of arguments.
Maybe there is some workaround for it?
You can try marking context parameter optional:
/**
* #param {ActionContext} [vuexContext]
* #param {Object} payload
* #return {void}
*/
myAction(vuexContext, payload) {}
Please also vote for the related feature request: WEB-29740

Lack of response and typing info in API Explorer

I am using the latest version of Restler v3 (commit 0d79cd8) but I'm having some problems having my Swagger-based UI look the same as in the examples. The two problems I'm noticing are that variable typing and #return objects are not being displayed.
On the Restler site, here's a good example of both of these working:
example
Instead, in my Actions class I get this:
And yet as you can see from definition of the class both type information and a response object is specified:
class Actions {
/**
* LIST action types
*
* List all the action-types available
*
* #url GET /
*/
function list_actions() {
throw new RestException(501);
}
/**
* GET today's Actions
*
* Get the set of actions done today
*
* #url GET /{user_id}
* #param integer $user_id The user_id for whom the actions apply; you can insert the text "self" and it will resolve to the current/default user
* #param string $time_of_day {#from url} Allow's you to optionally set a time-of-day; if set then actions are only returned after that. Time should be in the format of HH:MM:SS
* #return ActionList
*/
public function action_today ($user_id, $time_of_day = false )
{
throw new RestException(501, "Today's actions for user '{$user_id}' not implemented.");
}
and my definition of ActionList class is:
class ActionList {
/**
* Unique identifier of action
*
* #var integer
*/
public $action_id;
/**
* String based unique identifier
*
* #var string
*/
public $action_slug;
}
If your class is versioned, e.g. in the namespace v1\Actions, you have to annotate the return type in the namespace too, e.g. #return v1\ActionList