anyone knows what's wrong with this code.
The address from the api gateway returns {"message": "Missing Authentication Token"}.
All code deploy by serverless framework on AWS.
JS custom.js
var socket;
// Connect to the WebSocket and setup listeners
function setupWebSocket(username, token) {
socket = new ReconnectingWebSocket(" {api endpoint}?token=" + token);
socket.onopen = function(event) {
data = {"action": "getRecentMessages"};
socket.send(JSON.stringify(data));
};
socket.onmessage = function(message) {
var data = JSON.parse(message.data);
data["messages"].forEach(function(message) {
if ($("#message-container").children(0).attr("id") == "empty-message") {
$("#message-container").empty();
}
if (message["username"] === username) {
$("#message-container").append("<div class='message self-message'><b>(You)</b> " + message["content"]);
} else {
$("#message-container").append("<div class='message'><b>(" + message["username"] + ")</b> " + message["content"]);
}
$("#message-container").children().last()[0].scrollIntoView();
});
};
}
// Sends a message to the websocket using the text in the post bar
function postMessage(token){
var content = $("#post-bar").val();
if (content !== "") {
data = {"action": "sendMessage", "token": token, "content": content};
socket.send(JSON.stringify(data));
$("#post-bar").val("");
}
}
handler.py
def _send_to_connection(connection_id, data, event):
gatewayapi = boto3.client("apigatewaymanagementapi",
endpoint_url="https://" + event["requestContext"]["domainName"] +
"/" + event["requestContext"]["stage"])
return gatewayapi.post_to_connection(ConnectionId=connection_id,
Data=json.dumps(data).encode('utf-8'))
Contrary to the message, the issue is not actually a missing authentication token. API Gateway returns the same message when the endpoint you are accessing is not exactly correct; i.e. does not exist, probably due to some typo or slight misconfiguration. I would suggest confirming that your endpoint is valid and re-check that.
The reason you get this message is because if they returned a 404 it meant that you now know that the (invalid) endpoint you called does not exist. But that also means that you could do a brute force process of checking all possible endpoints and any not returning 404 do exist but behind some kind of firewall, authentication system or API Key. By returning 403 for all endpoints, even if they don't exist, AWS are improving their security posture. Its the same reason that on a login form you don't return a message such as "Username does not exist", because otherwise someone could find a way to find valid usernames based on your error message.
Hope that helps
Related
So I have some Swift code that send a request to my local host
//
// ContentView.swift
// Shared
//
// Created by Ulto4 on 10/23/21.
//
import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
Text("Hello, world!")
.padding()
Button(action : {
self.fu()
}, label: {
Image(systemName: "pencil").resizable().aspectRatio(contentMode:.fit)
})
}
}
func fu(){
let url = URL(string: "http://127.0.0.1:5000/232")
guard let requestUrl = url else { fatalError() }
var request = URLRequest(url: requestUrl)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print("Error took place \(error)")
return
}
if let response = response as? HTTPURLResponse {
print("Response HTTP Status code: \(response.statusCode)")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
}
However, on my Flask app there are no get requests coming in and the function isn't running. There also isn't anything printing to the console.
I am fairly new to swift so I don't really know how to fix this.
Is there any other way to send requests in swift, if not, How would I fix this?
You are creating the URLSessionDataTask, but you never start it. Call task.resume(), e.g.
func performRequest() {
guard let url = URL(string: "http://127.0.0.1:5000/232") else {
fatalError()
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print("Error took place \(error)")
return
}
if let response = response as? HTTPURLResponse {
print("Response HTTP Status code: \(response.statusCode)")
}
}
task.resume() // you must call this to start the task
}
That having been said, a few caveats:
You are doing http rather than https. Make sure to temporarily enable insecure network requests with app transport settings, e.g.
You didn’t say if this was for macOS or iOS.
If running on physical iOS device, it will not find your macOS web server at 127.0.0.1 (i.e., it will not find a web server running on your iPhone). You will want to specify the IP number for your web server on your LAN.
If macOS, make sure to enable outbound network requests in the target’s “capabilities”:
You asked:
Is there any other way to send requests in swift?
It is probably beyond the scope of your question, but longer term, when using SwiftUI, you might consider using Combine, e.g., dataTaskPublisher. When running a simple “what was the status code” routine, the difference is immaterial, but when you get into more complicated scenarios where you have to parse and process the responses, Combine is more consistent with SwiftUI’s declarative patterns.
Let us consider a more complicated example where you need to parse JSON responses. For illustrative purposes, below I am testing with httpbin.org, which echos whatever parameters you send. And I illustrate the use of dataTaskPublisher and how it can be used with functional chaining patterns to get out of the mess of hairy imperative code:
struct SampleObject: Decodable {
let value: String
}
struct HttpBinResponse<T: Decodable>: Decodable {
let args: T
}
class RequestService: ObservableObject {
var request: AnyCancellable?
let decoder = JSONDecoder()
#Published var status: String = "Not started yet"
func startRequest() {
request = createRequest().sink { completion in
print("completed")
} receiveValue: { [weak self] object in
self?.status = "Received " + object.value
}
}
func createRequest() -> AnyPublisher<SampleObject, Error>{
var components = URLComponents(string: "https://httpbin.org/get")
components?.queryItems = [URLQueryItem(name: "value", value: "foo")]
guard let url = components?.url else {
fatalError("Unable to build URL")
}
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.decode(type: HttpBinResponse<SampleObject>.self, decoder: decoder)
.map(\.args)
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}
struct ContentView: View {
#ObservedObject var requestService = RequestService()
var body: some View {
VStack{
Text("Hello, world!")
.padding()
Button {
requestService.startRequest()
} label: {
Image(systemName: "pencil").resizable().aspectRatio(contentMode:.fit)
}
Text(requestService.status)
}
}
}
But, like I said, it is beyond the scope of this question. You might want to make sure you get comfortable with SwiftUI and basic URLSession programming patterns (e.g., making sure you resume any tasks you create). Once you have that mastered, you can come back to Combine to write elegant networking code.
FWIW, like workingdog said, you could also use the new async-await rendition of data(for:delegate:). But when in the declarative world of SwiftUI, I would suggest Combine.
I'm using firebase UI to authenticate users in a given frontend. Facebook authentication is enabled. I need to implement a facebook data deletion callback so I need to make my backend do two things:
delete/disable the facebook sign in method from the user that issued the data deletion request from facebook
delete every trace of facebook data from my firebase user (the provider user info) but without deleting the user
However, I can't find anything in firebase admin's documentation to delete facebook data. So, how can I delete the data?
PD: Keep in mind that I want to delete the user's provider user info, but not the whole user (because I need the user to stay there for data consistency)
If someone is looking for a NodeJS implementation, this is how you can do it:
module.exports = functions.https.onRequest(async (req, res) => {
try {
const signedRequest = req.body.signed_request;
const userObj = parseSignedRequest(signedRequest, FB_SECRET_KEY);
const userRecord = await admin
.auth()
.getUserByProviderUid("facebook.com", userObj.user_id);
await admin.auth().deleteUser(userRecord.uid);
res.json({
url: "<status_url>",
confirmation_code: "<code>",
});
} catch (e) {
// console.log(e);
res.status(400).json({
message: "Bad Request",
});
}
});
function base64decode(data: string) {
while (data.length % 4 !== 0) {
data += "=";
}
data = data.replace(/-/g, "+").replace(/_/g, "/");
return Buffer.from(data, "base64").toString("utf-8");
}
function parseSignedRequest(signedRequest: string, secret: string) {
var encoded_data = signedRequest.split(".", 2);
// decode the data
var sig = encoded_data[0];
var json = base64decode(encoded_data[1]);
var data = JSON.parse(json);
if (!data.algorithm || data.algorithm.toUpperCase() != "HMAC-SHA256") {
throw Error(
"Unknown algorithm: " + data.algorithm + ". Expected HMAC-SHA256"
);
}
var expected_sig = crypto
.createHmac("sha256", secret)
.update(encoded_data[1])
.digest("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace("=", "");
if (sig !== expected_sig) {
throw Error("Invalid signature: " + sig + ". Expected " + expected_sig);
}
return data;
}
PS. There is no way to just unlink providers via Firebase Admin SDK for now so best we can do is delete the user data.
My frontend (ReactJS) is located at localhost:3000 which sends a request to my backend (localhost:5090/api/fetch/<name>)
frontend-snippet:
handleSubmit(event) {
//alert('A name was submitted: ' + this.state.value);
fetch('http://127.0.0.1:5090/api/fetch/' + this.state.value,
{
mode: 'no-cors'
}).then((response) => console.log(response));
event.preventDefault();
}
the backend receives the request:
127.0.0.1 - - [22/Oct/2020 10:54:44] "GET /api/fetch/212 HTTP/1.1" 200 -
and responses with {"stock": name}
Python
def get(self, name):
print(name)
return {"stock": name}
however, i'm unable to get the response.
What am I missing, that I can actualy see the response data of {"stock": <name>}?
Sending a request with no-cors returns an opaque type object.
Updating my backend to allow all sources
What happens with cross-origin requests from frontend JavaScript is that browsers by default block frontend code from accessing resources cross-origin. If Access-Control-Allow-Origin is in a response, then browsers will relax that blocking and allow your code to access the response.
from flask_cors import CORS
...
CORS(app, resources={r"/api/*": {"origins": "*"}})
and then removing the mode to cors in frontend
fetch('http://127.0.0.1:5090/api/fetch/' + this.state.value,
{
}).then(response => response.json())
.then(response => {
console.log(response)
})
.catch(error => {
console.log('Error ' + error);
})
successfully displays the data
(response)
{stock: "111"}
Can you try like this
.then(response => response.json())
.then(result => {
console.log(result);
})
})
.catch(error => {
console.log('Error ' + error);
})
code in Ejaz's answer should work just fine, But I'd recommned you to read the official documentation for fetch api
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
You cant just console.log the response from fetch api it just returns a promise,
you cant print response.body either as it returns a readable stream, Use interface methods on body to read the stream into completion.
You can call response.text() or response.json() depending on type of data your api returns.
Using fetch api, you have to deal with promises, I'll try to refactor your handleSubmit function using async/await, much cleaner way to deal with promises.
async handleSubmit(event) {
event.preventDefault();
try{
let response = await fetch('http://127.0.0.1:5090/api/fetch/'+this.state.value, {
mode: 'no-cors'});
console.log(await response.json());
}
catch(error => console.log('Error ' + error));
}
I am writing an application that integrates into a website that is already written in Meteor (I can't change that but I can add on to it). I am trying to send information from the Meteor application to my Flask server.
To do this I am using MeteorJs's HTTP module.
The code for this:
HTTP.post('http://127.0.0.1:5000/path', {
"content" : {"headers" : {"Content-Type": "application/json"}, "data": {time: getTime, data: getData()}}
},
(error, result) => {
if(error){
console.log(error);
console.log({time: getTime(), data: getData()})
}
else {
console.log(result);
}
}
)
getTime() and getData() both work independently outside this function, so they shouldn't be the source of error.
When I look at the JS console for when the event is being fired I receive the following message:
Error: Connection lost at XMLHttpRequest.xhr.onreadystateexchange and what was supposed to be sent to the Flask server.
When I look at the Flask server I see that it is receiving the post request with status code 200, but it seems like there is no data actually being received.
The code on the python end:
#app.route(r'path', methods=["POST"])
def get_data():
print(request.data)
print(request.args)
return "Hello World"
The print statements come out empty with this being shown on the console b'[object Object]' or ImmutableMultiDict([])
The Meteor app and the Flask app are both on different ports.
The problem I believe is on the MeteorJS side, since I used the curl linux function it works properly when I ping the flask server from there.
Is there a way to fix this error? If so how?
Hi "parameters" should be "data".
You can find all valid options in the docs.
Let me know if it works for you.
HTTP.post('http://127.0.0.1:5000/path', {
data : {time: getTime(), data: getData()}
}, (error, result) => {
if(error){
console.log(error);
console.log({time: getTime(), data: getData()})
} else {
console.log(result);
}
}
)
During the user migration I want to return "Incorrect username or password." as error message instead of "User does not exist"
Have been searching on google for a while, cannot find out how to replicate the following JS example in this documentation
https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html
exports.handler = (event, context, callback) => {
var user;
if ( event.triggerSource == "UserMigration_Authentication" ) {
// authenticate the user with your existing user directory service
user = authenticateUser(event.userName, event.request.password);
if ( user ) {
event.response.userAttributes = {
"email": user.emailAddress,
"email_verified": "true"
};
event.response.finalUserStatus = "CONFIRMED";
event.response.messageAction = "SUPPRESS";
context.succeed(event);
}
else {
// Return error to Amazon Cognito
callback("Bad password");
}
}
else if ( event.triggerSource == "UserMigration_ForgotPassword" ) {
// Lookup the user in your existing user directory service
user = lookupUser(event.userName);
if ( user ) {
event.response.userAttributes = {
"email": user.emailAddress,
// required to enable password-reset code to be sent to user
"email_verified": "true"
};
event.response.messageAction = "SUPPRESS";
context.succeed(event);
}
else {
// Return error to Amazon Cognito
callback("Bad password");
}
}
else {
// Return error to Amazon Cognito
callback("Bad triggerSource " + event.triggerSource);
}
};
It uses callback('message') in nodejs but I cannot find out how to do that in Python.
Stumbled on to this question
I can't find callback parameter in python lambda handler
Tried returning message string, but get "Exception during user migration"
Try raising a ValueError:
raise ValueError("My custom message")
For me, this changed the wording of the exception returned to the boto client from
An error occurred (UserNotFoundException) when calling the AdminInitiateAuth operation: Exception migrating user in app client aeiouffhfha
to the somewhat more useful
An error occurred (UserNotFoundException) when calling the AdminInitiateAuth operation: UserMigration failed with error My custom message.
So I have also tried raising an exception':
raise Exception('Incorrect username or password')
This still gives "Exception during user migration" in the hosted UI, but that worked on a custom login UI which respects the error message.