HonoJS CORS with cloudflare worker - serverless

I'm starting with cloudflare worker and used the recommended routing framework HonoJS.
Now the documented way of implementing cors functionallity doesn't work for me on my developement machine (npm run dev). I didn't test it on production, since I need it to work on development environment.
The problem is: The OPTION request gets an 404 returned.
How do I set a global CORS configuration?
My code is currently this:
import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { basicAuth } from 'hono/basic-auth'
import { default as register } from './register.js'
const app = new Hono()
app.use('*', cors())
const user = new Hono()
// also tried: user.use('/*', cors())
user.post('/register', register)
// Register route groups
app.route('/user', user)
export default app
Also tried following cors call:
cors({
origin: 'http://localhost:5173',
allowHeaders: ['X-Custom-Header', 'Upgrade-Insecure-Requests'],
allowMethods: ['POST', 'GET', 'OPTIONS'],
exposeHeaders: ['Content-Length', 'X-Kuma-Revision'],
maxAge: 600,
credentials: true,
})
Thank you very much for your time!

I fixed it by adding a wildcard for options.
app.use('*', cors({
origin: 'http://localhost:5173',
allowHeaders: ['Content-Type', 'Authorization'],
allowMethods: ['POST', 'GET', 'OPTIONS'],
exposeHeaders: ['Content-Length'],
maxAge: 600,
credentials: true,
}))
app.options('*', (c) => {
return c.text('', 204)
})

Related

Get OAuth 2.0 Token from personnal accounts (Outlook)

I am trying to use #azure/msal-node on a node backend server. 
all work fine for business accounts onmicrosoft.com but not for personnal accounts like outlook.com
according to this documentation, Authentication seems to be possible
https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth
But i don't understand if my problem come from azure AD configuration or from my code. 
exp.post('/connect', function (req, res) {
let authCodeUrlParameters = {
scopes: SCOPES_OUTLOOK,
redirectUri: "http://localhost:4220/redirect",
};
publicMicrosoftClient.getAuthCodeUrl(authCodeUrlParameters).then((response) => {
if (req.body.email) {
response += `&login_hint=${req.body.email}`
}
open(response)
}).catch((error) => console.log(JSON.stringify(error)));
});
exp.get('/redirect', async function (req, res) {
try {
const form = {
'code': req.query.code,
'client_id': CLIENT_ID_OUTLOOK,
'scope': SCOPES_OUTLOOK.join(' '),
'redirect_uri': 'http://localhost:4220/redirect',
'grant_type': 'authorization_code',
'client_secret': encodeURI(SECRET_VALUE_OUTLOOK),
}
const options = {
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
method: 'post',
}
response = await got(options, { form });
respToken = response.body
...
} catch (error) {
console.log(error)
res.end();
}
});
the error come from ...v2.0/token request. the server response doesn't really help (error 400 bad request)
in azure AD we have app registered and all required scope with status granted.
Thank you in advance for your help,
Yan
• You are getting this error because you have not allowed or selected ‘Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)’ as shown below in the snapshot for the Azure AD app registered regarding authentication for your backend code: -
• Also, if you have already configured your Azure AD application registration for your node backend code, then you can also configure the above in your Azure AD app’s ‘Application Manifest’ by modifying the parameter ‘signInAudience’ with the value as ‘AzureADandPersonalMicrosoftAccount’ as well as ensure that the below parameters are also set as per the stated values to resolve this issue: -
“allowPublicClient” : true
“accesstokenAcceptedVersion” : 2
For more information regarding this, kindly refer to the below link: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/reference-app-manifest

Workbox precache doesn't precache

I'm attempting to implement workbox to precache image and video assets on a website.
I've created a service worker file. It appears to be successfully referenced and used in my application. The service worker:
import { clientsClaim, setCacheNameDetails } from 'workbox-core';
import { precacheAndRoute, addRoute } from 'workbox-precaching';
const context = self; // eslint-disable-line no-restricted-globals
setCacheNameDetails({ precache: 'app' });
// eslint-disable-next-line no-restricted-globals, no-underscore-dangle
precacheAndRoute(self.__WB_MANIFEST);
context.addEventListener('install', (event) => {
event.waitUntil(
caches.open('dive').then((cache) => {
console.log(cache);
}),
);
});
context.addEventListener('activate', (event) => {
console.log('sw active');
});
context.addEventListener('fetch', async (event) => {
console.log(event.request.url);
});
context.addEventListener('message', ({ data }) => {
const { type, payload } = data;
if (type === 'cache') {
payload.forEach((url) => {
addRoute(url);
});
const manifest = payload.map((url) => (
{
url,
revision: null,
}
));
console.log('attempting to precache and route manifest', JSON.stringify(manifest));
precacheAndRoute(manifest);
}
});
context.skipWaiting();
clientsClaim();
The application uses workbox-window to load, reference and message the service worker. The app looks like:
import { Workbox } from 'workbox-window';
workbox = new Workbox('/sw.js');
workbox.register();
workbox.messageSW({
type: 'cache',
payload: [
{ url: 'https://media0.giphy.com/media/Ju7l5y9osyymQ/giphy.gif' }
],
});
This project is using vue with vue-cli. It has a webpack config which allows plugins to be sent added to webpack. The config looks like:
const { InjectManifest } = require('workbox-webpack-plugin');
const path = require('path');
module.exports = {
configureWebpack: {
plugins: [
new InjectManifest({
swSrc: path.join(__dirname, 'lib/services/Asset-Cache.serviceworker.js'),
swDest: 'Asset-Cache.serviceworker.js',
}),
],
},
};
I can see messages are successfully sent to the service worker and contain the correct payload. BUT, the assets never show up in Chrome dev tools cache storage. I also never see any workbox logging related to the assets sent via messageSW. I've also tested by disabling my internet, the assets don't appear to be loading into the cache. What am I doing wrong here?
I found the workbox docs to be a little unclear and have also tried to delete the message event handler from the service worker. Then, send messages to the service worker like this:
workbox.messageSW({
type: 'CACHE_URLS',
payload: { urlsToCache: [ 'https://media0.giphy.com/media/Ju7l5y9osyymQ/giphy.gif'] },
});
This also appears to have no effect on the cache.
The precache portion of precacheAndRoute() works by adding install and activate listeners to the current service worker, taking advantage of the service worker lifecycle. This will effectively be a no-op if the service worker has already finished installing and activating by the time it's called, which may be the case if you trigger it conditionally via a message handler.
We should probably warn folks about this ineffective usage of precacheAndRoute() in our Workbox development builds; I've filed an issue to track that.

Ionic 5 - API request working on browser, not on emulated IOS

I have this Ionic 5/Capacitor app, which I'm making an API call to a local server from, that server running on docker at localhost:3000. When I test from the browser, the request is made fine. From Postman it requests fine, too. In my XCode logs the emulator, I see this
[error] - ERROR {"headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"status":0,"statusText":"Unknown Error","url":"http://localhost:3000/pins","ok":false,"name":"HttpErrorResponse","message":"Http failure response for http://localhost:3000/pins: 0 Unknown Error","error":{"isTrusted":true}}
The really interesting part, is that I'm running Fiddler to monitor the request as it's made. Fiddler gets a 200 as well, I can even see the response data. So, Fiddler sees the proper network call, but then my Ionic app gets that error. That makes me feel like it's an Ionic/Emulator/IOS problem, but I don't have enough familiarity with Ionic to know right off the bat what it is.
Here's the code responsible for making the request:
ngOnInit() {
const request = this.http.get('http://localhost:3000/pins');
this.refresh$.subscribe(
(lastPos: { latitude?: any; longitude?: number }) => {
request.subscribe(data => {
if (data) {
this.addMarkersToMap(data, lastPos);
}
});
}
);
}
And the HTTPClient imported in the constructor is from Angular:
import { HttpClient } from '#angular/common/http';
I ended up having to use this package, doing a check on if I'm on mobile or not.
https://ionicframework.com/docs/native/http/
Try with this :
const request = this.http.get('http://localhost:3000/pins', { observe: 'response', withCredentials: true });
Solution 2 : capacitor.config.json
"server": {
"hostname": "localhost", (maybe try precising the port number too)
}
Solution 3 : On your Express server (from https://ionicframework.com/docs/troubleshooting/cors)
const express = require('express');
const cors = require('cors');
const app = express();
const allowedOrigins = [
'capacitor://localhost',
'ionic://localhost',
'http://localhost',
'http://localhost:8080',
'http://localhost:8100'
];
// Reflect the origin if it's in the allowed list or not defined (cURL, Postman, etc.)
const corsOptions = {
origin: (origin, callback) => {
if (allowedOrigins.includes(origin) || !origin) {
callback(null, true);
} else {
callback(new Error('Origin not allowed by CORS'));
}
}
}
// Enable preflight requests for all routes
app.options('*', cors(corsOptions));
app.get('/', cors(corsOptions), (req, res, next) => {
res.json({ message: 'This route is CORS-enabled for an allowed origin.' });
})
app.listen(3000, () => {
console.log('CORS-enabled web server listening on port 3000');
});

How do I setup Swashbuckle v5 with swagger when I have a custom base url?

I am upgrading a .net API to .net Core 3.1 and using Swashbuckle.AspNetcore 5.4.1. The API is running inside a ServiceFabric app. I found this https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1173 and tried to follow that and swagger gets generated but if I try to use the Swagger UI to send requests the request URL is with the wrong IP so the request fail.
In the old Swashbuckle 4.0.1 setup we did not specify host, only the relative basePath. How can I achieve the same?
Startup.cs
var swaggerBasePath = "/MySfApp/SfApp.ClientApi/";
app.UseSwagger(c =>
{
c.SerializeAsV2 = serializeAsSwaggerV2;
c.RouteTemplate = "swagger/{documentName}/swagger.json";
c.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
{
swaggerDoc.Servers = new List<OpenApiServer> { new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}{swaggerBasePath}" } };
});
});
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("api/swagger.json", "My API V1");
});
The result is that the Swagger UI loads correctly on URL:
http://145.12.23.1:54000/MySfApp/SfApp.ClientApi/swagger/index.html
and it says under name that BaseUrl is:
[ Base URL: 10.0.0.4:10680/MySfApp/SfApp.ClientApi/ ]
The 10.0.0.4:10680 is the node inside the ServiceFabric cluster. Correct IP to reach from outside is 145.12.23.1:54000. In the older version (4.0.1) of Swashbuckle it says baseUrl without IP first: "/MySfApp/SfApp.ClientApi"
Swagger.json is located at:
http://40.68.213.118:19081/MySfApp/SfApp.ClientApi/swagger/api/swagger.json
and it says:
"swagger": "2.0",
...
"host": "10.0.0.4:10680",
"basePath": "/MySfApp/SfApp.ClientApi/",
"schemes": [
"http"
],
"paths": {
"/activity/{activityId}": {
"get"
...etc
If i try to send a GET request from the Swagger UI the request is sent to wrong IP:
curl -X GET "http://10.0.0.4:10680/MySfApp/MySfApp/activity/3443"
EDIT 1:
After some digging I have now changed the setup to this in
startup.cs
var swaggerBasePath = "/MySfApp/SfApp.ClientApi/";
app.UsePathBase($"/{swaggerBasePath}");
app.UseMvc();
app.UseSwagger(c =>
{
c.SerializeAsV2 = serializeAsSwaggerV2;
c.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
{
if (!httpReq.Headers.ContainsKey("X-Original-Host"))
return;
var serverUrl = $"{httpReq.Headers["X-Original-Proto"]}://" +
$"{httpReq.Headers["X-Original-Host"]}/" +
$"{httpReq.Headers["X-Original-Prefix"]}";
swaggerDoc.Servers = new List<OpenApiServer>()
{
new OpenApiServer { Url = serverUrl }
};
});
});
app.UseSwaggerUI(options => {
options.SwaggerEndpoint("api/swagger.json", "My API V1");
});
This now leads to the Swagger UI loading properly with the baseUrl
http://145.12.23.1:54000/MySfApp/SfApp.ClientApi/swagger/index.html
and also swagger.json is served correctly with the correct baseUrl.
http://145.12.23.1:54000/MySfApp/SfApp.ClientApi/swagger/api/swagger.json
So the wrong hostname is resolved. Thanks to idea from this thread.
However when I try to call an endpoint from the Swagger UI page, the curl URL does not include the baseUrl. So closer... but currently not possible to use Swagger UI.
curl -X GET "http://10.0.0.4:10680/activity/3443"
The swagger.json does not have 'host' nor 'basePath' defined.
We're using Swashbuckle version 6.1.4 - which is the latest as of this time of writing and we're still having the same issue when our API is deployed in Azure App Service that is mapped through Azure Front Door and APIM. The "Try out" functionality does not work as the base path / api route prefix is stripped from the Swagger UI. For example,
Instead of https://{DOMAIN}.com/{BASEPATH}/v1/Foo, the Swagger UI uses this: https://{DOMAIN}.com/v1/Foo. You can see that the /BASEPATH is missing.
I spent the whole day trying to fix this with trial and error, trying various approaches with no luck, I couldn't get an elegant way to get the base path from swagger configuration. For the time being, here's what I did to fix it:
app.UseSwagger(options =>
{
//Workaround to use the Swagger UI "Try Out" functionality when deployed behind a reverse proxy (APIM) with API prefix /sub context configured
options.PreSerializeFilters.Add((swagger, httpReq) =>
{
if (httpReq.Headers.ContainsKey("X-Forwarded-Host"))
{
//The httpReq.PathBase and httpReq.Headers["X-Forwarded-Prefix"] is what we need to get the base path.
//For some reason, they returning as null/blank. Perhaps this has something to do with how the proxy is configured which we don't have control.
//For the time being, the base path is manually set here that corresponds to the APIM API Url Prefix.
//In this case we set it to 'sample-app'.
var basePath = "sample-app"
var serverUrl = $"{httpReq.Scheme}://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}";
swagger.Servers = new List<OpenApiServer> { new OpenApiServer { Url = serverUrl } };
}
});
})
.UseSwaggerUI(options =>
{
options.RoutePrefix = string.Empty;
options.SwaggerEndpoint("swagger/v1/swagger.json", "My Api (v1)");
});
Here's an open discussion related to this issue here.
I were having something similar in my solution and I have used a little bit this way and that works well for me, in case that helps someone.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrWhiteSpace(pathBase))
{
app.UsePathBase($"/{pathBase.TrimStart('/')}");
app.Use((context, next) =>
{
context.Request.PathBase = new PathString($"/{pathBase.TrimStart('/')}");
return next();
});
if (env.IsDevelopment())
{
app.UseSwagger(c =>
{
c.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
{
if (!httpReq.Headers.ContainsKey("X-Original-Host"))
return;
var serverUrl = $"{httpReq.Headers["X-Original-Proto"]}://" + $"{httpReq.Headers["X-Original-Host"]}/" + $"{httpReq.Headers["X-Original-Prefix"]}";
swaggerDoc.Servers = new List<OpenApiServer>()
{
new OpenApiServer { Url = serverUrl }
}
});
});
app.UseSwaggerUI(c => c.SwaggerEndpoint($"/{pathBase.TrimStart('/')}/swagger/v1/swagger.json", "My.API v1"));
}
}
}
check the last line
app.UseSwaggerUI(c => c.SwaggerEndpoint($"/{pathBase.TrimStart('/')}/swagger/v1/swagger.json", "My.API v1"));
Try this:
serverUrl = $"{httpReq.Headers["X-Forwarded-Proto"]}://" +
$"{httpReq.Headers["X-Forwarded-Host"]}" + _basePath;
where _basePath can be set using the ServiceName property of StatelessServiceContext.
Please be noted that the original value of X-Forwarded-Proto may be overridden by SF.

How do I get webpack-dev-server to accept POST requests

In my project I call:
$ webpack-dev-server --history-api-fallback
And it starts an express server (I'm assuming) available on localhost:8080.
It works great except that I want to submit a form via POST into an iframe loading my app; localhost:8080 in development and something else in production.
I don't expect to do anything with that POST data in development, but in production, it needs to be POST.
When I try to use POST however, it cannot find POST /
Is there a configuration option or some other solution that will allow me to use the webpack-dev-server? (I really don't want to have to write my own server for this).
#cowCrazy had half of the story, but didn't show how to respond with the same response for GET in the case of POST, which is what I was looking for.
In the Webpack config, you do this:
module.exports = {
...,
devServer: {
setup(app) {
app.post('*', (req, res) => {
res.redirect(req.originalUrl);
});
},
}
}
This will just take the POST URL and redirect with the same URL, making it a GET request.
Instead of having a server error, it will redirect with GET.
What you are looking for is devServer. Bellow you can see my config for it. Under setup(app) you can add "almost" whatever you want:
module.exports = {
...,
devServer: {
inline: true,
port: 3000,
publicPath: '/',
setup(app){
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.get("/get/some-data", function(req, res){
console.log(req);
res.send("GET res sent from webpack dev server")
})
app.post("/post/some-data", bodyParser.json(), function(req, res){
console.log(req.body);
res.send("POST res sent from webpack dev server")
})
}
}
}
EDIT:
I have pushed a minimalistic example to github if you wanna take a better look.
Check if it solves your problem by converting the POST request to GET request:
bypass: function (req, res, proxyOptions) {
const url = req.url;
req.method = 'GET';
if (url.indexOf('?') > -1) {
return url.replace('?', '.json?');
} else {
return url + '.json';
}
}

Resources