Asterisk ARI Caller id is always Anonymous - asterisk

I'm trying to make a outgoing call using asterisk and stasis.
From my app, i send a simple post to /ari/channels/create, like this:
params = {
endpoint: `PJSIP/${trunkPrefix}${numberOriginal}#${trunkName}`,
app: 'stasisApp',
channelId: uuidv4(),
appArgs: `digital,"${JSON.stringify(appArgs).replace(/\"/g, '\\"')}"`,
formats: 'ulaw',
};
url = `http://${asteriskHost}/ari/channels/create`;
const variables = {
'CALLERID(num)': callerId,
};
(async () => {
await axios.post(url, {
variables,
}, {
auth: {
username: '',
password: '',
},
params,
}).then(({ data }) => {
console.log(data);
}).catch(({response: {data}}) => {
console.log('Error', data);
});
})();
Then, i do dial() on the channel, but asterisk sets the From parameter like this:
From: "Anonymous" <sip:anonymous#anonymous.invalid>
I need to be able to set the callerid on outbound calls, i tried using CONNECTEDLINE(number), but isnt working either, also tried to set the callerid using /channels/{channelId}/variable endpoint, but when the call goes out, the From header is still anonymous. Any ideas?
I'm using asterisk 19.

I managed to solve my problem, after creating the channel I was doing another things before using dial() method, nothing fancy, just creating a bridge, start a recording on the bridge and putting another channel on the bridge, but apparently something during those operations made the callerid on the original channel go away, I just did an request to setChannelVar endpoint with CONNECTEDLINE(num) just before the dial() and it worked.
Thanks for the help

Related

oak on Deno - How do I build a URL to a route?

I come from a land of ASP.NET Core. Having fun learning a completely new stack.
I'm used to being able to:
name a route "orders"
give it a path like /customer-orders/{id}
register it
use the routing system to build a URL for my named route
An example of (4) might be to pass a routeName and then routeValues which is an object like { id = 193, x = "y" } and the routing system can figure out the URL /customer-orders/193?x=y - notice how it just appends extraneous key-vals as params.
Can I do something like this in oak on Deno?? Thanks.
Update: I am looking into some functions on the underlying regexp tool the routing system uses. It doesn't seem right that this often used feature should be so hard/undiscoverable/inaccessible.
https://github.com/pillarjs/path-to-regexp#compile-reverse-path-to-regexp
I'm not exactly sure what you mean by "building" a URL, but the URL associated to the incoming request is defined by the requesting client, and is available in each middleware callback function's context parameter at context.request.url as an instance of the URL class.
The documentation provides some examples of using a router and the middleware callback functions that are associated to routes in Oak.
Here's an example module which demonstrates accessing the URL-related data in a request:
so-74635313.ts:
import { Application, Router } from "https://deno.land/x/oak#v11.1.0/mod.ts";
const router = new Router({ prefix: "/customer-orders" });
router.get("/:id", async (ctx, next) => {
// An instance of the URL class:
const { url } = ctx.request;
// An instance of the URLSearchParams class:
const { searchParams } = url;
// A string:
const { id } = ctx.params;
const serializableObject = {
id,
// Iterate all the [key, value] entries and collect into an array:
searchParams: [...searchParams.entries()],
// A string representation of the full request URL:
url: url.href,
};
// Respond with the object as JSON data:
ctx.response.body = serializableObject;
ctx.response.type = "application/json";
// Log the object to the console:
console.log(serializableObject);
await next();
});
const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());
function printStartupMessage({ hostname, port, secure }: {
hostname: string;
port: number;
secure?: boolean;
}): void {
if (!hostname || hostname === "0.0.0.0") hostname = "localhost";
const address =
new URL(`http${secure ? "s" : ""}://${hostname}:${port}/`).href;
console.log(`Listening at ${address}`);
console.log("Use ctrl+c to stop");
}
app.addEventListener("listen", printStartupMessage);
await app.listen({ port: 8000 });
In a terminal shell (I'll call it shell A), the program is started:
% deno run --allow-net so-74635313.ts
Listening at http://localhost:8000/
Use ctrl+c to stop
Then, in another shell (I'll call it shell B), a network request is sent to the server at the route described in your question — and the response body (JSON text) is printed below the command:
% curl 'http://localhost:8000/customer-orders/193?x=y'
{"id":"193","searchParams":[["x","y"]],"url":"http://localhost:8000/customer-orders/193?x=y"}
Back in shell A, the output of the console.log statement can be seen:
{
id: "193",
searchParams: [ [ "x", "y" ] ],
url: "http://localhost:8000/customer-orders/193?x=y"
}
ctrl + c is used to send an interrupt signal (SIGINT) to the deno process and stop the server.
I am fortunately working with a React developer today!
Between us, we've found the .url(routeName, ...) method on the Router instance and that does exactly what I need!
Here's the help for it:
/** Generate a URL pathname for a named route, interpolating the optional
* params provided. Also accepts an optional set of options. */
Here's it in use in context:
export const routes = new Router()
.get(
"get-test",
"/test",
handleGetTest,
);
function handleGetTest(context: Context) {
console.log(`The URL for the test route is: ${routes.url("get-test")}`);
}
// The URL for the test route is: /test

Axios post request to Firebase Auth REST API produces 400 error

I have an instance of Axios:
import axios from 'axios';
const instance = axios.create({
baseURL: 'https://identitytoolkit.googleapis.com/v1'
});
export default instance;
Then I import it in my signup.vue file:
<script>
import axios from '../../axios-auth';
...
</script>
In that Vue file I have a signup form, which runs the following method once I hit the Submit button:
onSubmit() {
const formData = {
email: this.email,
age: this.age,
password: this.password,
confirmPassword: this.confirmPassword,
country: this.country,
hobbies: this.hobbyInputs.map(hobby => hobby.value),
terms: this.terms
};
console.log(formData);
axios.post('/accounts:signUp?key=my_key_goes_here', {
email: formData.email,
password: formData.password,
returnSecureToken: true
})
.then(res => {
console.info(res);
})
.catch(error => {
console.error(error);
});
}
I'm getting a 403 error - forbidden 400 error - bad request.
I tried to change headers:
instance.defaults.headers.post["Access-Control-Allow-Origin"] = "localhost";
instance.defaults.headers.common["Content-Type"] = "application/json";
But that didn't help.
I'm working from localhost and I saw that localhost is allowed by default. I tried also to add 127.0.0.1 to the list, but that also didn't help.
What am I missing? How can I make this request work?
If you get a 400 error it is maybe because you get an error from the API itself:
Common error codes
EMAIL_EXISTS: The email address is already in use by another account.
OPERATION_NOT_ALLOWED: Password sign-in is disabled for this project.
TOO_MANY_ATTEMPTS_TRY_LATER: We have blocked all requests from this device due to unusual activity. Try again later.
As a matter of fact, those errors return an HTTP Status Code of 400.
You can see the exact response message (e.g. EMAIL_EXISTS) by doing the following with axios:
axios.post('/accounts:signUp?key=my_key_goes_here', {
email: formData.email,
password: formData.password,
returnSecureToken: true
})
.then(res => {
console.info(res);
})
.catch(error => {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
} else if (error.request) {
console.log(error.request);
} else {
console.log("Error", error.message);
}
});
See https://github.com/axios/axios#handling-errors
I agree with you as i have tried many approaches but was not getting the result. Hence i have tried to change the code.
You need to make two changes in your code.
1] You need to comment the instance.defaults.headers.post["Access-Control-Allow-Origin"] = "localhost"; because you are providing the authentication globally. As, firebase provides the feature of authentication and you are connecting the web app with REST API.
2] You need to add { headers: {'Content-Type': 'application/json' } in the axios.post() method to prevent it from CORS Error.
Following this approach i hope you can get the respective output.
Happy Coding!
Directly call
https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[yourkey]
No need to keep it in a separate file
Anyone who comes to the thread in future. I faced this issue and lost in debugging and worked with fetch. It was tiresome and took me a day but i made axios work. Here is the code.
const data = JSON.stringify({
idToken: authContext.token,
password: enteredNewPassword,
returnSecureToken: false,
});
// Send the valid password to the endpoint to change password
axios
.post(
"https://identitytoolkit.googleapis.com/v1/accounts:update?key=[Your Key]",
data,
{
headers: {
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log(response.data);
})
.catch((err) => {
console.log(err.message);
});
Remember to Stringify the data you want to send. Stringify it outside of the http request and then pass that variable. Don't know why but this helps!
Lastly remember to add the header when sending the request to firebase. Make sure axios.post is on the same line. My formatter gave a line break which was also cause of error.
Hope it helps :)

How To guarantee that the input of the smart contract is not manipulated?

Let's say that my DApp got the following (smart) contract:
module.exports = {
winner: async function(value) {
if (value===10) {
}
}
}
Now the Dapp user can do someting which invoke the contract with some value which can be 10 or not. The Dapp determines if value equals 10 or not. So far so good.
But now it seems that anyone with a valid secret (and some XAS send to the Dapps's side chain) can invoke the contract with a simple PUT request to api/<dappId>//transactions/unsigned with value set to whatever they want.
How to ensure that the value of value is set by the Dapp and can not be manipulated?
As far as i do understand Asch DApps run on a express server, with the cors middleware enabled, which means that anyone can do a request (GET, POST, PUT, etc ) from anywhere.
So one can invoke your contract easily with a script like that shown below:
const axios = require('axios');
var fee = '10000000'
var data = {
secret: "<your secret>",
fee: fee,
type: 1001, //the number for contractfile.function
args: 1000 // a very high score
}
axios.put('http://<domain>:4096/api/dapps/<dappid>/transactions/unsigned',data)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
Due to the above it is not possible to guarantee that in input is not manipulated (send from outside the DApp). Also see: https://github.com/AschPlatform/asch/issues/228

Firebase : How to secure content sent without login?

I'm building a hybrid mobile app with Firebase as my backend. I want to let users post on a wall any message they want without authentication, but I feel concerned about spam possibilities. I mean, if users don't have to be authenticated to be able to post, my security rules are basically empty and anyone who gets the endpoint can post an infinite amount of content. And I don't see what I could do against it.
So I know about anonymous auth, but I'm not sure if it really fix the issue. The endpoint remains open, after all, just behind the necessity to call a method before. It adds a little complexity but not much, I think.
What I wonder is if there is a possibility to check for the call origin, to make sure it comes from my app and nothing else. Or, if you have another idea to get this more secure, I'm open to everything. Thanks!
You can accomplish this using a combination of recaptcha on the client, and firebase cloud functions on the backend.
You send the message you want to add to the store along with the captcha to the cloud function. In the cloud function, we first verify the captcha. If this one is ok, we add the message to the store. This works, because when adding items to the store via a cloud function, firebase authentication rules are ignored.
Here's an example cloud function:
const functions = require('firebase-functions')
const admin = require('firebase-admin')
const rp = require('request-promise')
const cors = require('cors')({
origin: true,
});
admin.initializeApp();
exports.createUser = functions.https.onRequest(function (req, res) {
cors(req, res, () => {
// the body is a json of form {message: Message, captcha: string}
const body = req.body;
// here we verify whether the captcha is ok. We need a remote server for
// for this so you might need a paid plan
rp({
uri: 'https://recaptcha.google.com/recaptcha/api/siteverify',
method: 'POST',
formData: {
secret: '<SECRET>',
response: body.captcha
},
json: true
}).then(result => {
if (result.success) {
// the captcha is ok! we can now send the message to the store
admin.firestore()
.collection('messages')
.add(body.message)
.then(writeResult => {
res.json({result: `Message with ID: ${writeResult.id} added.`});
});
} else {
res.send({success: false, msg: "Recaptcha verification failed."})
}
}).catch(reason => {
res.send({success: false, msg: "Recaptcha request failed."})
})
});
})
And here's some more info: https://firebase.googleblog.com/2017/08/guard-your-web-content-from-abuse-with.html

How to emit data only to one client in Meteor streams

I am building a realtime game with Meteor streams. I need to update only one client - send a room ID from server. Users are not logged in so Meteor.userId() is null and therefore I can't use this: http://arunoda.github.io/meteor-streams/communication-patterns.html#streaming_private_page
There is only one URL (homepage) where all things happen. So I don't use any URL parameters for room. Everything is on the server.
I have tried to use Meteor.uuid() instead of Meteor.userId() but uuid is changed after each emit (which is strange).
In socket.io I would do this:
//clients is an array of connected socket ids
var clientIndex = clients.indexOf(socket.id);
io.sockets.socket(clients[clientIndex]).emit('message', 'hi client');
Is there any way to do this in Meteor streams or Meteor itself?
Well, this can be easily done if you decided to use database, but I guess it is not the best option if you have a large number of clients.
So another way to achieve this - without database - is to make a good use of the Meteor's publish/subscribe mechanism. Basically the way it could work is the following:
1. client asks server for a communication token (use Meteor.methods)
2. client subscribes to some (abstract) data set using that token
3. server publishes the required data based on the received token
So you will need to define a method - say getToken - on the server that generates tokens for new users (since you don't want to use accounts). This could be something more or less like this:
var clients = {}
Meteor.methods({
getToken: function () {
var token;
do {
token = Random.id();
} while (clients[token]);
clients[token] = {
dependency: new Deps.Dependency(),
messages: [],
};
return token;
},
});
A new client will need to ask for token and subscribe to the data stream:
Meteor.startup(function () {
Meteor.call('getToken', function (error, myToken) {
// possibly use local storage to save the token for further use
if (!error) {
Meteor.subscribe('messages', myToken);
}
});
});
On the server you will need to define a custom publish method:
Meteor.publish('messages', function (token) {
var self = this;
if (!clients[token]) {
throw new Meteor.Error(403, 'Access deniend.');
}
send(token, 'hello my new client');
var handle = Deps.autorun(function () {
clients[token].dependency.depend();
while (clients[token].messages.length) {
self.added('messages', Random.id(), {
message: clients[token].messages.shift()
});
}
});
self.ready();
self.onStop(function () {
handle.stop();
});
});
and the send function could defined as follows:
var send = function (token, message) {
if (clients[token]) {
clients[token].messages.push(message);
clients[token].dependency.changed();
}
}
That's a method I would use. Please check if it works for you.
I think using Meteor.onConnection() like a login would enable you to do what you want pretty easily in a publish function.
Something like this:
Messages = new Meteor.Collection( 'messages' );
if ( Meteor.isServer ){
var Connections = new Meteor.Collection( 'connections' );
Meteor.onConnection( function( connection ){
var connectionMongoId = Connections.insert( connection );
//example Message
Message.insert( {connectionId: connection.id, msg: "Welcome"});
//remove users when they disconnect
connection.onClose = function(){
Connections.remove( connectionMongoId );
};
});
Meteor.publish( 'messages', function(){
var self = this;
var connectionId = self.connection.id;
return Messages.find( {connectionId: connectionId});
});
}
if ( Meteor.isClient ){
Meteor.subscribe('messages');
Template.myTemplate.messages = function(){
//show all user messages in template
return Messages.find();
};
}
I have used database backed collections here since they are the default but the database is not necessary. Making Messages a collection makes the reactive publishing easy whenever a new message is inserted.
One way that this is different from streams is that all the messages sent to all clients will end up being kept in server memory as it tries to keeps track of all data sent. If that is really undesirable then you could use a Meteor.method so send data instead and just use publish to notify a user a new message is available so call the method and get it.
Anyway this is how I would start.

Resources