Freeswitch: Check external API Before Call - voip

I'm trying to create a Dialplan in freeswitch that hits an external API and waits for an "OK" HTTP response before initiating the outgoing call or stops the call if the response is anything but OK.
The reason I want to do this is to ensure that the calling user A) has a sufficient balance and B) is allowed to call the number they've requested to call in a pragmatic and dynamic way.
I cannot find any documentation that outlines this use case. Do I need to create my own extension (perhaps using ESL?) or is there a way I can do this with existing mods?
Thanks for any help.

You can use https://freeswitch.org/confluence/display/FREESWITCH/mod_curl.
Just an example:
<action application="curl" data="http://your_api_url/?from=${sip_from_user}" inline="true"/>
<condition field="${curl_response_code}" expression="200">
<action application="set" data="channel_var=${curl_response_data}"/>
<anti-action application="respond" data="500"/>
</condition>

Related

Send parameters to Cortana Skill

I created a chatbot which Cortana is using as a skill, it works great, however, I'm currently reading some parameters from a blob storage file and I'd like to make it more dynamic; is there a way to send parameters upon initialization of the skill coming from Cortana? I read here:
Get the user's profile and contextual information
That Cortana can read the UserInfo such as name, email, localization, etc, but I haven't seen any way to enter custom values that I can read once the message is received on init.
I would appreciate your help, thanks!
Don't forget that Cortana is conversational (RESTful, and for the most part stateless). Ask yourself what configuration is part of the dialog, versus what is part of service. If there is configuration that is sent from the user, then it makes sense to store it on the session using one of the three contexts described: user data, conversation data, or private conversation data. This is all botframework: manage state data.
There are a couple ways you can discern if Cortana is configured or not. If you have not stored the properties on userData, assume you are not configured and change your dialog flow. If you want to check at the time you are invoked, you can always do something like this if( session.message.entities[0].name === 'Microsoft.Launch' ) { ... }
In one of my skills, I just do this... if(! session.userData.bookName ) { session.beginDialog('openBook'); return; } where openBook sets the name.
If this is service related, then you can move your configuration where you like. Keeping it in Azure storage may still require a service restart to use changes (unless you continuously poll.) Conversely, you can put the configuration data in system properties (environment variables), either in your web.config or on the container. For example,
<configuration>
<appSettings>
<!-- update these with your BotId, Microsoft App Id and your Microsoft App Password-->
<add key="BotId" value="YourBotId" />
<add key="MicrosoftAppId" value="" />
<add key="MicrosoftAppPassword" value="" /> ...
You can set IIS to watch for changed in the config file to auto-restart.
Hope this helps.

Handling parallel REST post requests

I have created my own REST service based on the examples from "Domino Sample REST Service Feature" from 901v00_11.20141217-1000 version of XPages Extension Library.
As far as I understand the design of the library each REST request will be run in its own thread on the server. This approach does not allow to handle parallel POST requests to the same document.
I have not found any examples in XPages Extension Library which would handle post requests as transactions on the server, i.e. which would block the server resource for the whole request processing time and would put put next requests in the queue?
Can anybody point to the source code of the service which would allow to handle parallel requests?
The skeleton for my post request processing function is this
#POST
#Path(PATH_SEPARATOR + MyURL)
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response myPost(
String requestEntity,
#Context final UriInfo uriInfo)
{
LogMgr.traceEntry(this, "myPost");
RestContext.verifyUserContext();
String myJson = ... // Process post
Response response = buildResponse(myJson);
LogMgr.traceExit(this, "myPost", "OK");
return response;
}
And I would like to implement something like this
// Start transaction
String myJson = ... // Process post
// Stop transaction
Is there a way to do it in Java?
I suppose you could use document locking in traditional Notes/Domino context - and synchronized in Java :-)
Have you tried any of these? I cannot see why they should not work.
/John
I agree with John. You can use document locking to prevent simultaneous updates to the same document. You might also want to consider some changes to the definition of your REST API.
First, you imply you are using POST to update an existing document. Usually, POST is used to create a new resource. Consider using PUT instead of POST.
Second, even with document locking, you still might want to check for version conflicts. For example, let's say a client reads version 2 of a document and then attempts to update it. Meanwhile, another client has already updated the document to version 3. Many REST APIs use HTTP ETags to handle such version conflicts.

How to access another conditional flow in the same endpoint?

Background
We have an api proxy with two conditional flows:
GetAllProducts
GetSingleProduct
GetAllProducts gets all product from our backend server. Requests to GetAllProducts are cached for some time.
GetSingleProduct does not access our backend server. It will just access GetAllProducts to get all products and then find the single product and return it. It performs the request in node.
Issue
GetSingleProduct must know the url for the api proxy, and we don't want to hardcode the url. I have tried the following policy to add a query string parameter that is passed to the node server:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="assign-message-path">
<DisplayName>Assign Message Path</DisplayName>
<FaultRules/>
<Properties/>
<Add>
<Headers/>
<QueryParams>
<QueryParam name="apiProxyUri">{client.scheme}://{client.host}:{client.port}{message.uri}</QueryParam>
</QueryParams>
</Add>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
The issue is that client.host and client.port are 'wrong'. They are set to some other ip and port that I don't really know what mean. Perhaps they are apigee-internal. However, what matters is that it doesn't work, but if I modify the line to hard-coded host and port it works:
<QueryParam name="apiProxyUri">{client.scheme}://90.123.123.123:9001{message.uri}</QueryParam>
Other things I've tried
I have read the variable reference page to find other variables that potentially could be used, with no luck. I've also considered using the variable virtualhost.name but there is no variable called virtualhost.port that would be needed as well.
Update with remaining issues
I've modified the proxy according to the answers below from Srikanth and Mike Dunker. I've chosen to do it like Srikanth suggests (two separate proxy flows for GetAllProducts and GetSingleProduct). See current flow for GetSingleProduct here.
Extract Product policy xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="extract-product">
<DisplayName>Extract Product</DisplayName>
<FaultRules/>
<Properties/>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<JSONPayload>
<Variable name="product">
<JSONPath>$.[?(#.id == {main.id})]</JSONPath>
</Variable>
</JSONPayload>
<Source clearPayload="false">response</Source>
<VariablePrefix>main</VariablePrefix>
</ExtractVariables>
Remaining issues:
When the jsonpath matches a specific product, the result is an array with a single item. How can I get the item itself, instead of an array with a single item?
When the jsonpath does not match any product, the result is an empty array. In this case the step 'Fault Invalid Id' should execute. How should I define the condition for that step?
If you situation is same as "Call Another API Proxy from one API Proxy in the same organization" then its not recommended.
if the flows are in the same proxy, the you can put GetAllProducts in target flow and GetSingleProduct passes the request to the target flow containing GetAllProducts.
In summary,
For GetAllProducts
Proxy flow - none, Target flow - GetAllProducts
For GetSingleProduct
Proxy flow - GetSingleProduct, Target flow - GetAllProducts (same target end point as above)
Your solution can be simpler (and perform better) than calling back into the proxy.
1) Create a single proxy flow with a condition that matches both GetSingleProduct and GetAllProducts.
2) Proxy flow request #1: set a variable that specifies whether GetAllProducts or GetSingleProduct was called (or just save the pathsuffix). This way when you rewrite GetSingleProduct to look like GetAllProducts for your backend, you will be able to handle the GetSingleProduct steps later in the response.
3) Proxy flow request #2: handle the backend request just like you would for GetAllProducts in your current design: checking the response cache, building the GetAllProducts request, sending it.
4) Proxy flow response #1: handle the backend response just like you would for GetAllProducts in your current design: get the response, populate the response cache.
5) Proxy flow response #2: in the next steps, if the original request was GetSingleProduct, extract the single product from the response (after the cache check). You just need to have the GetSingleProduct condition for all the GetSingleProduct steps.
That should get you what you need without calling out again.
Answers to remaining issues
I don't think you can use "main.product.length == 0" in your "Fault Invalid Id" condition, but you could try it. Regardless, you'll need to do something to grab the single item (remaining issue #1).
I would probably create a JavaScript policy that follows your extract variables policy. It could check the length of the main.product array, and set a flag if the length is 0 (which could then be used for your fault rule condition). If the length is 1, you could grab the single matching product.

Occasionally disabling Pyramid middleware

Note: If it's any help, I'm using Pyramid 1.3.2. I know it's a little out of date, I would prefer not to update right away, but I might be able to force an update if the latest version provides better support for this use case.
The Pyramid-based application I'm working on has a strict authorization policy: all calls must be authenticated. Since 1) it's tedious to add this manually on every request handelr; and 2) we don't want anybody to "forget" adding authentication, we enforce this server-wide using a simple Pyramid middleware (tween) that verifies all incoming requests.
Recently, this restriction has been slightly relaxed: occasionally, some resources should support (safe & idempotent) GET without authentication.
It seems this is directly opposed to the usual design ideas behind authentication in most web frameworks (optional authentication), so I can't get it to work quite as expected.
QUESTION: What is the correct approach to implementing an authorization middleware that authenticates & verifies authorization by default, but can be disabled on a view-by-view basis?
So far, I've tried adding a simple decorator like so:
def allows_anonymous_access(f):
f.allows_anonymous_access = True; return f
#allows_anonymous_access
def my_pyramid_view(request):
# ...
In my middleware, I would like to use it like this:
def authorization_middleware(handler, registry):
def verify_authorization(request):
# Identify the user making the request. Make sure we get the
# user's identify if provided, even when the request handler
# allows anonymous access.
try:
request.principal = extract_user(request)
except InvalidCredentials, error:
if getattr(handler, 'allows_anonymous_access', False):
request.principal = AnonymousUser()
else:
raise HTTPUnauthorized(...)
# Invoke the handler.
return handler(request)
# Middleware that will pre/post-process the request.
return authorization_middleware
However, when the middleware executes, handler is not my view. It happens to be a bound method (pyramid.router.Router.handle_request) which does not provide me access to the view callable, meaning I cannot access the flag set by the middleware.
You probably want pyramid.config.set_default_permission(permission). From docs:
Adding a default permission makes it unnecessary to protect each view
configuration with an explicit permission, unless your application
policy requires some exception for a particular view.
If a default permission is in effect, view configurations meant to
create a truly anonymously accessible view (even exception view views)
must use the value of the permission importable as
pyramid.security.NO_PERMISSION_REQUIRED. When this string is used as
the permission for a view configuration, the default permission is
ignored, and the view is registered, making it available to all
callers regardless of their credentials.
Answer provided by raydeo_ on #pyramid freenode IRC channel.

Why isn't Windows Live Writer working with my MetaWebLog API provider?

I'm developing a Web site that, amongst other things, provides blogging via Metaweblog API. I've gotten the API working quite well with several blog clients, but Windows Live Writer is killing me.
I've done a network trace to capture the actual back-and-forth traffic. Here's the results:
WLW asks for my blog URL, user name, and password. The URL is /item/list/type/blog/user/1/bloguser/1, and I provide this.
I see WLW make an HTTP request for that URL. It gets a response. That response includes both RSD and wlwmanifest link tags.
The next request from WLW is for /mwapi/rsd/bloguser/1, which is the correct URL.
The response is the MetaWeblog RSD response:
<?xml version="1.0" encoding="UTF-8"?>
<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
<service>
<engineName>Cahoots2</engineName>
<engineLink>http://sourceforge.net/projects/cahoots/</engineLink>
<homePageLink>http://10.0.1.39:8888</homePageLink>
<apis>
<api name="MetaWeblog" blogID="1" preferred="true" apiLink="http://10.0.1.39:8888/mwapi/index" />
</apis>
</service>
</rsd>
The next request from WLW is to /mwapi/index. This is the method call to blogger.getUsersBlogs. The request is:
.<?xml version="1.0" encoding="utf-8"?>..
<methodCall>.. <methodName>blogger.getUsersBlogs</methodName>..
<params>.. <param>.. <value>..
<string>ffffffabffffffce6dffffff93ffffffac29ffffffc9fffffff826ffffffdeffffffc9ffffffe43c0b763036ffffffa0fffffff3ffffffa963377716</string>..
</value>..
</param>..
<param>..
<value>..
<string>CommunityAdmin</string>..
</value>..
</param>..
<param>..
<value>..
<string>password</string>..
</value>..
</param>.. </params>..</methodCall>
Forgive the periods; those are carriage returns. I'm grabbing this from a network trace.
The response from the server is also in XML:
.<?xml version="1.0" encoding="UTF-8"?>.<methodResponse><params><param><value>
<struct><member><name>blogid</name><value><int>1</int>
</value></member><member><name>url</name><value>
<string>http://10.0.1.39:8888/item/list/type/blog/user/1/bloguser/1</string>
</value></member><member><name>blogname</name><value>
<string>CommunityAdmin # Cahoots!</string></value></member></struct></value>
</param></params></methodResponse>.
This looks correct to me. The BlogID is correct, the URL is correct, and the blog name is correct.
WLW then repeats the original getUsersBlogs method call. It gets an identical response.
WLW then displays, "A successful connection was made to your account however the server reported that you do not currently have an active blog. Please ensure that your account with this provider is current before proceeding."
WLW has made no further HTTP requests beyond the ones I've described here.
Any clues whatsoever what I'm doing wrong? I've ensured that a wlwmanifest.xml file is available, and in fact any request for wlwmanifest.xml (e.g., /this/is/not/it/wlwmanifest.xml) will still return the correct file.
EDIT: I realized I wasn't returning an array from my getUsersBlogs method. When I changed that, the HTTP response from the method call was:
.<?xml version="1.0" encoding="UTF-8"?>.<methodResponse><params><param><value><array><data><value>
<struct><member><name>blogid</name><value><int>1</int></value></member>
<member><name>url</name><value>
<string>http://10.0.1.39:8888/item/list/type/blog/user/1/bloguser/1</string>
</value></member><member><name>blogname</name><value>
<string>CommunityAdmin # Cahoots!</string></value></member></struct></value>
</data></array></value></param></params></methodResponse>.
This looks identical to what's described at http://msdn.microsoft.com/en-us/library/aa905665.aspx as a sample response. But, WLW displayed an error - "Object reference not set to an instance of an object." Again, the actual response data doesn't include the periods - that's just how Network Monitor represents carriage returns.
I've done test calls from a test harness and it's working fine with identical responses. And, as I said, it's working with other blogging clients. Help.
WLW, it seems, is VERY picky about the MWA implementation. I was not capitalizing one of the method names correctly.

Resources