Upload media with unofficial Instagram API - ruby

I'm writing a script that uploads photos to Instagram by schedule. The official Instagram API does not allow media uploads. I found that the only solution today is to use unofficial API. So, I'm trying to use it but it responds with 301 error to all my requests.
Ruby code:
url = 'https://instagr.am/api/v1/accounts/login/'
RestClient.post url, { username: 'username', password: 'password', device_id: '0000' }, user_agent: 'Instagram'
# RestClient::MovedPermanently: 301 Moved Permanently
Or curl:
$ curl -k --data "username=username&password=password&device_id=0000" --header "User-Agent: Instagram" https://instagr.am/api/v1/accounts/login/
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
Can you help me to find an error in my requests or suggest a better solution how to upload media to Instagram?

Instagram has put in place a signature that is required for "unofficial" API requests.. if you can find out how to generate that signature then you'll be golden... I've got a general understanding of how it's done by reviewing their android version's source code but I never quite cracked the process and haven't had the time to spend on it..
There are some third party clients out there that can do it but IG seems to be pretty good at detecting and deleting those photos.. and often banning the account.

Related

drf_yasg and amazon api gateway returns json instead of html ui

I have setup my python api service using djangorestframework and I am using drf_yasg for showing swagger docs for my api.
Here is glance of setup:
schema_view = get_schema_view(
openapi.Info(
title='My API',
default_version='v1',
description='rest service',
terms_of_service='',
contact=openapi.Contact(email='my#email'),
license=openapi.License(name='BSD License'),
),
public=False,
)
urlpatterns = [
path('pyapi/weather/', include('apps.weather.urls')),
re_path(r'^pyapi/swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
re_path(r'^pyapi/swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
re_path(r'^pyapi/redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]
Next I setup this api with amazon ec2 and stuff, and I am using Amazon API Gateway to access the api from containers.
Now the problem is when I try to access that using api gateway domain, it returns swagger JSON instead of HTML.
I tried several things like setting Content-Type mappings in method response and integration response but nothing works.
In my local machine it shows html as expected, so I am suspecting problem is in my gateway settings.
I highly appreciate if someone can help!
Ok I solved mystery!
After tons of tries and looking here and there, I found there was problem in API Gateway Request header setting.
Actually drf-yasg also kind of weird let me tell you why.
After setting up urls as I shown in first image, if you try to access http://localhost:8000/pyapi/swagger/ it shows UI perfectly.
At that time value of request header is Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Now same URL if you pass request header "Accept: application/json" then istead of showing html UI, it shows swagger JSON! wutt!!
That I found in Amazon API Gateways's test method's output. It was by default sending "Accept: application/json" and thats why I was always getting swagger.json in output. That was showstopper thing!
I changed it to Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 and now I could see UI perfectly!
I hope this will save time of many other people like me who are new to this kind of stuff!

How to submit a page in Oracle Apex using curl

I have a login page in an Oracle Apex application that works fine with a normal web browser like chrome. However when i try to perform the same operation using CURL (command-line browser), a HTTP 404 error is returned:
Request:
curl -i -d "P9999_USERNAME=MOIZ&P9999_PASSWORD=xxxx" -X POST http://localhost:8080/apex/f?p=101:9999:0:
Response:
HTTP/1.1 404 Not found
Server: Oracle XML DB/Oracle Database
Content-Type: text/html
Transfer-Encoding: chunked
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>404 Not found</TITLE>
</HEAD><BODY><H1>Not found</H1>
The requested URL /apex/f was not found on this server</BODY></HTML>
Using a normal browser, there are two sever request: one GET and one POST. However when using curl i am just making a single POST request.
Is that difference the cause of problem?
Is it possible to POST apex page without calling GET?
If yes then whether this solution will also work for file uploads?
Based on the post Python web scraping with BS using correct url? I was able to get answer to my above questions. [although this post uses python's requests and BeautifulSoup libraries for demonstration purpose, I think with some shell/windows scripting it may also be achievable with curl too]
Is that difference the cause of problem?
For POST request in APEX, we need to first perform a GET request as APEX expects the following hidden items to be sent as a payload of POST request
p_flow_id # application id
p_flow_step_id # page id
p_instance # session id
p_page_submission_id # page submission id
p_request # request
p_md5_checksum # md5 checksum
p_page_checksum # page checksum
p_arg_names # list of arguments
In addition, you may also need to add your page specific input items. For example,
p_t01 # username
p_t02 # password
Is it possible to POST apex page without calling GET?
For reasons mentioned in above answer, GET request will be required before POST request can be performed.

Google Sign-in is not working

I tried to use Google Sign-in for my website, however, it keeps giving me 400 error.
I referenced this article: https://developers.google.com/identity/sign-in/web/sign-in, and my code is really simple:
<html>
<head>
<title>Test Google Login</title>
<script src="https://apis.google.com/js/platform.js" async defer></script>
<meta name="google-signin-client_id" content="<CHANGE IT>">
<script>
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
console.log('ID: ' + profile.getId());
console.log('Name: ' + profile.getName());
console.log('Image URL: ' + profile.getImageUrl());
console.log('Email: ' + profile.getEmail());
}
</script>
</head>
<body>
<div class="g-signin2" data-onsuccess="onSignIn"></div>
</body>
</html>
When I click Sign-in button, it popups a window, and after logged in, it gave me 400 error as below:
400. That’s an error.
The requested URL was not found on this server. That’s all we know.
I guess it's redirect issue, but I don't know how to configure it. So I checked url it returned to me:
https://accounts.google.com/o/oauth2/auth?fetch_basic_profile=true&scope=email+profile+openid&response_type=permission&e=3100087&redirect_uri=storagerelay://http/127.0.0.1:8000?id%3Dauth867179&ss_domain=http://127.0.0.1:8000&client_id=378468243311-9dt7m9ufa9mee305j1b12815put5betb.apps.googleusercontent.com&openid.realm&hl=en&from_login=1&as=1b5f0a407ea58e11&pli=1&authuser=0
Why is redirect_uri "storagerelay://http/127.0.0.1:8000?id%3Dauth867179"?
Your code should work now.
Google fixed this issue. Origins with a trailing slash are also accepted now (Origin can be set in Google Developers Console > APIs & auth > Credentials).
Redirect URIs
http://localhost:8000/ this **/** at end solve my problem
JavaScript origins
http://localhost:8000
NOTE: localhost and 127.0.0.1 conflicts can create problems for you sometime
Hi I faced exactly same problem.
Regarding my case, the problem is that OAuth try to redirect to url of "127.0.0.1?id=authxxxxx" where xxxxx is random 5 digits.
Thus I added following four urls at Redirect URI Google Developers Console.
I am not sure which one hits the rule, but I could workaround with this
(1) http://127.0.0.1/*
(2) https of (1)
(3) http://127.0.0.1
(4) https of (3)
Hope it also works for you.
To test on localhost environment, here's things we should to do:
Add "http://localhost:8000" to "JavaScript origins"
Remove everything from "Redirect URIs", because JavaScript API doesn't need any redirect URIs
[1] https://developers.google.com/identity/sign-in/web/devconsole-project
I'm also having the same problem, and was able to get past it by using "localhost" instead of the ip address. It's not a great solution, but it was sufficient for me to continue debugging in dev, so I just thought I'd mention it.
edit: keep in mind that you will have to add http://localhost to your Google Oauth Javascript Origins.
I had the same problem yesterday. I had OAuth credentials with localhost and my-server.com. So, I fixed this problem creating a new OAuth credentials only for my-server.com, without localhost. Obviusly, my app uses these new credentials.
I found out that error disappears after clearing ACCOUNT_CHOOSER accounts.google.com cookie.
Replace everywherehttp://127.0.0.1:8000/ to HTTP://localhost:8000/even in your browser too. The Problem comes when you use http://127.0.0.1:8000/ either in the developer console or a browser.

cross domain request with dojo

I am attempting a cross domain request with dojo. External url is of MIME type text/html the only content on the page is something like 1236. I tried
dojo.require("dojo.io.script");
dojo.ready(function() {
dojo.io.script.get({
url: "theexternalurl",
callbackParamName: "jsoncallback",
load: function(data) {
console.log(data);
}
});
});,
But that was no good. Any ideas on how this can be done with dojo?
I suspect you are bumping into the browser security here. Cross-domain requests will only work when using iframes or injecting scripts (as you have done) and when the content of that script is valid "text/javascript".
If you are trying to load "text/html" into the script, it won't work as it isn't a valid script. It is something most of us have tried to do at some point. I have spent hours trying to get around cross-domain restrictions and found the security blocking it to be solid.
See my answer here for more details.
If all you are trying to do is load the content onto the page then you could use an <iframe>. However, if you are trying to parse the loaded content in some way than I'm afraid it is a dead-end. Probably not the answer you were hoping for but it'll save you hours of frustration.

How to manually send HTTP POST requests from Firefox or Chrome browser

I want to test some URLs in a web application I'm working on. For that I would like to manually create HTTP POST requests (meaning I can add whatever parameters I like).
Is there any functionality in Chrome and/or Firefox that I'm missing?
I have been making a Chrome app called Postman for this type of stuff. All the other extensions seemed a bit dated so made my own. It also has a bunch of other features which have been helpful for documenting our own API here.
Postman now also has native apps (i.e. standalone) for Windows, Mac and Linux! It is more preferable now to use native apps, read more here.
CURL is awesome to do what you want! It's a simple, but effective, command line tool.
REST implementation test commands:
curl -i -X GET http://rest-api.io/items
curl -i -X GET http://rest-api.io/items/5069b47aa892630aae059584
curl -i -X DELETE http://rest-api.io/items/5069b47aa892630aae059584
curl -i -X POST -H 'Content-Type: application/json' -d '{"name": "New item", "year": "2009"}' http://rest-api.io/items
curl -i -X PUT -H 'Content-Type: application/json' -d '{"name": "Updated item", "year": "2010"}' http://rest-api.io/items/5069b47aa892630aae059584
Firefox
Open Network panel in Developer Tools by pressing Ctrl+Shift+E or by going Menubar -> Tools -> Web Developer -> Network. Select a row corresponding to a request.
Newer versions
Look for a resend button in the far right. Then a new editing form would open in the left. Edit it.
Older versions
Then Click on small door icon on top-right (in expanded form in the screenshot, you'll find it just left of the highlighted Headers), second row (if you don't see it then reload the page) -> Edit and resend whatever request you want
Forget the browser and try CLI. HTTPie is a great tool!
CLI HTTP clients:
HTTPie
Curlie
HTTP Prompt
Curl
wget
If you insist on a browser extension then:
Chrome:
Postman - REST Client (deprecated, now has a desktop program)
Advanced REST client
Talend API Tester - Free Edition
Firefox:
RESTClient
Having been greatly inspired by Postman for Chrome, I decided to write something similar for Firefox.
REST Easy* is a restartless Firefox add-on that aims to provide as much control as possible over requests. The add-on is still in an experimental state (it hasn't even been reviewed by Mozilla yet) but development is progressing nicely.
The project is open source, so if anyone feels compelled to help with development, that would be awesome: https://github.com/nathan-osman/Rest-Easy
* the add-on available from http://addons.mozilla.org will always be slightly behind the code available on GitHub
You specifically asked for "extension or functionality in Chrome and/or Firefox", which the answers you have already received provide, but I do like the simplicity of oezi's answer to the closed question "How can I send a POST request with a web browser?" for simple parameters. oezi says:
With a form, just set method to "post"
<form action="blah.php" method="post">
<input type="text" name="data" value="mydata" />
<input type="submit" />
</form>
I.e., build yourself a very simple page to test the POST actions.
I think that Benny Neugebauer's comment on the OP question about the Fetch API should be presented here as an answer since the OP was looking for a functionality in Chrome to manually create HTTP POST requests and that is exactly what the fetch command does.
There is a nice simple example of the Fetch API here:
// Make sure you run it from the domain 'https://jsonplaceholder.typicode.com/'. (cross-origin-policy)
fetch('https://jsonplaceholder.typicode.com/posts',{method: 'POST', headers: {'test': 'TestPost'} })
.then(response => response.json())
.then(json => console.log(json))
Some of the advantages of the fetch command are really precious:
It's simple, short, fast, available and even as a console command it stored on your chrome console and can be used later.
The simplicity of pressing F12, write the command in the console tab (or press the up key if you used it before) then press Enter, see it pending and returning the response is what making it really useful for simple POST requests tests.
Of course, the main disadvantage here is that, unlike Postman, this won't pass the cross-origin-policy, but still I find it very useful for testing in local environment or other environments where I can enable CORS manually.
Here's the Advanced REST Client extension for Chrome.
It works great for me -- do remember that you can still use the debugger with it. The Network pane is particularly useful; it'll give you rendered JSON objects and error pages.
For Firefox there is also an extension called RESTClient which is quite nice:
RESTClient, a debugger for RESTful web services
It may not be directly related to browsers, but Fiddler is another good software.
You could also use Watir or WatiN to automate browsers. Watir is written for Ruby and Watin is for .NET languages. I am not sure if it's what you are looking for, though.
http://watin.sourceforge.net/
http://watir.com/
There have been some other clients born since the rise of Postman that is worth mentioning here:
Insomnia: with both desktop application and Chrome plugin
Hoppscotch: previously known as Postwoman, and with a Chrome plugin available as well. You can also make it work locally with docker if you want to get funny
Paw: if you are on Mac
Advanced Rest Client: already mentioned as a Chrome plugin, but it is worth pointing out that it also has a desktop application
soapUI: written in Java and with lots of testing functionality
Boomerang: yet another way to test APIs. It comes with SOAP integration and it also has a Chrome plugin available
Thunder Client: if you use VS Code as your text editor then you should go and check out this awesome extension
Try Runscope. A free tool sampling their service is provided at https://www.hurl.it/.
You can set the method, authentication, headers, parameters, and body. The response shows status code, headers, and body. The response body can be formatted from JSON with a collapsable hierarchy.
Paid accounts can automate test API calls and use return data to build new test calls.
COI disclosure: I have no relationship to Runscope.
Check out http-tool for Firefox...
Aimed at web developers who need to debug HTTP requests and responses.
Can be extremely useful while developing REST based API.
Features:
GET
HEAD
POST
PUT
DELETE
Add header(s) to request.
Add body content to request.
View header(s) in response.
View body content in response.
View status code of response.
View status text of response.
So it occurs to me that you can use the console, create a function, and just easily send requests from the console, which will have the correct cookies, etc.
so I just grabbed this from here: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#supplying_request_options
// Example POST method implementation:
async function postData(url = '', data = {}, options = {}) {
// Default options are marked with *
let defaultOptions = {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data) // body data type must match "Content-Type" header
}
// update the default options with specific options (e.g. { "method": "GET" } )
const requestParams = Object.assign(defaultOptions, options);
const response = await fetch(url, requestParams);
return response.text(); // displays the simplest form of the output in the console. Maybe changed to response.json() if you wish
}
IF YOU WANT TO MAKE GET REQUESTS, you can just put them in your browser address bar!
if you paste that into your console, then you can make POST requests by repeatedly calling your function like this:
postData('https://example.com/answer', { answer: 42 })
.then(data => {
console.log(data); // you might want to use JSON.parse on this
});
and the server output will be printed in the console (as well as all the data available in the network tab)
This function assumes you are sending JSON data. If you are not, you will need to change it to suite your needs
You can post requests directly from the browser with ReqBin.
No plugin or desktop application is required.
I tried to use postman app, had some auth issues.
If you have to do it exclusively using browser, go to network tab, right click on the call, say edit and send response. There is a similar ans on here about Firefox, this right click worked for me on edge and pretty sure it would work for chrome too
Windows CLI solution
In PowerShell you can use Invoke-WebRequest. Example syntax:
Invoke-WebRequest -Uri http://localhost:3000 -Method POST -Body #{ username='clever_name', password='hunter2' } -UseBasicParsing
On systems without Internet Explorer, you need the -UseBasicParsing flag.
The question being 12 years old now, it is easy to understand why the author asked a solution for Firefox or Chrome back then. After 12 years though, there are also other browsers and the best one which does not involve any add-ons or additional tools is Microsoft Edge.
Just open devtools (F12) and then Network Console tab (not the Network or Console tab. Click on + sign and open it, if it is not visible.).
And here is the official guide:
https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/network-console/network-console-tool
Have fun!

Resources