Error when setting up password reset with Parse Server - ios

I am using Parse Server hosted on Heroku with mongoDB. I am struggling to get the password reset function working. I have followed the instructions and added the below code to index.js. Once this code is added, when the app launches or I try to send an email I get this error: JSON text did not start with array or object and option to allow fragments not set.
I know that this means the server cannot parse the data back but I'm totally unsure how to fix this. Any help is much appreciated!
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var path = require('path');
var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
var api = new ParseServer({
databaseURI: databaseUri || 'MY_DATABASE_URI',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'MY_APP_ID',
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'MY_SERVER_URL', // Don't forget to change to https if needed
liveQuery: {
classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
}
verifyUserEmails: true,
//The public URL of your app.
//This will appear in the link that is used to verify email addresses and reset passwords.
//Set the mount path as it is in serverURL
publicServerURL: 'MY_SERVER_URL_FROM_HEROKU',
// Your apps name. This will appear in the subject and body of the emails that are sent.
appName: 'MY_APP_NAME',
// The email adapter
emailAdapter: {
module: 'parse-server-simple-mailgun-adapter',
options: {
// The address that your emails come from
fromAddress: 'MY_MAILGUN_DOMAIN',
// Your domain from mailgun.com
domain: 'MY_MAILGUN_DOMAIN',
// Your API key from mailgun.com
apiKey: 'MY_API_KEY_FROM_MAILGUN',
}
}
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey
var app = express();
// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));
// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);
// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
res.status(200).send('I dream of being a website. Please star the parse-server repo on GitHub!');
});
// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function(req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});
var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpServer);

You're missing a comma after livequery:{...}, before setting verifyUserEmails. Little harder to tell since the block you added for e-mails isn't properly indented.

Related

(XMLHttpRequest error) Problem with serverside CORS policy

I created a flutter project with a web version and we already have a server for database access that another android/ios app uses. However the web version of the new app is running into problems with cors policy. I've been trying to solve this looking at other stock overflow questions and searching on google without success and was hoping someone can help me figure out what I might be doing wrong.
I've tested making the uri client side both with:
String url = "https://" + host + ":" + port;
Uri uri = Uri.parse(url + "/test");
and
String url = host + ":" + port;
Uri uri = Uri.https(url, "/test");
I then call the server using the http/http package:
Response response = await get(uri).timeout(const Duration(seconds: 17));
As for the structure of the server side code:
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const https = require('https');
const routerOne = require('./path/to/router/file');
const routerTwo = require('./path/to/router/file');
const dotenv = require('dotenv');
const fs = require("fs");
dotenv.config();
console.log('port' + process.env.PORT);
var key = fs.readFileSync('./certs/key.key');
var cert = fs.readFileSync('./certs/cert.crt');
var options = {
key: key,
cert: cert
};
const cors = require('cors');
const app = express();
app.use(cors());
try {
let server = https.createServer(options, app);
server.listen(process.env.PORT, () => {
console.log('Started https server on port ' + process.env.PORT);
});
} catch (err) {
console.log(err);
}
app.get('/test', cors(), function (req, res, next) {
res.json({msg: "This is CORS-enabled for all origins!"})
})
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({limit: '50mb', extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/router/one', routerOne);
app.use('/router/two', routerTwo);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
console.log(err);
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
Unlike android when running web version(Chrome or Edge), I have been unable to get the response from the newly added '/test' on the server side. I'm hoping for some suggestion for how I can get the cors policy to work.
Client side I've tried using Uri.https instead of Uri.parse and I added headers as well.
On the server I tried to follow instructions on how to add cors policy to node.js/express.
Error message from flutter:
Error: XMLHttpRequest error.
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 963:28 get current
packages/http/src/browser_client.dart 69:22 <fn>
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1685:54 runUnary
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 147:18 handleValue
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 766:44 handleValueCallback
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 795:13 _propagateToListeners
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 557:7 [_complete]
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/stream_pipe.dart 61:11 _cancelAndValue
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/stream.dart 1530:7 <fn>
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 334:14 _checkAndCall
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 339:39 dcall
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/html/dart2js/html_dart2js.dart 37309:58 <fn>
at Object.createErrorWithStack (http://localhost:59072/dart_sdk.js:5093:12)
at Error._throw (http://localhost:59072/dart_sdk.js:20399:18)
at Error.throwWithStackTrace (http://localhost:59072/dart_sdk.js:20396:18)
at async._AsyncCallbackEntry.new.callback (http://localhost:59072/dart_sdk.js:40921:18)
at Object._microtaskLoop (http://localhost:59072/dart_sdk.js:40778:13)
at _startMicrotaskLoop (http://localhost:59072/dart_sdk.js:40784:13)
at http://localhost:59072/dart_sdk.js:36261:9
Image of browser: image of browser with network tab
Update Solution
The answer from Ber is correct. This is a problem with certificate. Self signed certificate was being used on our server and by getting a new certificate using Let's encrypt the problem got solved. If anyone else runs into the "XMLHttpRequest error" they may also want to check out the error output in the browser as the "net::ERR_CERT_AUTHORITY_INVALID" was not shown in flutter.
The error code in your screen shot is net::ERR_CERT_AUTHORITY_INVALID
meaning the server's SSL certificate is expired, invalid for the domain or not accepted by the root certificates in your app.

Parse-Server LiveQuery not sending events

I am trying to get live queries working with iOS and Parse-Server. The following is my setup for my Parse-Server:
...
let api = new ParseServer({
databaseURI: databaseUri || constants.DATABASE_URI,
cloud: process.env.CLOUD_CODE_MAIN || constants.CLOUD_CODE_MAIN,
appId: process.env.APP_ID || constants.APP_ID,
masterKey: process.env.MASTER_KEY || constants.MASTER_KEY,
serverURL: process.env.SERVER_URL || constants.LOCAL_SERVER_URL,
fileKey: process.env.FILE_KEY || constants.FILE_KEY,
appName: process.env.APP_NAME || constants.APP_NAME,
publicServerURL: process.env.SERVER_URL || constants.LOCAL_SERVER_URL,
liveQuery: {
classNames: [Parse.User]
}
});
...
let port = process.env.PORT || 1337;
let httpServer = require('http').createServer(app);
httpServer.listen(port, function () {
console.log('parse_server running on port ' + port + '.');
});
ParseServer.createLiveQueryServer(httpServer, {logLevel: 'VERBOSE'});
...
And this is my code in the iOS app:
let liveQueryClient = ParseLiveQuery.Client(server: "ws://serverurl/", applicationId: "appID", clientKey: "clientKey")
let query = PFUser.query()?.whereKey("objectId", equalTo: "ABC123") as! PFQuery<PFUser>
let subscription = self.liveQueryClient.subscribe(query).handle(Event.updated) { _, user in
debugprint("\(user)")
}
Debugging on local, I can see the user is connecting using the socket because the server logs:
info: Create new client: 0
and when I disconnect, the server logs:
info: Client disconnect: 0
My problem is that whenever I modify the User object in Parse Dashboard, nothings logs on the server side, and the client doesn't receive any events.
Is there another way to set this up?
Can the User class not be used in live queries?
I am not sure about IOS code however this part e.g:
liveQuery: {
classNames: ["YourColumnNameInDatabase","AnotherColumnName"]
}
Make sure to check that you are subscribing to the correct ClassName(ColumnName in Db)
Hope this helps a little...

Can the environmental keys that Parse Server is Using be verified inside the client app?

I was wondering if/how can the Parse-Server environmental variables be verified inside a client IOS App.
For those of us that are yet uncomfortable with backend systems, it would be useful to be able to validate via the client side during testing that the backend Parse-Server is actually using the correct Environmental Keys.
If you are testing the keys to setup parse-server such as appId, clientKey, masterKey, you can implement a verify cloud code.
Once you use appId (or you have set clientKey), you can call this function. Otherwise, you will get errors. You cannot use MasterKey in client-sdk. If you still want to test it, you can implement a rest api with masterKey on your client. But masterKey should not appear in client side, you should avoid user trigger this, or someone may get your masterKey.
Parse.Cloud.define("verify", function(request, response) {
if(request.master==true){
response.success(true);
}else{
response.error(new Error('MasterKey not matched'));
}
});
Edited
By implement a globalConfig obj, verify it as you wish.
Here is a sample.
globalConfig.js
var globalConfig = {};
globalConfig.verify = function(key) {
return globalConfig.keys.testKey==key;
}
module.exports = globalConfig;
index.js (partial)
var globalConfig = require('./globalConfig.js');
var initObj = {
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse', // Don't forget to change to https if needed
liveQuery: {
classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
},
testKey: "this is test"
}
var api = new ParseServer(initObj);
globalConfig.keys = initObj;
and then you can use globalConfig.verify() to check your keys
a cloud code example
var globalConfig = require('../globalConfig.js');
Parse.Cloud.define('verify', function(req, res) {
res.success(globalConfig.verify(req.params.testKey));
});
or you can use express post
app.post('/test', function(req, res) {
//verify and response
})

Parse.Cloud.afterSave for sending push notifications not working from Heroku server

I did the migration, from Parse to Heroku and everything went smooth. At this point I didn't have any cloud code or push notifications set up on Parse. When I was done with the migration I begin to implement cloud code to handle push notification every time I save a new text message, but the Parse.Cloud.afterSave method is not running. I know main.js is working because if I implement
Parse.Cloud.define('hello', function(req, res) {
res.success('Hi');
});
I get "Hi" return to my console in Xcode, but for some reason Parse.Cloud.afterSave does nothing. I also know my Parse.Cloud.afterSave code is correct because it's that same code I use on another app through parse though. What am I missing?
Here in my index.js file
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var path = require('path');
var databaseUri = process.env.DATABASE_URI || process.env.MONGOLAB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
var api = new ParseServer({
databaseURI: databaseUri || '',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || '',
masterKey: process.env.MASTER_KEY || '',
fileKey: 'XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', // file key from parse
serverURL: process.env.SERVER_URL || '',
push: {
ios: {
pfx: '/Users/alexcruz/Desktop/Certificates.p12', // The filename of private key and certificate in PFX or PKCS12 format from disk
bundleId: 'com.daps.DapsPush', // The bundle identifier associate with your app
production: false // Specifies which environment to connect to: Production (if true) or Sandbox
}
}
});
var app = express();
// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));
// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);
// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
res.status(200).send('Make sure to star the parse-server repo on GitHub!');
});
// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function(req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});
var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpServer);
Here is my main.js file
//Push Notification for messages that are received
Parse.Cloud.afterSave("MXTMessage", function(request) {
var messageText = request.object.get('message');
var usersReceived = request.object.get('receiver');
var currentUser = Parse.User.current();
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo('user', usersReceived);
pushQuery.notEqualTo('user', currentUser);
Parse.Push.send({
where: pushQuery, // Set our Installation query
data: {
alert: "New message: " + messageText
}
}, {
success: function() {
// Push was successful
},
error: function(error) {
throw "Got an error " + error.code + " : " + error.message;
}
});
});
Thank you
As I am not allowed to comment, I'm going to have to put this in an answer, but just treat it as a comment:
Did you verify the function itself is actually never being called e.g. by adding a console.log at the beginning of the function, or could it be that push itself is not working (you can check that by sending pushes via REST API Calls)? For example, push seems to be broken in parse-server 2.2.0, I had to downgrade to 1.6.0 to get it working.
Workaround could be to create a cloud code function for sending the push and have this function explicitly called by the clients after the message has been saved on the server.
Also you should check this: https://github.com/ParsePlatform/parse-server/issues/301 as you are using Parse.User.current() in your code.
Also, I get the impression that parse-server is not really stable at this time. I experience many bugs using parse-server and Heroku that the app running on parse.com does not have.

Parse to Heroku migration: Parse-server cloud code doesn't work

I succeeded to migrate my app from Parse to Heroku, now my AppDelegate use this code:
[Parse initializeWithConfiguration:[ParseClientConfiguration configurationWithBlock:^(id<ParseMutableClientConfiguration> configuration) {
configuration.applicationId = #"xxxxxxxx";
configuration.clientKey = #"xxxxxxxx";
configuration.server = #"http://xxxxxxxx.herokuapp.com/parse";
}]];
and not
// [Parse setApplicationId:#"xxxxxxxx"
// clientKey:#"xxxxxxxx"];
// [PFUser enableRevocableSessionInBackground];
Everything works except the cloud code, when I run a cloud code, this is the error from Simulator: [Error]: Invalid function. (Code: 141, Version: 1.12.0)
Here is my cloud file path: /Users/Viny/heroku/parse-server-example/cloud/main.js
I updated and push it with the same main.js from Parse.
Here is my index.js:
// Example express application adding the parse-server module to expose Parse
// compatible API routes.
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var databaseUri = process.env.DATABASE_URI || process.env.MONGOLAB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
var api = new ParseServer({
databaseURI: process.env.DATABASE_URI || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: 'xxxxxxx',
masterKey: 'xxxxxxx',
fileKey: 'xxxxxxx',
clientKey: 'xxxxxxx',
serverURL: 'http://localhost:1337/parse'
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey
var app = express();
// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);
// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
res.status(200).send('I dream of being a web site.');
});
var port = process.env.PORT || 1337;
app.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
Cloud code works as expected with Parse, but doesn't work with Heroku...
Instead of this
configuration.server = #"http://xxxxxxxx.herokuapp.com/parse";
Do this
configuration.server = #"http://xxxxxxxx.herokuapp.com/parse/";
Well, I think I've found the problem, I've two "personal apps" on Heroku for my iOS app: "chilln" (my iOS app name) and "rocky-reef-28464" (automatically created by following this tuto: https://learnappmaking.com/how-to-migrate-parse-app-parse-server-heroku-mongolab/)
I changed my configuration.server to : http://rocky-reef-28464.herokuapp.com/parse/
and now it seems to recognize the cloud code, just this error on simulator: [Error]: <null> (Code: 141, Version: 1.12.0)
Here is a screen of my personal apps on Heroku:
Should I have only one personal apps ?
chilln has the add-ons MongoLab and cfg var: "app_id", "master_key", "mongolab_url", "parse_mount". rocky-reef-28464 hasn't add-ons MongoLab but has only one cfg var: "DATABASE_URI", and has the git heroku repo (I think)
What I've to do ? Merge the two app to one ?

Resources