mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-28 12:12:20 +00:00
Merge pull request #2798 from khassel/cors
This commit is contained in:
commit
da90412cea
@ -15,6 +15,7 @@ _This release is scheduled to be released on 2022-04-01._
|
|||||||
- Added test for new weather forecast absoluteDates porperty.
|
- Added test for new weather forecast absoluteDates porperty.
|
||||||
- The modules get a class hidden added/removed if they get hidden/shown
|
- The modules get a class hidden added/removed if they get hidden/shown
|
||||||
- Added new config option `showTitleAsUrl` to newsfeed module. If set, the diplayed title is a link to the article which is useful when running in a browser and you want to read this article.
|
- Added new config option `showTitleAsUrl` to newsfeed module. If set, the diplayed title is a link to the article which is useful when running in a browser and you want to read this article.
|
||||||
|
- Added internal cors proxy to get weather providers working without public proxies (fixes #2714). The new url `http(s)://address:port/cors?url=https://whatever-to-proxy` can be used in other modules too.
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
|
29
js/server.js
29
js/server.js
@ -10,6 +10,7 @@ const path = require("path");
|
|||||||
const ipfilter = require("express-ipfilter").IpFilter;
|
const ipfilter = require("express-ipfilter").IpFilter;
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const helmet = require("helmet");
|
const helmet = require("helmet");
|
||||||
|
const fetch = require("node-fetch");
|
||||||
|
|
||||||
const Log = require("logger");
|
const Log = require("logger");
|
||||||
const Utils = require("./utils.js");
|
const Utils = require("./utils.js");
|
||||||
@ -61,6 +62,7 @@ function Server(config, callback) {
|
|||||||
app.use(function (req, res, next) {
|
app.use(function (req, res, next) {
|
||||||
ipfilter(config.ipWhitelist, { mode: config.ipWhitelist.length === 0 ? "deny" : "allow", log: false })(req, res, function (err) {
|
ipfilter(config.ipWhitelist, { mode: config.ipWhitelist.length === 0 ? "deny" : "allow", log: false })(req, res, function (err) {
|
||||||
if (err === undefined) {
|
if (err === undefined) {
|
||||||
|
res.header("Access-Control-Allow-Origin", "*");
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
Log.log(err.message);
|
Log.log(err.message);
|
||||||
@ -76,6 +78,33 @@ function Server(config, callback) {
|
|||||||
app.use(directory, express.static(path.resolve(global.root_path + directory)));
|
app.use(directory, express.static(path.resolve(global.root_path + directory)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.get("/cors", async function (req, res) {
|
||||||
|
// example: http://localhost:8080/cors?url=https://google.de
|
||||||
|
|
||||||
|
try {
|
||||||
|
const reg = "^/cors.+url=(.*)";
|
||||||
|
let url = "";
|
||||||
|
|
||||||
|
let match = new RegExp(reg, "g").exec(req.url);
|
||||||
|
if (!match) {
|
||||||
|
url = "invalid url: " + req.url;
|
||||||
|
Log.error(url);
|
||||||
|
res.send(url);
|
||||||
|
} else {
|
||||||
|
url = match[1];
|
||||||
|
Log.log("cors url: " + url);
|
||||||
|
const response = await fetch(url, { headers: { "User-Agent": "Mozilla/5.0 MagicMirror/" + global.version } });
|
||||||
|
const header = response.headers.get("Content-Type");
|
||||||
|
const data = await response.text();
|
||||||
|
if (header) res.set("Content-Type", header);
|
||||||
|
res.send(data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
Log.error(error);
|
||||||
|
res.send(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/version", function (req, res) {
|
app.get("/version", function (req, res) {
|
||||||
res.send(global.version);
|
res.send(global.version);
|
||||||
});
|
});
|
||||||
|
@ -18,7 +18,8 @@ WeatherProvider.register("darksky", {
|
|||||||
|
|
||||||
// Set the default config properties that is specific to this provider
|
// Set the default config properties that is specific to this provider
|
||||||
defaults: {
|
defaults: {
|
||||||
apiBase: "https://cors-anywhere.herokuapp.com/https://api.darksky.net",
|
useCorsProxy: true,
|
||||||
|
apiBase: "https://api.darksky.net",
|
||||||
weatherEndpoint: "/forecast",
|
weatherEndpoint: "/forecast",
|
||||||
apiKey: "",
|
apiKey: "",
|
||||||
lat: 0,
|
lat: 0,
|
||||||
|
@ -40,6 +40,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
|
|
||||||
// Set the default config properties that is specific to this provider
|
// Set the default config properties that is specific to this provider
|
||||||
defaults: {
|
defaults: {
|
||||||
|
useCorsProxy: true,
|
||||||
siteCode: "s1234567",
|
siteCode: "s1234567",
|
||||||
provCode: "ON"
|
provCode: "ON"
|
||||||
},
|
},
|
||||||
@ -73,7 +74,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
// Override the fetchCurrentWeather method to query EC and construct a Current weather object
|
// Override the fetchCurrentWeather method to query EC and construct a Current weather object
|
||||||
//
|
//
|
||||||
fetchCurrentWeather() {
|
fetchCurrentWeather() {
|
||||||
this.fetchData(this.getUrl(), "GET")
|
this.fetchData(this.getUrl(), "GET", "xml")
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
// Did not receive usable new data.
|
// Did not receive usable new data.
|
||||||
@ -93,7 +94,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
// Override the fetchWeatherForecast method to query EC and construct Forecast weather objects
|
// Override the fetchWeatherForecast method to query EC and construct Forecast weather objects
|
||||||
//
|
//
|
||||||
fetchWeatherForecast() {
|
fetchWeatherForecast() {
|
||||||
this.fetchData(this.getUrl(), "GET")
|
this.fetchData(this.getUrl(), "GET", "xml")
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
// Did not receive usable new data.
|
// Did not receive usable new data.
|
||||||
@ -113,7 +114,7 @@ WeatherProvider.register("envcanada", {
|
|||||||
// Override the fetchWeatherHourly method to query EC and construct Forecast weather objects
|
// Override the fetchWeatherHourly method to query EC and construct Forecast weather objects
|
||||||
//
|
//
|
||||||
fetchWeatherHourly() {
|
fetchWeatherHourly() {
|
||||||
this.fetchData(this.getUrl(), "GET")
|
this.fetchData(this.getUrl(), "GET", "xml")
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
// Did not receive usable new data.
|
// Did not receive usable new data.
|
||||||
@ -129,26 +130,6 @@ WeatherProvider.register("envcanada", {
|
|||||||
.finally(() => this.updateAvailable());
|
.finally(() => this.updateAvailable());
|
||||||
},
|
},
|
||||||
|
|
||||||
//
|
|
||||||
// Override fetchData function to handle XML document (base function assumes JSON)
|
|
||||||
//
|
|
||||||
fetchData: function (url, method = "GET", data = null) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
const request = new XMLHttpRequest();
|
|
||||||
request.open(method, url, true);
|
|
||||||
request.onreadystatechange = function () {
|
|
||||||
if (this.readyState === 4) {
|
|
||||||
if (this.status === 200) {
|
|
||||||
resolve(this.responseXML);
|
|
||||||
} else {
|
|
||||||
reject(request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
request.send();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Environment Canada methods - not part of the standard Provider methods
|
// Environment Canada methods - not part of the standard Provider methods
|
||||||
@ -160,11 +141,8 @@ WeatherProvider.register("envcanada", {
|
|||||||
// URL defaults to the Englsih version simply because there is no language dependancy in the data
|
// URL defaults to the Englsih version simply because there is no language dependancy in the data
|
||||||
// being accessed. This is only pertinent when using the EC data elements that contain a textual forecast.
|
// being accessed. This is only pertinent when using the EC data elements that contain a textual forecast.
|
||||||
//
|
//
|
||||||
// Also note that access is supported through a proxy service (thingproxy.freeboard.io) to mitigate
|
|
||||||
// CORS errors when accessing EC
|
|
||||||
//
|
|
||||||
getUrl() {
|
getUrl() {
|
||||||
return "https://thingproxy.freeboard.io/fetch/https://dd.weather.gc.ca/citypage_weather/xml/" + this.config.provCode + "/" + this.config.siteCode + "_e.xml";
|
return "https://dd.weather.gc.ca/citypage_weather/xml/" + this.config.provCode + "/" + this.config.siteCode + "_e.xml";
|
||||||
},
|
},
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -111,8 +111,17 @@ const WeatherProvider = Class.extend({
|
|||||||
this.delegate.updateAvailable(this);
|
this.delegate.updateAvailable(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getCorsUrl: function () {
|
||||||
|
if (this.config.mockData || typeof this.config.useCorsProxy === "undefined" || !this.config.useCorsProxy) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return location.protocol + "//" + location.host + "/cors?url=";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// A convenience function to make requests. It returns a promise.
|
// A convenience function to make requests. It returns a promise.
|
||||||
fetchData: function (url, method = "GET", data = null) {
|
fetchData: function (url, method = "GET", type = "json") {
|
||||||
|
url = this.getCorsUrl() + url;
|
||||||
const getData = function (mockData) {
|
const getData = function (mockData) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
if (mockData) {
|
if (mockData) {
|
||||||
@ -125,7 +134,11 @@ const WeatherProvider = Class.extend({
|
|||||||
request.onreadystatechange = function () {
|
request.onreadystatechange = function () {
|
||||||
if (this.readyState === 4) {
|
if (this.readyState === 4) {
|
||||||
if (this.status === 200) {
|
if (this.status === 200) {
|
||||||
resolve(JSON.parse(this.response));
|
if (type === "xml") {
|
||||||
|
resolve(this.responseXML);
|
||||||
|
} else {
|
||||||
|
resolve(JSON.parse(this.response));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
reject(request);
|
reject(request);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@
|
|||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"verbose": true,
|
"verbose": true,
|
||||||
"testTimeout": 15000,
|
"testTimeout": 20000,
|
||||||
"testSequencer": "<rootDir>/tests/configs/test_sequencer.js",
|
"testSequencer": "<rootDir>/tests/configs/test_sequencer.js",
|
||||||
"projects": [
|
"projects": [
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user