Online Blacklist / Reputation check using Tellows API

Hi,

I was wondering if anyone has ever done a reputation check of callers against the Tellows database. They have an API for checking, and there is a docker project for Asterisk which requires a “Makro”. Not sure if and how this would work for FreePBX as well.

Marco

Conversation to a superfecta source may be a good way to make it work on FreePBX.

Looking for API details, all I can find is this.
https://www.tellows.com/openapi/index.html

It looks like with an auth token, you can get a list of sus numbers, and there is a hint on that page that it may be possible to get a spam score for a specific number, tho I don’t see API details for that.

If there’s a simple URL with GET args that will return a json string containing a spam score, it would be trivial to add a superfecta module.

1 Like

Did you look to the GitHub project link? This is likely a conversation to something Asterisk understands as there are also Asterisk macros in the docs. Not sure if and how these will work with FreePBX.

From the github link and taking a known bad NANP number from their home page, it looks like this URL yields a useful result

https://www.tellows.de/basic/num/+16282159969?json=1

I’m getting valid results without an auth token, and unable to locate any docs for how to use /basic/num so I assume this is legit usage. But that needs to be confirmed somehow.

This is enough to get a proof of concept for superfecta. Create the file owned by asterisk:asterisk at:
/var/www/html/admin/modules/superfecta/sources/source-TellowsAPI.module

<?php

class TellowsAPI extends superfecta_base {

	public $description, $source_param;
	public $version_requirement = "2.11";

	public function __construct() {
		$this->description = "https://www.tellows.de/ - "._("A datasource devoted to identifying spam callers.");
		$this->source_param = array(
			'SPAM_Threshold' => array(
				'description' => _('Specify the score above which a call is considered spam.'),
				'type' => 'number',
				'default' => 5
			)
		);
	}

	function get_caller_id($thenumber, $run_param=array()) {
		// $thuenumber must be in E164 format: [+][country code][subscriber number including area code]
	
		$url = "https://www.tellows.de/basic/num/$thenumber?json=1";
		$json = $this->get_url_contents($url);
		$result = json_decode($json,true);
		$value = $result['tellows']['score'];

		if (is_numeric($value)) {
			$this->DebugPrint(_('Found')." ".$value);

			$score = $value;
			if ($score > $run_param['SPAM_Threshold']) {
				$this->spam = true;
				$this->DebugPrint(" "._("determined to be SPAM"));
			} else {
				$this->DebugPrint(_("Not a SPAM caller"));
			}
		} 
	}
}```
1 Like

@lgaetz WOW! Awesome! :heart_eyes:
This is simple and seems to work like a charm! Thanks a ton! :sunglasses:

Do you see the possibility to add the username/password as an option if you buy the access? I’m not sure how long this works without (I guess they might rate limit / block after some queries per IP)

1 Like

I’m assuming yes, there’s likely support for passing additional params as GET args, but requires docs (or an example) of the API usage for /basic/num

The code above needs more work to use in production. At a min it needs to check that content returned from API is valid, properly format the number to e164 etc.

Unauthenticated use may be rate limited or not but it does seem to use this commercially you are suppose to obtain a license.

Yap, that’s why I ask for the authentication support. Although I’m not commercial, but I’d like to buy an API key for programmers for 2 years (no commercial use).

Interface for accessing the tellows database for programmers - tellows API Key | shop.tellows.de

Oh, OK. Unfortunately I’m personally far from being able to add this.

I’ll contact the author of the GitHub project in parallel, not sure if it’s already maintained. Maybe he can add something to it which can be accessed by your Superfecta script.

Nothing in that project is directly usable for Superfecta.

It’s possible that a user account might reveal how to pass an api key, or a purchase. The page linked above shows how to use an API key for other purposes, so my guess the URL will look something like:

https://www.tellows.de/basic/num/[phone_number]?partner=[APIname]&apikey=[APIkey]&json=1

Right, but the project provides a webserver which the Asterisk Macro accesses … if there would be an URL which can be accessed by Superfecta we’re “home”.

Uhm … I found a showstopper :face_with_raised_eyebrow:

I’m using Allowlist to bypass well known callers on the inbound route. Unfortunately Allowlist has a higher priority than Superfecta, so once Allowlist is activated, Superfecta does nut run. :pleading_face:

Hi Lorne,

the author of the Github project responded:

You don’t need macros to use the tool. I only mentioned macros in the documentation because my example diaplan uses one.
The tool is simply a FastAGI server that you can call from anywhere in the dialplan - whether from a macro or not.
In principle, there are various options for integration in Superfecta - although I am not familiar with Superfecta:

  • Superfecta calls my system via AGI Call (if it can do AGI)
  • You call my system via AGI before Superfecta and pass the result in a variable to Superfecta (if it can read variables from asterisk)
  • Superfecta calls my system via another interface, e.g. REST. However, this interface does not yet exist
  • Superfecta calls Tellows directly - that would certainly make more sense than the last option, so I wouldn’t build an interface for Superfecta

Are these “AGI calls” something Superfecta can deal with (referring to the first two points in the list)?

Updated script:

Apart from the Tellows spam score it might be also relevant how many comments and/or how many searches a number has experienced. If only one person reports a number and no significant searches are done it might be not a direct spam number.

So based on Lorne’s great template I’ve enhanced the script to also consider these parameters. Also I’ve added the ability to configure and use the Tellows API key.

<?php

class TellowsAPI extends superfecta_base {

	public $description, $source_param;
	public $version_requirement = "2.11";

	public function __construct() {
		$this->description = "https://www.tellows.de/ - "._("A datasource devoted to identifying spam callers.");
		$this->source_param = array(
			'SPAM_Threshold' => array(
				'description' => _('Specify the score from which a call is considered spam.'),
				'type' => 'number',
				'default' => 6
			),
			'COMMENTS_Threshold' => array(
				'description' => _('Specify the number of comments which are needed for spam classification.'),
				'type' => 'number',
				'default' => 2
			),
			'SEARCHES_Threshold' => array(
				'description' => _('Specify the number of searches which are needed for spam classification.'),
				'type' => 'number',
				'default' => 5
			),
			'Tellows_Key' => array(
				'description' => _('Tellows API key (MD5 Hash).'),
				'type' => 'text',
				'default' => ''
			)
		);
	}

	function get_caller_id($thenumber, $run_param=array()) {
		// $thuenumber must be in E164 format: [+][country code][subscriber number including area code]
	
	    $apihash = $run_param['Tellows_Key'];
	    if ($apihash <> '') {
		   $url = "https://www.tellows.de/basic/num/$thenumber?json=1&partner=tellowskey&apikey=$apihash";
           $this->DebugPrint(_('Request with API key')." ".$apihash);
		} else {
		   $url = "https://www.tellows.de/basic/num/$thenumber?json=1";
           $this->DebugPrint(_('Request without API key'));
        }			
		$json = $this->get_url_contents($url);
		$result = json_decode($json,true);
		$value = $result['tellows']['score'];
		$comments = $result['tellows']['comments'];
		$searches = $result['tellows']['searches'];

		if (is_numeric($value)) {
			$this->DebugPrint(_('Found')." score ".$value." (".$run_param['SPAM_Threshold'].") with ".$comments." (".$run_param['COMMENTS_Threshold'].") comments and ".$searches." (".$run_param['SEARCHES_Threshold'].") searches");

			$score = $value;
			if ($score >= $run_param['SPAM_Threshold'] AND $comments >= $run_param['COMMENTS_Threshold'] AND $searches >= $run_param['SEARCHES_Threshold']) {
				$this->spam = true;
				$this->DebugPrint(" "._("determined to be SPAM"));
			} else {
				$this->DebugPrint(_("Not a SPAM caller"));
			}
		} 
	}
}

Meanwhile I’ve added error checking (in case the API returns an error because of an unsupported format) and for me the script is fine now and working very well.

I’ve created a GitHub project with the Tellows script here: GitHub - jacotec/FreePBX-Superfecta-Tellows: Superfecta script for spamchecking against tellows.de

@lgaetz I’ve had a Superfecta update in FreePBX and my script was wiped from the directory :pleading_face:. How can I avoid this? Will removing all write permissions help, or will this lead to errors during the module update?

In addition, do you have plans to add my final version to the “official” scripts? I think many guys in the German speaking area would be happy to use Tellows also for their FreePBX. Their call blocking app is very common and well-rated on IOS and Android as well.

The gold standard would be to

  1. Sign the Sangoma OSS CLA
  2. Fork the Superfecta repo on GitHub
  3. Make the changes on your local copy and make a PR back. The next published version will have your contribution.

[edit - corrected CLA link]

Hi @lgaetz

Sure, good idea. However, I’m failing here:

That link shows me:

I already have installed this Github app but I don’t see anything to sign :thinking:

I guess I need to wait with the PR until this is solved?

It requires you to go to a specific repository, the following link will work:

https://oss-cla.sangoma.com/freepbx/superfecta

Putting up a pull request will also cause a comment to be added if you haven’t signed, and there’s a link on it to sign.

1 Like