From b13719ee11e8ef5cb14e2310a12e9f790ecc7809 Mon Sep 17 00:00:00 2001
From: Loïc Collignon
Date: Thu, 11 Jan 2018 14:41:57 +0100
Subject: removed unused files and useless subdirectories
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Change-Id: Ie0ebe0104589ff99ae24c7410a484eeef18821e7
Signed-off-by: Loïc Collignon
---
CMakeLists.txt | 56 +-
agl-identity-agent.service.in | 11 -
agl-identity-service/CMakeLists.txt | 25 -
agl-identity-service/conf.d/cmake/config.cmake | 201 -----
agl-identity-service/conf.d/wgt/config.xml.in | 21 -
agl-identity-service/etc/config.json | 23 -
.../htdocs/identity/AFB-websock.js | 174 -----
.../htdocs/identity/binding-debug.css | 61 --
.../htdocs/identity/identity-binding.js | 158 ----
agl-identity-service/htdocs/identity/index.html | 41 --
agl-identity-service/src/CMakeLists.txt | 49 --
agl-identity-service/src/agl-forgerock.c | 209 ------
agl-identity-service/src/agl-forgerock.h | 24 -
agl-identity-service/src/agl-identity-binding.c | 333 ---------
agl-identity-service/src/aia-get.c | 245 -------
agl-identity-service/src/aia-get.h | 28 -
agl-identity-service/src/authorization.c | 43 --
agl-identity-service/src/authorization.h | 23 -
agl-identity-service/src/base64.c | 108 ---
agl-identity-service/src/base64.h | 51 --
agl-identity-service/src/curl-wrap.c | 210 ------
agl-identity-service/src/curl-wrap.h | 45 --
agl-identity-service/src/escape.c | 428 -----------
agl-identity-service/src/escape.h | 23 -
agl-identity-service/src/export.map | 1 -
agl-identity-service/src/memo.txt | 11 -
agl-identity-service/src/oidc-agent.c | 812 ---------------------
agl-identity-service/src/oidc-agent.h | 119 ---
agl-identity-service/src/test-aia-uds-bluez.c | 65 --
conf.d/cmake/config.cmake | 201 +++++
conf.d/wgt/config.xml.in | 21 +
etc/config.json | 23 +
htdocs/identity/AFB-websock.js | 174 +++++
htdocs/identity/binding-debug.css | 61 ++
htdocs/identity/identity-binding.js | 158 ++++
htdocs/identity/index.html | 41 ++
src/CMakeLists.txt | 49 ++
src/agl-forgerock.c | 209 ++++++
src/agl-forgerock.h | 24 +
src/agl-identity-binding.c | 333 +++++++++
src/aia-get.c | 245 +++++++
src/aia-get.h | 28 +
src/authorization.c | 43 ++
src/authorization.h | 23 +
src/base64.c | 108 +++
src/base64.h | 51 ++
src/curl-wrap.c | 210 ++++++
src/curl-wrap.h | 45 ++
src/escape.c | 428 +++++++++++
src/escape.h | 23 +
src/export.map | 1 +
src/memo.txt | 11 +
src/oidc-agent.c | 812 +++++++++++++++++++++
src/oidc-agent.h | 119 +++
src/test-aia-uds-bluez.c | 65 ++
uds-ble-id-init-service/CMakeLists.txt | 21 -
uds-ble-id-init-service/btle-advise.service | 8 -
uds-ble-id-init-service/btle-advise.timer | 6 -
uds-ble-id-init-service/conf.d/cmake/config.cmake | 201 -----
uds-ble-id-init-service/conf.d/wgt/config.xml.in | 19 -
uds-ble-id-init-service/src/CMakeLists.txt | 35 -
uds-ble-id-init-service/src/aia-uds-bluez.c | 607 ---------------
uds-ble-id-init-service/src/aia-uds-bluez.h | 46 --
.../src/uds-ble-id-init-service.c | 146 ----
64 files changed, 3513 insertions(+), 4680 deletions(-)
delete mode 100644 agl-identity-agent.service.in
delete mode 100644 agl-identity-service/CMakeLists.txt
delete mode 100644 agl-identity-service/conf.d/cmake/config.cmake
delete mode 100644 agl-identity-service/conf.d/wgt/config.xml.in
delete mode 100644 agl-identity-service/etc/config.json
delete mode 100644 agl-identity-service/htdocs/identity/AFB-websock.js
delete mode 100644 agl-identity-service/htdocs/identity/binding-debug.css
delete mode 100644 agl-identity-service/htdocs/identity/identity-binding.js
delete mode 100644 agl-identity-service/htdocs/identity/index.html
delete mode 100644 agl-identity-service/src/CMakeLists.txt
delete mode 100644 agl-identity-service/src/agl-forgerock.c
delete mode 100644 agl-identity-service/src/agl-forgerock.h
delete mode 100644 agl-identity-service/src/agl-identity-binding.c
delete mode 100644 agl-identity-service/src/aia-get.c
delete mode 100644 agl-identity-service/src/aia-get.h
delete mode 100644 agl-identity-service/src/authorization.c
delete mode 100644 agl-identity-service/src/authorization.h
delete mode 100644 agl-identity-service/src/base64.c
delete mode 100644 agl-identity-service/src/base64.h
delete mode 100644 agl-identity-service/src/curl-wrap.c
delete mode 100644 agl-identity-service/src/curl-wrap.h
delete mode 100644 agl-identity-service/src/escape.c
delete mode 100644 agl-identity-service/src/escape.h
delete mode 100644 agl-identity-service/src/export.map
delete mode 100644 agl-identity-service/src/memo.txt
delete mode 100644 agl-identity-service/src/oidc-agent.c
delete mode 100644 agl-identity-service/src/oidc-agent.h
delete mode 100644 agl-identity-service/src/test-aia-uds-bluez.c
create mode 100644 conf.d/cmake/config.cmake
create mode 100644 conf.d/wgt/config.xml.in
create mode 100644 etc/config.json
create mode 100644 htdocs/identity/AFB-websock.js
create mode 100644 htdocs/identity/binding-debug.css
create mode 100644 htdocs/identity/identity-binding.js
create mode 100644 htdocs/identity/index.html
create mode 100644 src/CMakeLists.txt
create mode 100644 src/agl-forgerock.c
create mode 100644 src/agl-forgerock.h
create mode 100644 src/agl-identity-binding.c
create mode 100644 src/aia-get.c
create mode 100644 src/aia-get.h
create mode 100644 src/authorization.c
create mode 100644 src/authorization.h
create mode 100644 src/base64.c
create mode 100644 src/base64.h
create mode 100644 src/curl-wrap.c
create mode 100644 src/curl-wrap.h
create mode 100644 src/escape.c
create mode 100644 src/escape.h
create mode 100644 src/export.map
create mode 100644 src/memo.txt
create mode 100644 src/oidc-agent.c
create mode 100644 src/oidc-agent.h
create mode 100644 src/test-aia-uds-bluez.c
delete mode 100644 uds-ble-id-init-service/CMakeLists.txt
delete mode 100644 uds-ble-id-init-service/btle-advise.service
delete mode 100644 uds-ble-id-init-service/btle-advise.timer
delete mode 100644 uds-ble-id-init-service/conf.d/cmake/config.cmake
delete mode 100644 uds-ble-id-init-service/conf.d/wgt/config.xml.in
delete mode 100644 uds-ble-id-init-service/src/CMakeLists.txt
delete mode 100644 uds-ble-id-init-service/src/aia-uds-bluez.c
delete mode 100644 uds-ble-id-init-service/src/aia-uds-bluez.h
delete mode 100644 uds-ble-id-init-service/src/uds-ble-id-init-service.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d9d7bd1..7ef4f7a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,8 +1,7 @@
###########################################################################
-# Copyright 2016 IoT.bzh
+# Copyright 2017 IoT.bzh
#
-# author: José Bollo
-# author: Stéphane Desneux
+# author: Jose Bollo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,51 +16,10 @@
# limitations under the License.
###########################################################################
-cmake_minimum_required(VERSION 3.3)
-
-project(agl-identity-agent VERSION 0.1)
-
-include(GNUInstallDirs)
-include(FindPkgConfig)
-
-###########################################################################
-
-set(CMAKE_BUILD_TYPE Debug CACHE STRING "set debug build by default")
-
-link_libraries(-Wl,--as-needed -Wl,--gc-sections)
-
-add_compile_options(-Wall -Wextra -Wconversion)
-add_compile_options(-Wno-unused-parameter) # frankly not using a parameter does it care?
-add_compile_options(-Wno-unused-but-set-variable)
-add_compile_options(-Werror=maybe-uninitialized)
-add_compile_options(-Werror=implicit-function-declaration)
-add_compile_options(-ffunction-sections -fdata-sections)
-add_compile_options(-Wl,--as-needed -Wl,--gc-sections)
-add_compile_options(-fPIC)
-
-set(CMAKE_C_FLAGS_PROFILING "-g -O0 -pg -Wp,-U_FORTIFY_SOURCE")
-set(CMAKE_C_FLAGS_DEBUG "-g -O0 -ggdb -Wp,-U_FORTIFY_SOURCE")
-set(CMAKE_C_FLAGS_RELEASE "-g -O2")
-set(CMAKE_C_FLAGS_CCOV "-g -O2 --coverage")
-
-###########################################################################
-
-set(PROJECT_DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR}/${PROJECT_NAME})
-
-###########################################################################
-
-add_subdirectory(binding)
-
-###########################################################################
-
-configure_file(agl-identity-agent.service.in agl-identity-agent.service @ONLY)
-
-INSTALL(FILES
- ${CMAKE_CURRENT_BINARY_DIR}/agl-identity-agent.service
- ${CMAKE_CURRENT_SOURCE_DIR}/btle-advise.service
- ${CMAKE_CURRENT_SOURCE_DIR}/btle-advise.timer
- DESTINATION
- ${PROJECT_DESTINATION}
- )
+cmake_minimum_required(VERSION 3.6)
+SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/)
+include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake)
+install(DIRECTORY etc DESTINATION ./)
+install(DIRECTORY htdocs/identity DESTINATION htdocs)
diff --git a/agl-identity-agent.service.in b/agl-identity-agent.service.in
deleted file mode 100644
index 5381946..0000000
--- a/agl-identity-agent.service.in
+++ /dev/null
@@ -1,11 +0,0 @@
-[Unit]
-Description=AGL identity agent
-Requires=btle-advise.service
-
-[Service]
-User=root
-ExecStartPre=/usr/sbin/rfkill unblock 0
-ExecStart=/usr/bin/afb-daemon --rootdir=@PROJECT_DESTINATION@ --ldpaths=@PROJECT_DESTINATION@ --port=1212 --token= --verbose --verbose --verbose
-
-[Install]
-WantedBy=default.target
diff --git a/agl-identity-service/CMakeLists.txt b/agl-identity-service/CMakeLists.txt
deleted file mode 100644
index 7ef4f7a..0000000
--- a/agl-identity-service/CMakeLists.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-###########################################################################
-# Copyright 2017 IoT.bzh
-#
-# author: Jose Bollo
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-###########################################################################
-
-cmake_minimum_required(VERSION 3.6)
-SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/)
-include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake)
-
-
-install(DIRECTORY etc DESTINATION ./)
-install(DIRECTORY htdocs/identity DESTINATION htdocs)
diff --git a/agl-identity-service/conf.d/cmake/config.cmake b/agl-identity-service/conf.d/cmake/config.cmake
deleted file mode 100644
index c5fdae6..0000000
--- a/agl-identity-service/conf.d/cmake/config.cmake
+++ /dev/null
@@ -1,201 +0,0 @@
-###########################################################################
-# Copyright 2015, 2016, 2017 IoT.bzh
-#
-# author: Fulup Ar Foll
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-###########################################################################
-
-# Project Info
-# ------------------
-set(PROJECT_NAME agl-identity-service)
-set(PROJECT_VERSION "0.1")
-set(PROJECT_PRETTY_NAME "AGL identity service")
-set(PROJECT_DESCRIPTION "AGL identity service")
-set(PROJECT_URL "https://github.com/iotbzh/aia-binding")
-set(PROJECT_ICON "icon.png")
-set(PROJECT_AUTHOR "José Bollo")
-set(PROJECT_AUTHOR_MAIL "jose.bollo@iot.bzh")
-set(PROJECT_LICENSE "APL2.0")
-set(PROJECT_LANGUAGES,"C")
-
-# Where are stored default templates files from submodule or subtree app-templates in your project tree
-# relative to the root project directory
-set(PROJECT_APP_TEMPLATES_DIR "../conf.d/app-templates")
-
-# Where are stored your external libraries for your project. This is 3rd party library that you don't maintain
-# but used and must be built and linked.
-# set(PROJECT_LIBDIR "libs")
-
-# Where are stored data for your application. Pictures, static resources must be placed in that folder.
-# set(PROJECT_RESOURCES "data")
-
-# Which directories inspect to find CMakeLists.txt target files
-# set(PROJECT_SRC_DIR_PATTERN "*")
-
-# Compilation Mode (DEBUG, RELEASE)
-# ----------------------------------
-set(USE_EFENCE 0)
-
-# Kernel selection if needed. You can choose between a
-# mandatory version to impose a minimal version.
-# Or check Kernel minimal version and just print a Warning
-# about missing features and define a preprocessor variable
-# to be used as preprocessor condition in code to disable
-# incompatibles features. Preprocessor define is named
-# KERNEL_MINIMAL_VERSION_OK.
-#
-# NOTE*** FOR NOW IT CHECKS KERNEL Yocto environment and
-# Yocto SDK Kernel version.
-# -----------------------------------------------
-#set (kernel_mandatory_version 4.8)
-#set (kernel_minimal_version 4.8)
-
-# Compiler selection if needed. Impose a minimal version.
-# -----------------------------------------------
-set (gcc_minimal_version 4.9)
-
-# PKG_CONFIG required packages
-# -----------------------------
-set (PKG_REQUIRED_LIST
- json-c
- afb-daemon
-)
-
-# Prefix path where will be installed the files
-# Default: /usr/local (need root permission to write in)
-# ------------------------------------------------------
-#set(CMAKE_INSTALL_PREFIX $ENV{HOME}/opt)
-
-# Customize link option
-# -----------------------------
-#list(APPEND link_libraries -an-option)
-
-# Compilation options definition
-# Use CMake generator expressions to specify only for a specific language
-# Values are prefilled with default options that is currently used.
-# Either separate options with ";", or each options must be quoted separately
-# DO NOT PUT ALL OPTION QUOTED AT ONCE , COMPILATION COULD FAILED !
-# ----------------------------------------------------------------------------
-#set(COMPILE_OPTIONS
-# -Wall
-# -Wextra
-# -Wconversion
-# -Wno-unused-parameter
-# -Wno-sign-compare
-# -Wno-sign-conversion
-# -Werror=maybe-uninitialized
-# -Werror=implicit-function-declaration
-# -ffunction-sections
-# -fdata-sections
-# -fPIC
-# CACHE STRING "Compilation flags")
-#set(C_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C language.")
-#set(CXX_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C++ language.")
-#set(PROFILING_COMPILE_OPTIONS
-# -g
-# -O0
-# -pg
-# -Wp,-U_FORTIFY_SOURCE
-# CACHE STRING "Compilation flags for PROFILING build type.")
-#set(DEBUG_COMPILE_OPTIONS
-# -g
-# -ggdb
-# -Wp,-U_FORTIFY_SOURCE
-# CACHE STRING "Compilation flags for DEBUG build type.")
-#set(CCOV_COMPILE_OPTIONS
-# -g
-# -O2
-# --coverage
-# CACHE STRING "Compilation flags for CCOV build type.")
-#set(RELEASE_COMPILE_OPTIONS
-# -g
-# -O2
-# CACHE STRING "Compilation flags for RELEASE build type.")
-
-# (BUG!!!) as PKG_CONFIG_PATH does not work [should be an env variable]
-# ---------------------------------------------------------------------
-set(CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}/lib64/pkgconfig ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
-set(LD_LIBRARY_PATH ${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib)
-
-# Optional location for config.xml.in
-# -----------------------------------
-#set(WIDGET_ICON conf.d/wgt/${PROJECT_ICON} CACHE PATH "Path to the widget icon")
-set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in CACHE PATH "Path to widget config file template (config.xml.in)")
-
-# Mandatory widget Mimetype specification of the main unit
-# --------------------------------------------------------------------------
-# Choose between :
-#- text/html : HTML application,
-# content.src designates the home page of the application
-#
-#- application/vnd.agl.native : AGL compatible native,
-# content.src designates the relative path of the binary.
-#
-# - application/vnd.agl.service: AGL service, content.src is not used.
-#
-#- ***application/x-executable***: Native application,
-# content.src designates the relative path of the binary.
-# For such application, only security setup is made.
-#
-set(WIDGET_TYPE application/vnd.agl.service)
-
-# Mandatory Widget entry point file of the main unit
-# --------------------------------------------------------------
-# This is the file that will be executed, loaded,
-# at launch time by the application framework.
-#
-set(WIDGET_ENTRY_POINT config.xml)
-
-# Optional dependencies order
-# ---------------------------
-#set(EXTRA_DEPENDENCIES_ORDER)
-
-# Optional Extra global include path
-# -----------------------------------
-#set(EXTRA_INCLUDE_DIRS)
-
-# Optional extra libraries
-# -------------------------
-#set(EXTRA_LINK_LIBRARIES)
-
-# Optional force binding Linking flag
-# ------------------------------------
-# set(BINDINGS_LINK_FLAG LinkOptions )
-
-# Optional force package prefix generation, like widget
-# -----------------------------------------------------
-# set(PKG_PREFIX DestinationPath)
-
-# Optional Application Framework security token
-# and port use for remote debugging.
-#------------------------------------------------------------
-set(AFB_TOKEN "" CACHE PATH "Default binder security token")
-set(AFB_REMPORT "1234" CACHE PATH "Default binder listening port")
-
-# Print a helper message when every thing is finished
-# ----------------------------------------------------
-set(CLOSING_MESSAGE "Typical binding launch: afb-daemon --port=${AFB_REMPORT} --workdir=${CMAKE_BINARY_DIR}/package --ldpaths=lib --roothttp=htdocs --token=\"${AFB_TOKEN}\" --tracereq=common --verbose")
-set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt")
-
-# Optional schema validator about now only XML, LUA and JSON
-# are supported
-#------------------------------------------------------------
-#set(LUA_CHECKER "luac" "-p" CACHE STRING "LUA compiler")
-#set(XML_CHECKER "xmllint" CACHE STRING "XML linter")
-#set(JSON_CHECKER "json_verify" CACHE STRING "JSON linter")
-
-# This include is mandatory and MUST happens at the end
-# of this file, else you expose you to unexpected behavior
-# -----------------------------------------------------------
-include(${PROJECT_APP_TEMPLATES_DIR}/cmake/common.cmake)
diff --git a/agl-identity-service/conf.d/wgt/config.xml.in b/agl-identity-service/conf.d/wgt/config.xml.in
deleted file mode 100644
index cd66c2b..0000000
--- a/agl-identity-service/conf.d/wgt/config.xml.in
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
- @PROJECT_NAME@
-
-
- @PROJECT_DESCRIPTION@
- @PROJECT_AUTHOR@ <@PROJECT_AUTHOR_MAIL@>
- @PROJECT_LICENSE@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/agl-identity-service/etc/config.json b/agl-identity-service/etc/config.json
deleted file mode 100644
index c69e5be..0000000
--- a/agl-identity-service/etc/config.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "endpoint": "https://agl-graphapi.forgerocklabs.org:443/getuserprofilefromtoken",
- "vin": "WVGGF7BP7HD005986",
- "autoadvise": true,
- "delay": 5,
- "idp": {
- "authorization_endpoint": "",
- "token_endpoint": "https://agl-am.forgerocklabs.org:8043/openam/oauth2/stateless/access_token"
- }/*,
- "appli": {
- "authorization": "Basic c3RhdGVsZXNzOnBhc3N3b3JkMg==",
- "username": "bjensen",
- "password": "Passw0rd",
- "scope": "openid profile email cn sn givenName ou mail postalAddress departmentNumber physicalDeliveryOfficeName facsimileTelephoneNumber"
- }
-*/
-}
-/*
- "endpoint": "https://frdemo-graphapi.forgerocklabs.org/getuserprofilefromtoken",
- "vin": "JTEBU4BF6EK189816",
- "delay": 10
-*/
-
diff --git a/agl-identity-service/htdocs/identity/AFB-websock.js b/agl-identity-service/htdocs/identity/AFB-websock.js
deleted file mode 100644
index 08a7ffe..0000000
--- a/agl-identity-service/htdocs/identity/AFB-websock.js
+++ /dev/null
@@ -1,174 +0,0 @@
-AFB = function(base, initialtoken){
-
-var urlws = "ws://"+window.location.host+"/"+base;
-var urlhttp = "http://"+window.location.host+"/"+base;
-
-/*********************************************/
-/**** ****/
-/**** AFB_context ****/
-/**** ****/
-/*********************************************/
-var AFB_context;
-{
- var UUID = undefined;
- var TOKEN = initialtoken;
-
- var context = function(token, uuid) {
- this.token = token;
- this.uuid = uuid;
- }
-
- context.prototype = {
- get token() {return TOKEN;},
- set token(tok) {if(tok) TOKEN=tok;},
- get uuid() {return UUID;},
- set uuid(id) {if(id) UUID=id;}
- };
-
- AFB_context = new context();
-}
-/*********************************************/
-/**** ****/
-/**** AFB_websocket ****/
-/**** ****/
-/*********************************************/
-var AFB_websocket;
-{
- var CALL = 2;
- var RETOK = 3;
- var RETERR = 4;
- var EVENT = 5;
-
- var PROTO1 = "x-afb-ws-json1";
-
- AFB_websocket = function(onopen, onabort) {
- var u = urlws;
- if (AFB_context.token) {
- u = u + '?x-afb-token=' + AFB_context.token;
- if (AFB_context.uuid)
- u = u + '&x-afb-uuid=' + AFB_context.uuid;
- }
- this.ws = new WebSocket(u, [ PROTO1 ]);
- this.pendings = {};
- this.awaitens = {};
- this.counter = 0;
- this.ws.onopen = onopen.bind(this);
- this.ws.onerror = onerror.bind(this);
- this.ws.onclose = onclose.bind(this);
- this.ws.onmessage = onmessage.bind(this);
- this.onopen = onopen;
- this.onabort = onabort;
- this.onclose = onabort;
- }
-
- function onerror(event) {
- var f = this.onabort;
- if (f) {
- delete this.onopen;
- delete this.onabort;
- f && f(this);
- }
- this.onerror && this.onerror(this);
- }
-
- function onopen(event) {
- var f = this.onopen;
- delete this.onopen;
- delete this.onabort;
- f && f(this);
- }
-
- function onclose(event) {
- for (var id in this.pendings) {
- var ferr = this.pendings[id].onerror;
- ferr && ferr(null, this);
- }
- this.pendings = {};
- this.onclose && this.onclose();
- }
-
- function fire(awaitens, name, data) {
- var a = awaitens[name];
- if (a)
- a.forEach(function(handler){handler(data);});
- var i = name.indexOf("/");
- if (i >= 0) {
- a = awaitens[name.substring(0,i)];
- if (a)
- a.forEach(function(handler){handler(data);});
- }
- a = awaitens["*"];
- if (a)
- a.forEach(function(handler){handler(data);});
- }
-
- function reply(pendings, id, ans, offset) {
- if (id in pendings) {
- var p = pendings[id];
- delete pendings[id];
- var f = p[offset];
- f(ans);
- }
- }
-
- function onmessage(event) {
- var obj = JSON.parse(event.data);
- var code = obj[0];
- var id = obj[1];
- var ans = obj[2];
- AFB_context.token = obj[3];
- switch (code) {
- case RETOK:
- reply(this.pendings, id, ans, 0);
- break;
- case RETERR:
- reply(this.pendings, id, ans, 1);
- break;
- case EVENT:
- default:
- fire(this.awaitens, id, ans);
- break;
- }
- }
-
- function close() {
- this.ws.close();
- this.onabort();
- }
-
- function call(method, request) {
- return new Promise((function(resolve, reject){
- var id, arr;
- do {
- id = String(this.counter = 4095 & (this.counter + 1));
- } while (id in this.pendings);
- this.pendings[id] = [ resolve, reject ];
- arr = [CALL, id, method, request ];
- if (AFB_context.token) arr.push(AFB_context.token);
- this.ws.send(JSON.stringify(arr));
- }).bind(this));
- }
-
- function onevent(name, handler) {
- var id = name;
- var list = this.awaitens[id] || (this.awaitens[id] = []);
- list.push(handler);
- }
-
- AFB_websocket.prototype = {
- close: close,
- call: call,
- onevent: onevent
- };
-}
-/*********************************************/
-/**** ****/
-/**** ****/
-/**** ****/
-/*********************************************/
-return {
- context: AFB_context,
- ws: AFB_websocket
-};
-};
-
diff --git a/agl-identity-service/htdocs/identity/binding-debug.css b/agl-identity-service/htdocs/identity/binding-debug.css
deleted file mode 100644
index f41c940..0000000
--- a/agl-identity-service/htdocs/identity/binding-debug.css
+++ /dev/null
@@ -1,61 +0,0 @@
-#debug-panel {
- float: right;
-}
-
-#debug-panel.collapsed {
- background-color: transparent;
- overflow-x: hidden;
-}
-
-#debug-panel.expanded {
- background-color: lightyellow;
- max-width: 25%;
- overflow-x: scroll;
-}
-
-#debug-panel.collapsed > #debug-panel-collapse {
- display: none;
-}
-
-#debug-panel.expanded > #debug-panel-collapse {
- display: block;
-}
-
-#debug-panel.collapsed > #debug-panel-expand {
- display: block;
-}
-
-#debug-panel.expanded > #debug-panel-expand {
- display: none;
-}
-
-#debug-panel.expanded > #debug-panel-content {
- display: block;
-}
-
-#debug-panel.collapsed > #debug-panel-content {
- display: none;
-}
-
-.json-key {
- color: cornflowerblue;
- font-weight: bold;
-}
-
-.json-string {
- color: crimson;
-}
-
-.json-number {
- color: sandybrown;
-}
-
-.json-boolean {
- color: fuchsia;
- font-weight: bold;
-}
-
-.json-null {
- color: black;
- font-weight: bold;
-}
diff --git a/agl-identity-service/htdocs/identity/identity-binding.js b/agl-identity-service/htdocs/identity/identity-binding.js
deleted file mode 100644
index 55dbb96..0000000
--- a/agl-identity-service/htdocs/identity/identity-binding.js
+++ /dev/null
@@ -1,158 +0,0 @@
-var afb = new AFB("api", "HELLO");
-var ws;
-
-function add_debbug_panel() {
-
- if (document.getElementById("debug-panel"))
- return;
-
- var itm = document.getElementById("debug-panel-container");
- if (itm)
- {
- var pnl =
- "\n" +
- "
\n" +
- "
\n" +
- "
\n" +
- "
Debug
\n" +
- "
Call
\n" +
- "
\n" +
- " - api :
\n" +
- " - verb :
\n" +
- " - query :
\n" +
- "
\n" +
- "
\n" +
- "
\n" +
- "
Response
\n" +
- "
Event
\n" +
- "
\n" +
- "
\n";
- itm.insertAdjacentHTML("afterbegin", pnl);
- }
-}
-
-function createClass(name,rules) {
- var style = document.createElement('style');
- style.type = 'text/css';
- document.getElementsByTagName('head')[0].appendChild(style);
- if(!(style.sheet||{}).insertRule)
- (style.styleSheet || style.sheet).addRule(name, rules);
- else
- style.sheet.insertRule(name+"{"+rules+"}",0);
-}
-
-function syntaxHighlight(json) {
- if (typeof json != 'string')
- json = JSON.stringify(json, undefined, 2);
-
- json = json.replace(/&/g, '&').replace(//g, '>');
- return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
- var cls = 'json-number';
- if (/^"/.test(match)) {
- if (/:$/.test(match)) {
- cls = 'json-key';
- } else {
- cls = 'json-string';
- }
- } else if (/true|false/.test(match)) {
- cls = 'json-boolean';
- } else if (/null/.test(match)) {
- cls = 'json-null';
- }
- return '' + match + '';
- });
-}
-
-function set_item_html(id, text)
-{
- var itm = document.getElementById(id);
- if (itm) itm.innerHTML = text;
-}
-
-function set_item_text(id, text)
-{
- var itm = document.getElementById(id);
- if (itm) itm.innerText = text;
-}
-
-function debug_panel_collapse() {
- var pnl = document.getElementById('debug-panel');
- if (pnl)
- {
- pnl.classList.remove('expanded');
- pnl.classList.add('collapsed');
- }
-}
-
-function debug_panel_expand() {
- var pnl = document.getElementById('debug-panel');
- if (pnl)
- {
- pnl.classList.remove('collapsed');
- pnl.classList.add('expanded');
- }
-}
-
-function init() {
- add_debbug_panel();
- ws = new afb.ws(onopen, onabort);
-}
-
-function onopen() {
- //callbinder("ll-auth", "getuser", "");
- ws.onevent("*", gotevent);
-}
-
-function onabort() {
-}
-
-function replyok(obj) {
- console.log("replyok:" + JSON.stringify(obj));
- set_item_html("debug-panel-response", syntaxHighlight(JSON.stringify(obj, null, 4)));
-}
-
-function replyerr(obj) {
- console.log("replyerr:" + JSON.stringify(obj));
- set_item_html("debug-panel-response", syntaxHighlight(JSON.stringify(obj, null, 4)));
-}
-
-function gotevent(obj) {
- console.log("gotevent:" + JSON.stringify(obj));
- set_item_html("debug-panel-event", syntaxHighlight(JSON.stringify(obj, null, 4)));
-}
-
-function callbinder(api, verb, query) {
- console.log ("subscribe api="+api+" verb="+verb+" query=" +query);
-
- set_item_text("debug-panel-call-api", api);
- set_item_text("debug-panel-call-verb", verb);
- set_item_html("debug-panel-call-query", syntaxHighlight(JSON.stringify(query, null, 4)));
-
- ws.call(api+"/"+verb, query).then(replyok, replyerr);
-}
-
-function subscribe() {
- callbinder("identity", "subscribe", {});
-}
-
-function getIdentity() {
- callbinder("identity", "get", {});
-}
-
-function logout() {
- callbinder("identity", "logout", {});
-}
-
-function fakeAuth() {
-
- var e = document.getElementById("fake-auth-kind");
- var arg = {
- "kind": e.options[e.selectedIndex].value,
- "key": (document.getElementById("fake-auth-key").value === "custom" ? document.getElementById("fake-auth-key-custom").value : document.getElementById("fake-auth-key").value)
- }
- callbinder("identity", "fake-auth", arg);
-}
-
-function updateNfcUi() {
- document.getElementById('fake-auth-key-custom').disabled = !(document.getElementById("fake-auth-key").value === "custom");
-}
diff --git a/agl-identity-service/htdocs/identity/index.html b/agl-identity-service/htdocs/identity/index.html
deleted file mode 100644
index bbeee51..0000000
--- a/agl-identity-service/htdocs/identity/index.html
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
- agl-service-identity
-
-
-
-
-
-
-
-
- agl-service-identity
-
-
-
-
-
diff --git a/agl-identity-service/src/CMakeLists.txt b/agl-identity-service/src/CMakeLists.txt
deleted file mode 100644
index e4a744b..0000000
--- a/agl-identity-service/src/CMakeLists.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-###########################################################################
-# Copyright 2016, 2017 IoT.bzh
-#
-# author: José Bollo
-# author: Stéphane Desneux
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-###########################################################################
-
-PROJECT_TARGET_ADD(afb-identity-binding)
-
-add_library(afb-identity-binding MODULE
- agl-identity-binding.c
- agl-forgerock.c
- aia-get.c
- authorization.c
- base64.c
- curl-wrap.c
- escape.c
- oidc-agent.c
-)
-
-pkg_check_modules(EXTRAS REQUIRED libcurl)
-
-set_target_properties(afb-identity-binding PROPERTIES
- LABELS "BINDING"
- PREFIX ""
- COMPILE_FLAGS "${EXTRAS_CFLAGS} -DFOR_AFB_BINDING"
- LINK_FLAGS "${BINDINGS_LINK_FLAG}"
- LINK_LIBRARIES "${EXTRAS_LIBRARIES}"
- OUTPUT_NAME "${TARGET_NAME}"
-)
-
-add_custom_command(TARGET ${TARGET_NAME}
-PRE_BUILD
-COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/../package/htdocs
-COMMAND cp -rv ${CMAKE_CURRENT_SOURCE_DIR}/../htdocs ${CMAKE_CURRENT_BINARY_DIR}/../package/
-COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/../package/etc
-COMMAND cp -rv ${CMAKE_CURRENT_SOURCE_DIR}/../etc ${CMAKE_CURRENT_BINARY_DIR}/../package/)
diff --git a/agl-identity-service/src/agl-forgerock.c b/agl-identity-service/src/agl-forgerock.c
deleted file mode 100644
index 97cc4b9..0000000
--- a/agl-identity-service/src/agl-forgerock.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-
-#include
-#include
-
-#include
-
-#define AFB_BINDING_VERSION 2
-#include
-
-#include "oidc-agent.h"
-#include "aia-get.h"
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-static int expiration_delay = 5;
-
-static const char default_endpoint[] = "https://agl-graphapi.forgerocklabs.org/getuserprofilefromtoken";
-static const char *oidc_name;
-
-static char *endpoint;
-
-static void (*onloaded)(struct json_object *data, const char *error);
-
-/***** configuration ********************************************/
-
-static void confsetstr(struct json_object *conf, const char *name, char **value, const char *def)
-{
- struct json_object *v;
- const char *s;
- char *p;
-
- s = conf && json_object_object_get_ex(conf, name, &v) ? json_object_get_string(v) : def;
- p = *value;
- if (s && p != s) {
- *value = strdup(s);
- free(p);
- }
-}
-
-static void confsetint(struct json_object *conf, const char *name, int *value, int def)
-{
- struct json_object *v;
-
- *value = conf && json_object_object_get_ex(conf, name, &v) ? json_object_get_int(v) : def;
-}
-
-static void confsetoidc(struct json_object *conf, const char *name)
-{
- struct json_object *idp, *appli;
-
- if (conf
- && json_object_object_get_ex(conf, "idp", &idp)
- && json_object_object_get_ex(conf, "appli", &appli)) {
- if (oidc_idp_set(name, idp) && oidc_appli_set(name, name, appli, 1)) {
- oidc_name = name;
- }
- }
-}
-
-/****************************************************************/
-
-static void loaded(struct json_object *data, const char *error)
-{
- if (onloaded)
- onloaded(data, error);
-}
-
-static void downloaded(void *closure, int status, const void *buffer, size_t size)
-{
- struct json_object *object, *subobj;
- struct json_object *objkey = closure;
- struct json_object *tmp;
-
- json_object_object_get_ex(objkey, "url", &tmp);
- const char *url = json_object_get_string(tmp);
-
- /* checks whether discarded */
- if (status == 0 && !buffer) {
- AFB_ERROR("discarded");
- loaded(NULL, "discarded");
- goto end; /* discarded */
- }
-
- /* scan for the status */
- if (status == 0 || !buffer) {
- AFB_ERROR("uploading %s failed %s", url ? : "?", (const char*)buffer ? : "");
- loaded(NULL, "failed");
- goto end;
- }
-
- /* get the object */
- AFB_DEBUG("received data: %.*s", (int)size, (char*)buffer);
- object = json_tokener_parse(buffer); /* okay because 0 appended */
-
- /* extract useful part */
- subobj = NULL;
- if (object && !json_object_object_get_ex(object, "results", &subobj))
- subobj = NULL;
- if (subobj)
- subobj = json_object_array_get_idx(subobj, 0);
- if (subobj && !json_object_object_get_ex(subobj, "data", &subobj))
- subobj = NULL;
- if (subobj)
- subobj = json_object_array_get_idx(subobj, 0);
- if (subobj && !json_object_object_get_ex(subobj, "row", &subobj))
- subobj = NULL;
- if (subobj)
- subobj = json_object_array_get_idx(subobj, 0);
-
- /* is it a recognized user ? */
- if (!subobj) {
- /* not recognized!! */
- AFB_INFO("unrecognized key for %s", url ? : "?");
- json_object_put(object);
- loaded(NULL, "malformed");
- goto end;
- }
-
- // Save the profile to the database
- struct json_object* dbr;
- struct json_object* record = json_object_new_object();
- json_object_object_add(record, "key", objkey);
- json_object_object_add(record, "value", json_object_get(subobj));
- afb_service_call_sync("persistence", "update", record, &dbr);
-
- loaded(subobj, NULL);
- json_object_put(object);
-end:
- json_object_put(objkey);
-}
-
-/** public **************************************************************/
-
-void agl_forgerock_setconfig(struct json_object *conf)
-{
- confsetstr(conf, "endpoint", &endpoint, endpoint ? : default_endpoint);
- confsetint(conf, "delay", &expiration_delay, expiration_delay);
- confsetoidc(conf, "oidc-aia");
- AFB_NOTICE("Forgerock endpoint is: %s", endpoint);
-}
-
-void agl_forgerock_setcb(void (*callback)(struct json_object *data, const char *error))
-{
- onloaded = callback;
-}
-
-void reply_from_db(void* closure, int status, struct json_object* result)
-{
- if (status)
- {
- AFB_WARNING("Failed to retrieve profile from persistence!");
- return;
- }
-
- struct json_object* tmp;
- json_object_object_get_ex(result, "response", &tmp);
- json_object_object_get_ex(tmp, "value", &tmp);
- AFB_NOTICE("User profile retrieved from persistence: %s", json_object_to_json_string(tmp));
- loaded(json_object_get(tmp), NULL);
-}
-
-void agl_forgerock_download_request(const char *vin, const char *kind, const char *key)
-{
- int rc;
- char *url;
-
- rc = asprintf(&url, "%s?vin=%s&kind=%s&keytoken=%s", endpoint, vin, kind, key);
- if (rc >= 0)
- {
- struct json_object* obj = json_object_new_object();
- json_object_object_add(obj, "url", json_object_new_string(url));
- json_object_object_add(obj, "vin", json_object_new_string(vin));
- json_object_object_add(obj, "kind", json_object_new_string(kind));
- json_object_object_add(obj, "key", json_object_new_string(key));
-
- // Async get from database and from forgerock
- struct json_object* key = json_object_new_object();
- json_object_object_add(key, "key", json_object_get(obj));
- afb_service_call("persistence", "read", key, reply_from_db, NULL);
-
- // Async get from forgerock
- aia_get(url, expiration_delay, oidc_name, oidc_name, downloaded, obj);
- free(url);
- }
- else
- AFB_ERROR("out of memory");
-}
-
-/* vim: set colorcolumn=80: */
-
diff --git a/agl-identity-service/src/agl-forgerock.h b/agl-identity-service/src/agl-forgerock.h
deleted file mode 100644
index 1aee680..0000000
--- a/agl-identity-service/src/agl-forgerock.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-struct json_object;
-
-extern void agl_forgerock_setconfig(struct json_object *conf);
-extern void agl_forgerock_setcb(void (*callback)(struct json_object *data, const char *error));
-extern void agl_forgerock_download_request(const char *vin, const char *kind, const char *key);
diff --git a/agl-identity-service/src/agl-identity-binding.c b/agl-identity-service/src/agl-identity-binding.c
deleted file mode 100644
index 12f43bd..0000000
--- a/agl-identity-service/src/agl-identity-binding.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#define AFB_BINDING_VERSION 2
-#include
-
-#include "agl-forgerock.h"
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-static struct afb_event event;
-
-static struct json_object *current_identity;
-
-static const char default_vin[] = "4T1BF1FK5GU260429";
-static char *vin;
-
-/***** configuration ********************************************/
-
-static struct json_object *readjson(int fd)
-{
- char *buffer;
- struct stat s;
- struct json_object *result = NULL;
- int rc;
-
- rc = fstat(fd, &s);
- if (rc == 0 && S_ISREG(s.st_mode)) {
- buffer = alloca((size_t)(s.st_size)+1);
- if (read(fd, buffer, (size_t)s.st_size) == (ssize_t)s.st_size) {
- buffer[s.st_size] = 0;
- //AFB_NOTICE("Config file: %s", buffer);
- result = json_tokener_parse(buffer);
- //if (!result)
- //{
- // AFB_ERROR("Config file is not a valid JSON: %s", json_tokener_error_desc(json_tokener_get_error(NULL)));
- //}
- }
- }
- close(fd);
-
- return result;
-}
-
-static struct json_object *get_global_config(const char *name, const char *locale)
-{
- int fd = afb_daemon_rootdir_open_locale(name, O_RDONLY, locale);
- if (fd < 0) AFB_ERROR("Config file not found: %s", name);
- return fd < 0 ? NULL : readjson(fd);
-}
-
-static struct json_object *get_local_config(const char *name)
-{
- int fd = openat(AT_FDCWD, name, O_RDONLY, 0);
- return fd < 0 ? NULL : readjson(fd);
-}
-
-static void confsetstr(struct json_object *conf, const char *name, char **value, const char *def)
-{
- struct json_object *v;
- const char *s;
- char *p;
-
- s = conf && json_object_object_get_ex(conf, name, &v) ? json_object_get_string(v) : def;
- p = *value;
- if (s && p != s) {
- *value = strdup(s);
- free(p);
- }
-}
-
-static void setconfig(struct json_object *conf)
-{
- if (conf) {
- confsetstr(conf, "vin", &vin, vin ? : default_vin);
- agl_forgerock_setconfig(conf);
- }
-}
-
-static void readconfig()
-{
- setconfig(get_global_config("etc/config.json", NULL));
- setconfig(get_local_config("/etc/agl/identity-agent-config.json"));
- setconfig(get_local_config("config.json"));
-}
-
-/****************************************************************/
-
-static struct json_object *make_event_object(const char *name, const char *id, const char *nick)
-{
- struct json_object *object = json_object_new_object();
-
- /* TODO: errors */
- json_object_object_add(object, "eventName", json_object_new_string(name));
- json_object_object_add(object, "accountid", json_object_new_string(id));
- if (nick)
- json_object_object_add(object, "nickname", json_object_new_string(nick));
- return object;
-}
-
-static int send_event_object(const char *name, const char *id, const char *nick)
-{
- return afb_event_push(event, make_event_object(name, id, nick));
-}
-
-static void do_login(struct json_object *desc)
-{
- if (current_identity == NULL && desc == NULL) return; // Switching from NULL to NULL -> do nothing
- if (current_identity && desc)
- {
- const char* a = json_object_to_json_string(current_identity);
- const char* b = json_object_to_json_string(desc);
- if (strcmp(a, b) == 0)
- {
- AFB_NOTICE("Reloging of the same user.");
- return; // Switching from one user to the same user -> do nothing
- }
- }
-
- struct json_object *object;
-
- /* switching the user */
- AFB_INFO("Switching to user %s", desc ? json_object_to_json_string(desc) : "null");
- object = current_identity;
- current_identity = json_object_get(desc);
- json_object_put(object);
-
- if (!json_object_object_get_ex(desc, "name", &object))
- object = 0;
- send_event_object("login", !object ? "null" : json_object_get_string(object)? : "?", 0);
-}
-
-static void do_logout()
-{
- struct json_object *object;
-
- AFB_INFO("Switching to no user");
- object = current_identity;
- current_identity = 0;
- json_object_put(object);
-
- send_event_object("logout", "null", 0);
-}
-
-static void on_forgerock_data(struct json_object *data, const char *error)
-{
- if (error) {
- AFB_ERROR("Can't get data: %s", error);
- } else {
- do_login(data);
- }
-}
-
-/****************************************************************/
-
-static void subscribe (struct afb_req request)
-{
- int rc;
-
- rc = afb_req_subscribe(request, event);
- if (rc < 0)
- afb_req_fail(request, "failed", "subscribtion failed");
- else
- afb_req_success(request, NULL, NULL);
-}
-
-static void unsubscribe (struct afb_req request)
-{
- afb_req_unsubscribe(request, event);
- afb_req_success(request, NULL, NULL);
-}
-
-static void logout (struct afb_req request)
-{
- do_logout();
- afb_req_success(request, NULL, NULL);
-}
-
-static void fake_login (struct afb_req request)
-{
- struct json_object *desc = afb_req_json(request);
- do_logout();
- if (desc)
- do_login(desc);
- afb_req_success(request, NULL, NULL);
-}
-
-static void get (struct afb_req request)
-{
- afb_req_success(request, json_object_get(current_identity), NULL);
-}
-
-static void on_nfc_subscribed(void *closure, int status, struct json_object *result)
-{
- if(status)
- AFB_ERROR("Failed to subscribe to nfc events.");
-}
-
-static void on_nfc_started(void *closure, int status, struct json_object *result)
-{
- if (!status) {
- afb_service_call("nfc", "subscribe", NULL, on_nfc_subscribed, NULL);
- }
- else
- AFB_ERROR("Failed to start nfc polling.");
-}
-
-static int service_init()
-{
- agl_forgerock_setcb(on_forgerock_data);
- event = afb_daemon_make_event("event");
- if (!afb_event_is_valid(event))
- return -1;
-
- readconfig();
-
- if (afb_daemon_require_api("nfc", 1))
- return -1;
-
- if (afb_daemon_require_api("persistence", 1))
- return -1;
-
- afb_service_call("nfc", "start", NULL, on_nfc_started, NULL);
-
- return 0;
-}
-
-static void on_nfc_target_add(struct json_object *object)
-{
- struct json_object * json_uid;
- const char *uid;
-
- if (json_object_object_get_ex(object, "UID", &json_uid))
- {
- uid = json_object_get_string(json_uid);
- AFB_NOTICE("nfc tag detected, call forgerock with vincode=%s and key=%s", vin ? vin : default_vin, uid);
- send_event_object("incoming", uid, uid);
- agl_forgerock_download_request(vin ? vin : default_vin, "nfc", uid);
- }
- else AFB_ERROR("nfc target add event is received but no UID found: %s", json_object_to_json_string(object));
-}
-
-static void onevent(const char *event, struct json_object *object)
-{
- AFB_NOTICE("Received event: %s", event);
- if (!strcmp("nfc/on-nfc-target-add", event))
- {
- on_nfc_target_add(object);
- return;
- }
- AFB_WARNING("Unhandled event: %s", event);
-}
-
-static void fake_auth(struct afb_req req)
-{
- struct json_object* req_object;
- struct json_object* kind_object;
- struct json_object* key_object;
-
- req_object = afb_req_json(req);
-
- if (!json_object_object_get_ex(req_object, "kind", &kind_object))
- {
- afb_req_fail(req, "Missing arg: kind", NULL);
- return;
- }
-
- if (!json_object_object_get_ex(req_object, "key", &key_object))
- {
- afb_req_fail(req, "Missing arg: key", NULL);
- return;
- }
-
- const char* kind = json_object_get_string(kind_object);
- const char* key = json_object_get_string(key_object);
-
- send_event_object("incoming", key, key);
- agl_forgerock_download_request(vin ? vin : default_vin, kind, key);
-
- afb_req_success(req, NULL, "fake auth success!");
-}
-
-// NOTE: this sample does not use session to keep test a basic as possible
-// in real application most APIs should be protected with AFB_SESSION_CHECK
-static const struct afb_verb_v2 verbs[]=
-{
- {"subscribe" , subscribe , NULL, "subscribe to events" , AFB_SESSION_NONE },
- {"unsubscribe", unsubscribe , NULL, "unsubscribe to events" , AFB_SESSION_NONE },
- {"fake-login" , fake_login , NULL, "fake a login" , AFB_SESSION_NONE },
- {"logout" , logout , NULL, "log the current user out", AFB_SESSION_NONE },
- {"get" , get , NULL, "get data" , AFB_SESSION_NONE },
- {"fake-auth" , fake_auth , NULL, "fake an authentication" , AFB_SESSION_NONE },
- {NULL}
-};
-
-const struct afb_binding_v2 afbBindingV2 =
-{
- .api = "identity",
- .specification = NULL,
- .info = "AGL identity service",
- .verbs = verbs,
- .preinit = NULL,
- .init = service_init,
- .onevent = onevent,
- .noconcurrency = 0
-};
-
-/* vim: set colorcolumn=80: */
diff --git a/agl-identity-service/src/aia-get.c b/agl-identity-service/src/aia-get.c
deleted file mode 100644
index 56c82b0..0000000
--- a/agl-identity-service/src/aia-get.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2015, 2016 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include "curl-wrap.h"
-#include "oidc-agent.h"
-
-/*
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-
-
-#include "u2f-bluez.h"
-*/
-
-
-struct keyrequest {
- struct keyrequest *next;
- int dead;
- time_t expiration;
- const char *url;
- const char *appli;
- const char *idp;
- void (*callback)(void *closure, int status, const void *buffer, size_t size);
- void *closure;
- json_object *token;
- pthread_t tid;
-};
-
-static struct keyrequest *keyrequests = 0;
-
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static int curl_initialized = 0;
-
-static void perform_query_callback(void *closure, int status, CURL *curl, const char *result, size_t size)
-{
- struct keyrequest *kr = closure;
- kr->callback(kr->closure, status, result, size);
-}
-
-static void perform_query(struct keyrequest *kr)
-{
- CURL *curl;
-
- curl = curl_wrap_prepare_get_url(kr->url);
- if (!curl)
- kr->callback(kr->closure, 0, "out of memory", 0);
- else {
- oidc_add_bearer(curl, kr->token);
- curl_wrap_do(curl, perform_query_callback, kr);
- }
-}
-
-static void token_success(void *closure, struct json_object *token)
-{
- struct keyrequest *kr = closure;
- kr->token = token;
- perform_query(kr);
-}
-
-static void token_error(void *closure, const char *message, const char *indice)
-{
- struct keyrequest *kr = closure;
- kr->callback(kr->closure, 0, message, 0);
-}
-
-static void *kr_get_thread(void *closure)
-{
- struct oidc_grant_cb cb;
- struct keyrequest *kr = closure;
-
- if (!kr->appli)
- perform_query(kr);
- else {
- cb.closure = kr;
- cb.success = token_success;
- cb.error = token_error;
- oidc_grant_owner_password(kr->appli, kr->idp, NULL, &cb);
- }
- kr->dead = 1;
- return NULL;
-}
-
-static void kr_free(struct keyrequest *kr)
-{
- json_object_put(kr->token);
- free(kr);
-}
-
-static struct keyrequest *kr_alloc(
- const char *url,
- time_t expiration,
- const char *appli,
- const char *idp,
- void (*callback)(void *closure, int status, const void *buffer, size_t size),
- void *closure
-)
-{
- struct keyrequest *result;
- char *buf;
- size_t surl, sappli, sidp;
-
- surl = 1 + strlen(url);
- sappli = appli ? 1 + strlen(appli) : 0;
- sidp = idp ? 1 + strlen(idp) : 0;
-
- result = calloc(1, surl + sappli + sidp + sizeof *result);
- if (result) {
- result->next = NULL;
- result->dead = 0;
- result->expiration = expiration;
- result->callback = callback;
- result->closure = closure;
- result->token = NULL;
- result->tid = 0;
-
- buf = (char*)(&result[1]);
- result->url = buf;
- buf = mempcpy(buf, url, surl);
- if (!appli)
- result->appli = NULL;
- else {
- result->appli = buf;
- buf = mempcpy(buf, appli, sappli);
- }
- if (!idp)
- result->idp = NULL;
- else {
- result->idp = buf;
- buf = mempcpy(buf, idp, sidp);
- }
- }
- return result;
-}
-
-void aia_get(
- const char *url,
- int delay,
- const char *appli,
- const char *idp,
- void (*callback)(void *closure, int status, const void *buffer, size_t size),
- void *closure
-)
-{
- int rc;
- time_t now;
- struct keyrequest **pkr, *kr, *found_kr;
-
- /* initialize CURL component */
- pthread_mutex_lock(&mutex);
- if (!curl_initialized) {
- curl_initialized = 1;
- curl_global_init(CURL_GLOBAL_DEFAULT);
- }
-
- /* search for the same request and also cleanup deads */
- now = time(NULL);
- found_kr = 0;
- pkr = &keyrequests;
- kr = *pkr;
- while (kr) {
- if (now > kr->expiration) {
- if (kr->dead) {
- *pkr = kr->next;
- kr_free(kr);
- } else {
- pkr = &kr->next;
- }
- } else {
- if (!strcmp(url, kr->url))
- found_kr = kr;
- pkr = &kr->next;
- }
- kr = *pkr;
- }
-
- /* check if found and pending */
- if (found_kr) {
- /* found -> cancel */
- pthread_mutex_unlock(&mutex);
- callback(closure, 0, NULL, 0);
- return;
- }
-
- /* allocates the keyrequest */
- kr = kr_alloc(url, now + delay, appli, idp, callback, closure);
- if (!kr) {
- pthread_mutex_unlock(&mutex);
- callback(closure, 0, "Out of memory", 0);
- return;
- }
-
- /* link the request */
- kr->next = keyrequests;
- keyrequests = kr;
-
- /* makes the request in a new thread */
- rc = pthread_create(&kr->tid, 0, kr_get_thread, kr);
- if (rc != 0) {
- /* error, unlink */
- keyrequests = kr->next;
- pthread_mutex_unlock(&mutex);
- kr_free(kr);
- callback(closure, 0, "Can't create a new thread", 0);
- return;
- }
- pthread_mutex_unlock(&mutex);
-}
-
-/* vim: set colorcolumn=80: */
-
diff --git a/agl-identity-service/src/aia-get.h b/agl-identity-service/src/aia-get.h
deleted file mode 100644
index be1a1f8..0000000
--- a/agl-identity-service/src/aia-get.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-extern void aia_get(
- const char *url,
- int delay,
- const char *appli,
- const char *idp,
- void (*callback)(void *closure, int status, const void *buffer, size_t size),
- void *closure
-);
-
diff --git a/agl-identity-service/src/authorization.c b/agl-identity-service/src/authorization.c
deleted file mode 100644
index ae00923..0000000
--- a/agl-identity-service/src/authorization.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _GNU_SOURCE
-
-#include
-#include
-
-#include "base64.h"
-
-char *authorization_basic_make(const char *user, const char *password)
-{
- const char *array[3] = { user, ":", password };
- return base64_encode_array(array, 3);
-}
-
-char *authorization_basic_make_header(const char *user, const char *password)
-{
- char *key, *result;
-
- key = authorization_basic_make(user, password);
- if (!key || asprintf(&result, "Authorization: Basic %s", key) < 0)
- result = NULL;
- free(key);
- return result;
-}
-
-/* vim: set colorcolumn=80: */
-
diff --git a/agl-identity-service/src/authorization.h b/agl-identity-service/src/authorization.h
deleted file mode 100644
index bd26c1a..0000000
--- a/agl-identity-service/src/authorization.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-extern char *authorization_basic_make(const char *user, const char *password);
-extern char *authorization_basic_make_header(const char *user, const char *password);
-
-/* vim: set colorcolumn=80: */
diff --git a/agl-identity-service/src/base64.c b/agl-identity-service/src/base64.c
deleted file mode 100644
index 0841aba..0000000
--- a/agl-identity-service/src/base64.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include
-#include
-#include
-
-const char base64_variant_standard[] = "+/=";
-const char base64_variant_url[] = "-_=";
-const char base64_variant_trunc[] = "+/";
-const char base64_variant_url_trunc[] = "-_";
-
-static char eb64(int x, const char *variant)
-{
- if (x < 52)
- return (char)(x + (x < 26 ? 'A' : 'a'-26));
- else
- return x < 62 ? (char)(x + '0' - 52) : variant[x - 62];
-}
-
-char *base64_encode_array_variant(const char * const *args, size_t count, const char *variant)
-{
- const char *v, *s;
- char *buffer, c;
- size_t i, j, n;
- uint16_t x;
-
- /* compute size and allocate */
- i = n = 0;
- while (n < count)
- i += strlen(args[n++]);
- buffer = malloc(5 + ((i / 3) << 2));
- if (!buffer)
- return NULL;
-
- /* encode */
- v = variant ? : base64_variant_standard;
- n = 0;
- j = 0;
- x = 0;
- while (n < count) {
- s = args[n++];
- c = s[i = 0];
- while (c) {
- x = (uint16_t)((uint16_t)(x << 8) | (uint16_t)(uint8_t)c);
- switch (j & 3) {
- case 0:
- buffer[j++] = eb64((x >> 2) & 63, v);
- break;
- case 1:
- buffer[j++] = eb64((x >> 4) & 63, v);
- break;
- case 2:
- buffer[j++] = eb64((x >> 6) & 63, v);
- buffer[j++] = eb64(x & 63, v);
- break;
- }
- c = s[++i];
- }
- }
-
- /* pad */
- if (v[2]) {
- switch (j & 3) {
- case 1:
- buffer[j++] = eb64((x << 4) & 63, v);
- buffer[j++] = v[2];
- buffer[j++] = v[2];
- break;
- case 2:
- buffer[j++] = eb64((x << 2) & 63, v);
- buffer[j++] = v[2];
- break;
- }
- }
-
- /* done */
- buffer[j] = 0;
- return buffer;
-}
-
-char *base64_encode_multi_variant(const char * const *args, const char *variant)
-{
- size_t count;
-
- for (count = 0 ; args[count] ; count++);
- return base64_encode_array_variant(args, count, variant);
-}
-
-char *base64_encode_variant(const char *arg, const char *variant)
-{
- return base64_encode_array_variant(&arg, !!arg, variant);
-}
-
diff --git a/agl-identity-service/src/base64.h b/agl-identity-service/src/base64.h
deleted file mode 100644
index 5a944df..0000000
--- a/agl-identity-service/src/base64.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-extern const char base64_variant_standard[];
-extern const char base64_variant_trunc[];
-
-extern const char base64_variant_url[];
-extern const char base64_variant_url_trunc[];
-
-extern char *base64_encode_array_variant(const char * const *args, size_t count, const char *variant);
-extern char *base64_encode_multi_variant(const char * const *args, const char *variant);
-extern char *base64_encode_variant(const char *arg, const char *variant);
-
-#define base64_encode_array(args,count) base64_encode_array_variant(args,count,base64_variant_standard)
-#define base64_encode_multi(args) base64_encode_multi_variant(args,base64_variant_standard)
-#define base64_encode(arg) base64_encode_variant(arg,base64_variant_standard)
-
-#define base64_encode_array_standard(args,count) base64_encode_array_variant(args,count,base64_variant_standard)
-#define base64_encode_multi_standard(args) base64_encode_multi_variant(args,base64_variant_standard)
-#define base64_encode_standard(arg) base64_encode_variant(arg,base64_variant_standard)
-
-#define base64_encode_array_url(args,count) base64_encode_array_variant(args,count,base64_variant_url)
-#define base64_encode_multi_url(args) base64_encode_multi_variant(args,base64_variant_url)
-#define base64_encode_url(arg) base64_encode_variant(arg,base64_variant_url)
-
-#define base64_encode_array_trunc(args,count) base64_encode_array_variant(args,count,base64_variant_trunc)
-#define base64_encode_multi_trunc(args) base64_encode_multi_variant(args,base64_variant_trunc)
-#define base64_encode_trunc(arg) base64_encode_variant(arg,base64_variant_trunc)
-
-#define base64_encode_array_url_trunc(args,count) base64_encode_array_variant(args,count,base64_variant_url_trunc)
-#define base64_encode_multi_url_trunc(args) base64_encode_multi_variant(args,base64_variant_url_trunc)
-#define base64_encode_url_trunc(arg) base64_encode_variant(arg,base64_variant_url_trunc)
-
-
-
diff --git a/agl-identity-service/src/curl-wrap.c b/agl-identity-service/src/curl-wrap.c
deleted file mode 100644
index 3c566a3..0000000
--- a/agl-identity-service/src/curl-wrap.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2015, 2016 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-
-#include
-#include
-#include
-#include
-
-#include
-
-#include "curl-wrap.h"
-#include "escape.h"
-
-
-/* internal representation of buffers */
-struct buffer {
- size_t size;
- char *data;
-};
-
-/* write callback for filling buffers with the response */
-static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
-{
- struct buffer *buffer = userdata;
- size_t sz = size * nmemb;
- size_t old_size = buffer->size;
- size_t new_size = old_size + sz;
- char *data = realloc(buffer->data, new_size + 1);
- if (!data)
- return 0;
- memcpy(&data[old_size], ptr, sz);
- data[new_size] = 0;
- buffer->size = new_size;
- buffer->data = data;
- return sz;
-}
-
-/*
- * Perform the CURL operation for 'curl' and put the result in
- * memory. If 'result' isn't NULL it receives the returned content
- * that then must be freed. If 'size' isn't NULL, it receives the
- * size of the returned content. Note that if not NULL, the real
- * content is one byte greater than the read size and the last byte
- * zero. This facility allows to handle the returned content as a
- * null terminated C-string.
- */
-int curl_wrap_perform(CURL *curl, char **result, size_t *size)
-{
- int rc;
- struct buffer buffer;
- CURLcode code;
-
- /* init tthe buffer */
- buffer.size = 0;
- buffer.data = NULL;
-
- /* Perform the request, res will get the return code */
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
-
- /* Perform the request, res will get the return code */
- code = curl_easy_perform(curl);
- rc = code == CURLE_OK;
-
- /* Check for no errors */
- if (rc) {
- /* no error */
- if (size)
- *size = buffer.size;
- if (result)
- *result = buffer.data;
- else
- free(buffer.data);
- } else {
- /* had error */
- if (size)
- *size = 0;
- if (result)
- *result = NULL;
- free(buffer.data);
- }
-
- return rc;
-}
-
-void curl_wrap_do(CURL *curl, void (*callback)(void *closure, int status, CURL *curl, const char *result, size_t size), void *closure)
-{
- int rc;
- char *result;
- size_t size;
- char errbuf[CURL_ERROR_SIZE];
-
- curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
- rc = curl_wrap_perform(curl, &result, &size);
- if (rc)
- callback(closure, rc, curl, result, size);
- else
- callback(closure, rc, curl, errbuf, 0);
- free(result);
- curl_easy_cleanup(curl);
-}
-
-int curl_wrap_content_type_is(CURL *curl, const char *value)
-{
- char *actual;
- CURLcode code;
-
- code = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &actual);
- if (code != CURLE_OK || !actual)
- return 0;
-
- return !strncasecmp(actual, value, strcspn(actual, "; "));
-}
-
-CURL *curl_wrap_prepare_get_url(const char *url)
-{
- CURL *curl;
- CURLcode code;
-
- curl = curl_easy_init();
- if(curl) {
- code = curl_easy_setopt(curl, CURLOPT_URL, url);
- if (code == CURLE_OK)
- return curl;
- curl_easy_cleanup(curl);
- }
- return NULL;
-}
-
-CURL *curl_wrap_prepare_get(const char *base, const char *path, const char * const *args)
-{
- CURL *res;
- char *url;
-
- url = escape_url(base, path, args, NULL);
- res = url ? curl_wrap_prepare_get_url(url) : NULL;
- free(url);
- return res;
-}
-
-int curl_wrap_add_header(CURL *curl, const char *header)
-{
- int rc;
- struct curl_slist *list;
-
- list = curl_slist_append(NULL, header);
- rc = list ? curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list) == CURLE_OK : 0;
-/*
- curl_slist_free_all(list);
-*/
- return rc;
-}
-
-int curl_wrap_add_header_value(CURL *curl, const char *name, const char *value)
-{
- char *h;
- int rc;
-
- rc = asprintf(&h, "%s: %s", name, value);
- rc = rc < 0 ? 0 : curl_wrap_add_header(curl, h);
- free(h);
- return rc;
-}
-
-
-CURL *curl_wrap_prepare_post_url_data(const char *url, const char *datatype, const char *data, size_t szdata)
-{
- CURL *curl;
-
- curl = curl_easy_init();
- if (curl
- && CURLE_OK == curl_easy_setopt(curl, CURLOPT_URL, url)
- && (!szdata || CURLE_OK == curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, szdata))
- && CURLE_OK == curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data)
- && (!datatype || curl_wrap_add_header_value(curl, "content-type", datatype)))
- return curl;
- curl_easy_cleanup(curl);
- return NULL;
-}
-
-CURL *curl_wrap_prepare_post(const char *base, const char *path, const char * const *args)
-{
- CURL *res;
- char *url;
- char *data;
- size_t szdata;
-
- url = escape_url(base, path, NULL, NULL);
- data = escape_args(args, &szdata);
- res = url ? curl_wrap_prepare_post_url_data(url, NULL, data, szdata) : NULL;
- free(url);
- return res;
-}
-
-/* vim: set colorcolumn=80: */
diff --git a/agl-identity-service/src/curl-wrap.h b/agl-identity-service/src/curl-wrap.h
deleted file mode 100644
index 2e44f47..0000000
--- a/agl-identity-service/src/curl-wrap.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015, 2016 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#pragma once
-
-#include
-
-extern char *curl_wrap_url (const char *base, const char *path,
- const char *const *query, size_t * size);
-
-extern int curl_wrap_perform (CURL * curl, char **result, size_t * size);
-
-extern void curl_wrap_do(CURL *curl, void (*callback)(void *closure, int status, CURL *curl, const char *result, size_t size), void *closure);
-
-extern int curl_wrap_content_type_is (CURL * curl, const char *value);
-
-extern CURL *curl_wrap_prepare_get_url(const char *url);
-
-extern CURL *curl_wrap_prepare_get(const char *base, const char *path, const char * const *args);
-
-extern CURL *curl_wrap_prepare_post_url_data(const char *url, const char *datatype, const char *data, size_t szdata);
-
-extern CURL *curl_wrap_prepare_post(const char *base, const char *path, const char * const *args);
-
-extern int curl_wrap_add_header(CURL *curl, const char *header);
-
-extern int curl_wrap_add_header_value(CURL *curl, const char *name, const char *value);
-
-/* vim: set colorcolumn=80: */
-
diff --git a/agl-identity-service/src/escape.c b/agl-identity-service/src/escape.c
deleted file mode 100644
index 3bb25c2..0000000
--- a/agl-identity-service/src/escape.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Copyright (C) 2015, 2016 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-
-#include
-#include
-#include
-
-/*
- * Test if 'c' is to be escaped or not.
- * Any character that is not in [-.0-9A-Z_a-z~]
- * must be escaped.
- * Note that space versus + is not managed here.
- */
-static inline int should_escape(char c)
-{
-/* ASCII CODES OF UNESCAPED CHARS
-car hx/oct idx
-'-' 2d/055 1
-'.' 2e/056 2
-'0' 30/060 3
-... ..
-'9' 39/071 12
-'A' 41/101 13
-... ..
-'Z' 5a/132 38
-'_' 5f/137 39
-'a' 61/141 40
-... ..
-'z' 7a/172 65
-'~' 7e/176 66
-*/
- /* [-.0-9A-Z_a-z~] */
- if (c <= 'Z') {
- /* [-.0-9A-Z] */
- if (c < '0') {
- /* [-.] */
- return c != '-' && c != '.';
- } else {
- /* [0-9A-Z] */
- return c < 'A' && c > '9';
- }
- } else {
- /* [_a-z~] */
- if (c <= 'z') {
- /* [_a-z] */
- return c < 'a' && c != '_';
- } else {
- /* [~] */
- return c != '~';
- }
- }
-}
-
-/*
- * returns the ASCII char for the hexadecimal
- * digit of the binary value 'f'.
- * returns 0 if f isn't in [0 ... 15].
- */
-static inline char bin2hex(int f)
-{
- if ((f & 15) != f)
- f = 0;
- else if (f < 10)
- f += '0';
- else
- f += 'A' - 10;
- return (char)f;
-}
-
-/*
- * returns the binary value for the hexadecimal
- * digit whose char is 'c'.
- * returns -1 if c isn't i n[0-9A-Fa-f]
- */
-static inline int hex2bin(char c)
-{
- /* [0-9A-Fa-f] */
- if (c <= 'F') {
- /* [0-9A-F] */
- if (c <= '9') {
- /* [0-9] */
- if (c >= '0') {
- return (int)(c - '0');
- }
- } else if (c >= 'A') {
- /* [A-F] */
- return (int)(c - ('A' - 10));
- }
- } else {
- /* [a-f] */
- if (c >= 'a' && c <= 'f') {
- return (int)(c - ('a' - 10));
- }
- }
- return -1;
-}
-
-/*
- * returns the length that will have the text 'itext' of length
- * 'ilen' when escaped. When 'ilen' == 0, strlen is used to
- * compute the size of 'itext'.
- */
-static size_t escaped_length(const char *itext, size_t ilen)
-{
- char c;
- size_t i, r;
-
- if (!ilen)
- ilen = strlen(itext);
- c = itext[i = r = 0];
- while (i < ilen) {
- r += c != ' ' && should_escape(c) ? 3 : 1;
- c = itext[++i];
- }
- return r;
-}
-
-/*
- * Escapes the text 'itext' of length 'ilen'.
- * When 'ilen' == 0, strlen is used to compute the size of 'itext'.
- * The escaped text is put in 'otext' of length 'olen'.
- * Returns the length of the escaped text (it can be greater than 'olen').
- * When 'olen' is greater than the needed length, an extra null terminator
- * is appened to the escaped string.
- */
-static size_t escape_to(const char *itext, size_t ilen, char *otext, size_t olen)
-{
- char c;
- size_t i, r;
-
- if (!ilen)
- ilen = strlen(itext);
- c = itext[i = r = 0];
- while (i < ilen) {
- if (c == ' ')
- c = '+';
- else if (should_escape(c)) {
- if (r < olen)
- otext[r] = '%';
- r++;
- if (r < olen)
- otext[r] = bin2hex((c >> 4) & 15);
- r++;
- c = bin2hex(c & 15);
- }
- if (r < olen)
- otext[r] = c;
- r++;
- c = itext[++i];
- }
- if (r < olen)
- otext[r] = 0;
- return r;
-}
-
-/*
- * returns the length of 'itext' of length 'ilen' that can be unescaped.
- * compute the size of 'itext' when 'ilen' == 0.
- */
-static size_t unescapable_length(const char *itext, size_t ilen)
-{
- char c;
- size_t i;
-
- c = itext[i = 0];
- while (i < ilen) {
- if (c != '%')
- i++;
- else {
- if (i + 3 > ilen
- || hex2bin(itext[i + 1]) < 0
- || hex2bin(itext[i + 2]) < 0)
- break;
- i += 3;
- }
- c = itext[i];
- }
- return i;
-}
-
-/*
- * returns the length that will have the text 'itext' of length
- * 'ilen' when escaped. When 'ilen' == 0, strlen is used to
- * compute the size of 'itext'.
- */
-static size_t unescaped_length(const char *itext, size_t ilen)
-{
- char c;
- size_t i, r;
-
- c = itext[i = r = 0];
- while (i < ilen) {
- i += (size_t)(1 + ((c == '%') << 1));
- r++;
- c = itext[i];
- }
- return r;
-}
-
-static size_t unescape_to(const char *itext, size_t ilen, char *otext, size_t olen)
-{
- char c;
- size_t i, r;
- int h, l;
-
- ilen = unescapable_length(itext, ilen);
- c = itext[i = r = 0];
- while (i < ilen) {
- if (c != '%') {
- if (c == '+')
- c = ' ';
- i++;
- } else {
- if (i + 2 >= ilen)
- break;
- h = hex2bin(itext[i + 1]);
- l = hex2bin(itext[i + 2]);
- c = (char)((h << 4) | l);
- i += 3;
- }
- if (r < olen)
- otext[r] = c;
- r++;
- c = itext[i];
- }
- if (r < olen)
- otext[r] = 0;
- return r;
-}
-
-/* create an url */
-char *escape_url(const char *base, const char *path, const char * const *args, size_t *length)
-{
- int i;
- size_t lb, lp, lq, l, L;
- const char *null;
- char *result;
-
- /* ensure args */
- if (!args) {
- null = NULL;
- args = &null;
- }
-
- /* compute lengths */
- lb = base ? strlen(base) : 0;
- lp = path ? strlen(path) : 0;
- lq = 0;
- i = 0;
- while (args[i]) {
- lq += 1 + escaped_length(args[i], strlen(args[i]));
- i++;
- if (args[i])
- lq += 1 + escaped_length(args[i], strlen(args[i]));
- i++;
- }
-
- /* allocation */
- L = lb + lp + lq + 1;
- result = malloc(L + 1);
- if (result) {
- /* make the resulting url */
- l = lb;
- if (lb) {
- memcpy(result, base, lb);
- if (result[l - 1] != '/' && path && path[0] != '/')
- result[l++] = '/';
- }
- if (lp) {
- memcpy(result + l, path, lp);
- l += lp;
- }
- i = 0;
- while (args[i]) {
- if (i) {
- result[l++] = '&';
- } else if (base || path) {
- result[l] = memchr(result, '?', l) ? '&' : '?';
- l++;
- }
- l += escape_to(args[i], strlen(args[i]), result + l, L - l);
- i++;
- if (args[i]) {
- result[l++] = '=';
- l += escape_to(args[i], strlen(args[i]), result + l, L - l);
- }
- i++;
- }
- result[l] = 0;
- if (length)
- *length = l;
- }
- return result;
-}
-
-char *escape_args(const char * const *args, size_t *length)
-{
- return escape_url(NULL, NULL, args, length);
-}
-
-const char **unescape_args(const char *args)
-{
- const char **r, **q;
- char c, *p;
- size_t j, z, l, n, lt;
-
- lt = n = 0;
- if (args[0]) {
- z = 0;
- do {
- l = strcspn(&args[z], "&=");
- j = 1 + unescaped_length(&args[z], l);
- lt += j;
- z += l;
- c = args[z++];
- if (c == '=') {
- l = strcspn(&args[z], "&");
- j = 1 + unescaped_length(&args[z], l);
- lt += j;
- z += l;
- c = args[z++];
- }
- n++;
- } while(c);
- }
-
- l = lt + (2 * n + 1) * sizeof(char *);
- r = malloc(l);
- if (!r)
- return r;
-
- q = r;
- p = (void*)&r[2 * n + 1];
- if (args[0]) {
- z = 0;
- do {
- q[0] = p;
- l = strcspn(&args[z], "&=");
- j = 1 + unescape_to(&args[z], l, p, lt);
- lt -= j;
- p += j;
- z += l;
- c = args[z++];
- if (c != '=')
- q[1] = NULL;
- else {
- q[1] = p;
- l = strcspn(&args[z], "&");
- j = 1 + unescape_to(&args[z], l, p, lt);
- lt -= j;
- p += j;
- z += l;
- c = args[z++];
- }
- q = &q[2];
- } while(c);
- }
- q[0] = NULL;
- return r;
-}
-
-char *escape(const char *text, size_t textlen, size_t *reslength)
-{
- size_t len;
- char *result;
-
- len = 1 + escaped_length(text, textlen);
- result = malloc(len);
- if (result)
- escape_to(text, textlen, result, len);
- if (reslength)
- *reslength = len - 1;
- return result;
-}
-
-char *unescape(const char *text, size_t textlen, size_t *reslength)
-{
- size_t len;
- char *result;
-
- len = 1 + unescaped_length(text, textlen);
- result = malloc(len);
- if (result)
- unescape_to(text, textlen, result, len);
- if (reslength)
- *reslength = len - 1;
- return result;
-}
-
-#if 1
-#include
-int main(int ac, char **av)
-{
- int i;
- char *x = escape_args((void*)++av, NULL);
- char *y = escape(x, strlen(x), NULL);
- char *z = unescape(y, strlen(y), NULL);
- const char **v = unescape_args(x);
-
- printf("%s\n%s\n%s\n", x, y, z);
- free(x);
- free(y);
- free(z);
- i = 0;
- while(v[i]) {
- printf("%s=%s / %s=%s\n", av[i], av[i+1], v[i], v[i+1]);
- i += 2;
- }
- free(v);
- return 0;
-}
-#endif
-/* vim: set colorcolumn=80: */
diff --git a/agl-identity-service/src/escape.h b/agl-identity-service/src/escape.h
deleted file mode 100644
index 7d548db..0000000
--- a/agl-identity-service/src/escape.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-extern char *escape_url(const char *base, const char *path, const char * const *args, size_t *length);
-extern char *escape_args(const char * const *args, size_t *length);
-extern const char **unescape_args(const char *args);
-
-/* vim: set colorcolumn=80: */
diff --git a/agl-identity-service/src/export.map b/agl-identity-service/src/export.map
deleted file mode 100644
index ee2f413..0000000
--- a/agl-identity-service/src/export.map
+++ /dev/null
@@ -1 +0,0 @@
-{ global: afbBindingV*; local: *; };
diff --git a/agl-identity-service/src/memo.txt b/agl-identity-service/src/memo.txt
deleted file mode 100644
index 3a6ed50..0000000
--- a/agl-identity-service/src/memo.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-
-gcc --shared -fPIC -o aia.so [^t]*.c -lcurl -lsystemd -ljson-c
-
-afb-daemon --rootdir=. --ldpaths=. --port=1212 --token= --verbose --verbose --verbose
-
-
-afb-client-demo localhost:1212/api?token=t
-agl-identity-agent subscribe
-
-
-gcc -o taia *aia-uds-bluez.c -lsystemd
diff --git a/agl-identity-service/src/oidc-agent.c b/agl-identity-service/src/oidc-agent.c
deleted file mode 100644
index 1f09e7a..0000000
--- a/agl-identity-service/src/oidc-agent.c
+++ /dev/null
@@ -1,812 +0,0 @@
-/*
- * Copyright (C) 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _GNU_SOURCE
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include "oidc-agent.h"
-#include "escape.h"
-#include "curl-wrap.h"
-
-/***************** utilities *************************/
-
-static const char string_empty[] = "";
-static const char string_authorization_endpoint[] = "authorization_endpoint";
-static const char string_token_endpoint[] = "token_endpoint";
-#if 0
-static const char string_issuer[] = "issuer";
-static const char string_userinfo_endpoint[] = "userinfo_endpoint";
-static const char string_revocation_endpoint[] = "revocation_endpoint";
-static const char string_jwks_uri[] = "jwks_uri";
-#endif
-
-#define MAX_IDP_COUNT 20
-#define MAX_APPLI_COUNT 100
-
-static struct json_object *idps;
-static struct json_object *applis;
-
-static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
-
-/***************** utilities *************************/
-
-/*
- * Get the object of 'name' in the 'container' and return it.
- * Creates the result if needed and add it to the container.
- * When 'maxcount' isn't zero the final count will not exceed 'maxcount'.
- */
-static struct json_object *j_container_item(struct json_object *container, const char *name, int maxcount)
-{
- struct json_object *result;
-
- /* ensure object of 'name' exists */
- if (!json_object_object_get_ex(container, name, &result)) {
- if (maxcount && json_object_object_length(container) >= maxcount)
- return NULL;
- result = json_object_new_object();
- if (!result)
- return NULL;
- json_object_object_add (container, name, result);
- }
- return result;
-}
-
-/*
- * Like 'j_container_item' but also creates the 'container' if needed.
- */
-static struct json_object *j_container_item_make(struct json_object **container, const char *name, int maxcount)
-{
- struct json_object *cont;
-
- /* ensure container exists */
- cont = *container;
- if (!cont) {
- cont = json_object_new_object();
- if (!cont)
- return NULL;
- *container = cont;
- }
- return j_container_item(cont, name, maxcount);
-}
-
-/*
- * Adds in 'dest' the fields of 'src'
- * Also when the value of a field of 'src' is null, delete the field of 'dst'
- */
-static void j_merge(struct json_object *dest, struct json_object *src)
-{
- struct json_object_iter i;
- json_object_object_foreachC(src, i) {
- if (json_object_is_type(i.val, json_type_null))
- json_object_object_del(dest, i.key);
- else
- json_object_object_add(dest, i.key, json_object_get(i.val));
- }
-}
-
-/***************** IDP **************************/
-
-/*
- * Set the values of 'desc' for the idp of 'name'.
- * Return 0 on error or 1 on success.
- */
-int oidc_idp_set(const char *name, struct json_object *desc)
-{
- struct json_object *idp;
- int result = 0;
-
- pthread_rwlock_wrlock(&rwlock);
- idp = j_container_item_make(&idps, name, MAX_IDP_COUNT);
- if (idp) {
- j_merge(idp, desc);
- result = 1;
- }
- pthread_rwlock_unlock(&rwlock);
- return result;
-}
-
-/*
- * Return 1 if idp of 'name' exists or 0 otherwise.
- */
-int oidc_idp_exists(const char *name)
-{
- int result;
-
- pthread_rwlock_rdlock(&rwlock);
- result = json_object_object_get_ex(idps, name, NULL);
- pthread_rwlock_unlock(&rwlock);
-
- return result;
-}
-
-/*
- * Deletes the idp of 'name'.
- */
-void oidc_idp_delete(const char *name)
-{
- pthread_rwlock_wrlock(&rwlock);
- json_object_object_del(idps, name);
- pthread_rwlock_unlock(&rwlock);
-}
-
-/***************** APPLI **************************/
-
-/*
- * Returns the name of the idp of the 'appli'.
- * Returns NULL when appli isn't set or default idp isn't set.
- */
-static const char *get_default_idp(const char *appli)
-{
- struct json_object *a, *i;
-
- if (!json_object_object_get_ex(applis, appli, &a))
- return NULL;
- if (!json_object_object_get_ex(a, string_empty, &i))
- return NULL;
- return json_object_get_string(i);
-}
-
-/*
- * Returns the application data related to the 'appli' for the 'idp'.
- * If 'ja' isn't null, returns in it the object for the application 'appli'.
- * Returns NULL in case of error.
- */
-static struct json_object *get_appli_idp(const char *appli, const char *idp, struct json_object **ja)
-{
- struct json_object *a, *i;
-
- if (!json_object_object_get_ex(applis, appli, &a) || !json_object_object_get_ex(a, idp, &i))
- return NULL;
- if (ja)
- *ja = a;
- return i;
-}
-
-/*
- * Set the description 'desc' for the application of 'name' and
- * the 'idp'. When 'make_default' is set it, make it the default idp
- * for the application.
- * Return 0 on error or 1 on success.
- */
-int oidc_appli_set(const char *name, const char *idp, struct json_object *desc, int make_default)
-{
- struct json_object *a, *ai;
- int result = 0;
-
- pthread_rwlock_wrlock(&rwlock);
- a = j_container_item_make(&applis, name, MAX_APPLI_COUNT);
- if (a) {
- ai = j_container_item(a, idp, 0);
- if (ai) {
- j_merge(ai, desc);
- if (make_default || !json_object_object_get_ex(a, string_empty, NULL))
- json_object_object_add(a, string_empty, json_object_new_string(idp));
- result = 1;
- }
- }
- pthread_rwlock_unlock(&rwlock);
- return result;
-}
-
-/*
- * Is the appli of 'name' defined?
- * Return 1 if answer is yes or 0 for no.
- */
-int oidc_appli_exists(const char *name)
-{
- int result;
-
- pthread_rwlock_rdlock(&rwlock);
- result = json_object_object_get_ex(applis, name, NULL);
- pthread_rwlock_unlock(&rwlock);
-
- return result;
-}
-
-/*
- * Does the appli of 'name' has the 'idp' defined?
- * Return 1 if answer is yes or 0 for no.
- */
-int oidc_appli_has_idp(const char *name, const char *idp)
-{
- int result;
-
- pthread_rwlock_rdlock(&rwlock);
- result = !!get_appli_idp(name, idp, NULL);
- pthread_rwlock_unlock(&rwlock);
-
- return result;
-}
-
-/*
- * Set 'idp' as default for the application of 'name'.
- * Returns 0 on error (appli or idp for appli not existing)
- * or 1 in case of success.
- */
-int oidc_appli_set_default_idp(const char *name, const char *idp)
-{
- struct json_object *a, *i;
-
- pthread_rwlock_wrlock(&rwlock);
- i = get_appli_idp(name, idp, &a);
- if (i)
- json_object_object_add(a, string_empty, json_object_new_string(idp));
- pthread_rwlock_unlock(&rwlock);
-
- return !!i;
-}
-
-/*
- * Deletes the application of 'name'
- */
-void oidc_appli_delete(const char *name)
-{
- pthread_rwlock_wrlock(&rwlock);
- json_object_object_del(applis, name);
- pthread_rwlock_unlock(&rwlock);
-}
-
-/***************** AUTHORISATION **************************/
-
-/* parameters */
-enum param
-{
- Param_Access_Token,
- Param_Acr_Values,
- Param_Authorization,
- Param_Client_Id,
- Param_Client_Secret,
- Param_Code,
- Param_Display,
- Param_Error,
- Param_Error_Description,
- Param_Error_Uri,
- Param_Expires_In,
- Param_Grant_Type,
- Param_Id_Token,
- Param_Id_Token_Hint,
- Param_Login_Hint,
- Param_Max_Age,
- Param_Nonce,
- Param_Password,
- Param_Prompt,
- Param_Redirect_Uri,
- Param_Refresh_Token,
- Param_Response_Type,
- Param_Scope,
- Param_State,
- Param_Token_Type,
- Param_Ui_Locales,
- Param_Username,
- PARAM_COUNT
-};
-
-#if PARAM_COUNT > 30
-# error "Too much parameters"
-#endif
-#define PARAM(p) ((uint32_t)((uint32_t)1 << (Param_##p)))
-
-/* args of authorization requests */
-struct args
-{
- struct json_object *appli;
- struct json_object *idp;
- struct json_object *args;
- struct oidc_grant_cb cb;
- int locked;
- int refresh;
- uint32_t mandatory;
- uint32_t all;
- struct json_object *header;
- struct json_object *query;
-};
-
-/* Release the lock if needed */
-static void args_unlock(struct args *args)
-{
- if (!args->locked) {
- pthread_rwlock_unlock(&rwlock);
- args->locked = 0;
- }
-}
-
-/* Release the memory needed by args */
-static void args_destroy(struct args *args)
-{
- json_object_put(args->appli);
- json_object_put(args->idp);
- json_object_put(args->header);
- json_object_put(args->query);
- free(args);
-}
-
-/* Send the success event with the gained tokens */
-static void args_send_success(struct args *args, struct json_object *result)
-{
- args_unlock(args);
- args->cb.success(args->cb.closure, result);
- args_destroy(args);
-}
-
-/* Sends the error event with the indice to the client of args */
-static void args_send_error(struct args *args, const char *message, const char *indice)
-{
- args_unlock(args);
- args->cb.error(args->cb.closure, message, indice);
- args_destroy(args);
-}
-
-/* Send the error and also return NULL */
-static inline struct args *args_send_error_null(struct args *args, const char *message, const char *indice)
-{
- args_send_error(args, message, indice);
- return NULL;
-}
-
-/* creates a struct args from the arguments, returns NULL on error */
-struct args *mkargs(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb)
-{
- struct args *result;
- struct json_object *obj;
-
- /* allocates the args */
- result = calloc(1, sizeof *result);
- if (!result) {
- cb->error(cb->closure, "Out of memory", NULL);
- return NULL;
- }
-
- /* init of the structure */
- result->cb = *cb;
- result->args = args;
- result->header = json_object_new_object();
- result->query = json_object_new_object();
-
- /* lock in read */
- pthread_rwlock_rdlock(&rwlock);
- result->locked = 1;
-
- /* check previous allocations */
- if (!result->query || !result->header) {
- return args_send_error_null(result, "Out of memory", NULL);
- }
-
- /* check whether default idp */
- if (!idp) {
- idp = get_default_idp(appli);
- if (!idp)
- return args_send_error_null(result, "No default IDP", NULL);
- }
-
- /* get the IDP */
- if (!json_object_object_get_ex(idps, idp, &obj))
- return args_send_error_null(result, "Unknown IDP", idp);
- result->idp = json_object_get(obj);
-
- /* get the appli */
- obj = get_appli_idp(appli, idp, NULL);
- if (!obj)
- return args_send_error_null(result, "Unknown APPLI for IDP", appli);
- result->appli = json_object_get(obj);
-
- return result;
-}
-
-/* get a value for a struct args */
-static struct json_object *args_object(struct args *args, const char *name)
-{
- struct json_object *result;
-
- if (!json_object_object_get_ex(args->appli, name, &result)
- && !json_object_object_get_ex(args->idp, name, &result)
- && !json_object_object_get_ex(args->args, name, &result))
- result = NULL;
- return result;
-}
-
-/* get a string value for a struct args */
-static const char *args_string(struct args *args, const char *name)
-{
- struct json_object *object = args_object(args, name);
- return object ? json_object_get_string(object) : NULL;
-}
-
-/* add a data */
-static int args_add(struct args *args, uint32_t val, const char *name, int query)
-{
- struct json_object *obj, *dest;
-
- if (val & args->all) {
- obj = args_object(args, name);
- if (obj) {
- dest = query ? args->query : args->header;
- json_object_object_add(dest, name, json_object_get(obj));
- }
- else if (val & args->mandatory) {
- args_send_error(args, "Mandatory field missing", name);
- return 0;
- }
- }
-
- return 1;
-}
-
-/*
- * Makes the CURL object for the given 'url' for either GET or POST depending
- * on 'post' with the added 'header' fields and the given query parameters.
- * Returns NULL on error.
- * Ex:
- *
- * curl_json("http://iot.bzh/api", 0, {"X-Index": "no"}, {"fast":true,"item":"2345-hellfest"})
- *
- * produces the query:
- *
- * GET /api?fast=true&item=2345-hellfest HTTP/1.1
- * Host: iot.bzh
- * X-Index: no
- *
- * while the same but with post not null produces:
- *
- * POST /api HTTP/1.1
- * Host: iot.bzh
- * X-Index: no
- * Content-Type: application/x-www-form-urlencoded
- *
- * fast=true&item=2345-hellfest
- *
- */
-static CURL *curl_json(const char *url, int post, struct json_object *header, struct json_object *query)
-{
- const char **args, *str;
- struct json_object_iter i;
- int idx;
- CURL *result;
-
- /* create args array */
- idx = 1 + (json_object_object_length(query) << 1);
- args = malloc((unsigned)idx * sizeof *args);
- if (!args)
- return NULL;
-
- /* fill the args array */
- args[--idx] = NULL;
- json_object_object_foreachC(query, i) {
- str = json_object_get_string(i.val);
- args[--idx] = str;
- args[--idx] = i.key;
- }
-
- /* prepare the query */
- if (post)
- result = curl_wrap_prepare_post(url, NULL, args);
- else
- result = curl_wrap_prepare_get(url, NULL, args);
- free(args);
- if(!result)
- return NULL;
-
- /* add headers */
- if (header) {
- json_object_object_foreachC(header, i) {
- str = json_object_get_string(i.val);
- if (!curl_wrap_add_header_value(result, i.key, str)) {
- curl_easy_cleanup(result);
- return NULL;
- }
- }
- }
- return result;
-}
-
-/*
- * Extract from the answer of 'curl' whose 'content' has 'size' bytes the
- * embeded JSON object (if any).
- * Returns it or returns NULL if the answer can't be interpreted.
- */
-static struct json_object *decode_perform_result(CURL *curl, const char *content, size_t size)
-{
- int i;
- const char **args;
- struct json_object *result;
-
- /* is it an url encoded answer? */
- if (curl_wrap_content_type_is(curl, "application/x-www-form-urlencoded")) {
- /* yes, unescape as an array of strings */
- args = unescape_args(content);
- if (!args)
- result = NULL;
- else {
- /* wrap the key=value pairs in an object */
- result = json_object_new_object();
- if (result) {
- for (i = 0 ; args[i] ; i += 2)
- json_object_object_add(result, args[i],
- json_object_new_string(args[i+1]));
- }
- free(args);
- }
- } else if (curl_wrap_content_type_is(curl, "application/json")) {
- /* interpret the json */
- result = json_tokener_parse (content);
- } else {
- /* by default, still try to interpret the answer as if json */
- result = json_tokener_parse (content);
- }
- return result;
-}
-
-/*
- * Treats the result of the query 'curl' of 'content' of 'size' bytes for the 'args'
- */
-static void perform_result(struct args *args, CURL *curl, const char *content, size_t size)
-{
- struct json_object *obj, *at, *tt;
- char *txt;
-
- /* get answer */
- obj = decode_perform_result(curl, content, size);
- if (!obj)
- return args_send_error(args, "unable to extract answer", content);
-
- /* process the answer */
- if (json_object_object_get_ex(obj, "access_token", &at) && json_object_object_get_ex(obj, "token_type", &tt)) {
- if (!strcmp(json_object_get_string(tt), "bearer")) {
- if (asprintf(&txt, "Bearer %s", json_object_get_string(at)) > 0) {
- json_object_object_add(obj, "authorization", json_object_new_string(txt));
- free(txt);
- }
- }
- }
-
- /* merge the answer to the token args in case of refresh */
- if (args->refresh)
- j_merge(args->args, obj);
-
- /* send the answer */
- args_send_success(args, obj);
-}
-
-/*
- * Treats the redirect answer of the query 'curl' of 'content' of 'size' bytes for the 'args'
- */
-static void perform_redirect(struct args *args, CURL *curl, const char *content, size_t size)
-{
- /* TODO: handle redirection for the normal flow */
- return args_send_error(args, "unhandled redirection", content);
-}
-
-/*
- * Handle the result of the query 'curl' of 'status'. If a data is returned, it is available in
- * 'content' of 'size' bytes.
- * When 'status' is 0, an error occured. Otherwise, 'statu' isn't zero.
- */
-static void perform_callback(void *closure, int status, CURL *curl, const char *content, size_t size)
-{
- long code;
- struct args *args = closure;
-
- /* query error ? */
- if (!status
- || curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code) != CURLE_OK)
- return args_send_error(args, "query error", NULL); /* TODO: IMPROVE? */
-
- /* get the returned code */
- switch (code) {
- case 200:
- return perform_result(args, curl, content, size);
- case 302:
- return perform_redirect(args, curl, content, size);
- case 400:
- case 401:
- return args_send_error(args, content ? : "returned code error", content ? "returned code error" : content);
- default:
- return args_send_error(args, content ? : "unexpected code error", content ? "unexpected code error" : content);
- }
-}
-
-/*
- * Main function for performing OAuth2/OpenId Connect transactions.
- * The structure 'args' is filled with the needed values:
- * Application data as json object, IDP data as json object
- * Contextual arguments for the transaction.
- * 'endpoint' must be the name of an endpoint in the context of 'args'.
- * 'operation' is the value that will get either response_type or grant_type,
- * depending on the nature of the required parameters 'mandatory'.
- * 'mandatory' designates the mandatory parameters.
- * 'optional' designate the optional parameters.
- */
-static void perform(struct args *args, const char *endpoint, const char *operation, uint32_t mandatory, uint32_t optional)
-{
- int post;
- const char *url, *type;
- CURL *curl;
-
- /* set the flags */
- args->mandatory = mandatory;
- args->all = mandatory | optional;
-
- /* get the endpoint */
- url = args_string(args, endpoint);
- if (!url)
- return args_send_error(args, "No endpoint", endpoint);
-
- /* get the operation type */
- if ((mandatory & PARAM(Response_Type)) == PARAM(Response_Type)) {
- type = "response_type";
- post = 0; /* can be 1 sometimes so not risk here */
- } else if ((mandatory & PARAM(Grant_Type)) == PARAM(Grant_Type)) {
- type = "grant_type";
- post = 1; /* must be 1 */
- } else
- return args_send_error(args, "Unexpected operation Type", NULL);
-
- json_object_object_add(args->query, type, json_object_new_string(operation));
-
- /* get the arguments */
- if (1
- && args_add(args, PARAM(Access_Token), "access_token", 1)
- && args_add(args, PARAM(Acr_Values), "acr_values", 1)
- && args_add(args, PARAM(Authorization), "authorization", 0)
- && args_add(args, PARAM(Client_Id), "client_id", 1)
- && args_add(args, PARAM(Client_Secret), "client_secret", 1)
- && args_add(args, PARAM(Code), "code", 1)
- && args_add(args, PARAM(Display), "display", 1)
- && args_add(args, PARAM(Expires_In), "expires_in", 1)
- && args_add(args, PARAM(Id_Token_Hint), "id_token_hint", 1)
- && args_add(args, PARAM(Login_Hint), "login_hint", 1)
- && args_add(args, PARAM(Max_Age), "max_age", 1)
- && args_add(args, PARAM(Nonce), "nonce", 1)
- && args_add(args, PARAM(Password), "password", 1)
- && args_add(args, PARAM(Prompt), "prompt", 1)
- && args_add(args, PARAM(Redirect_Uri), "redirect_uri", 1)
- && args_add(args, PARAM(Refresh_Token), "refresh_token", 1)
- && args_add(args, PARAM(Scope), "scope", 1)
- && args_add(args, PARAM(State), "state", 1)
- && args_add(args, PARAM(Token_Type), "token_type", 1)
- && args_add(args, PARAM(Ui_Locales), "ui_locales", 1)
- && args_add(args, PARAM(Username), "username", 1)
- ) {
- /* creates the curl query */
- curl = curl_json(url, post, args->header, args->query);
- if (!curl)
- return args_send_error(args, "out of memory", NULL);
-
- /* release data */
- args_unlock(args);
-
- /* perform the request to the server */
- curl_wrap_do(curl, perform_callback, args);
- }
-}
-
-/* perform a grant of flow Flow_Resource_Owner_Password_Credentials_Grant */
-static void grant_owner_password(struct args *args)
-{
- perform(args, string_token_endpoint, "password",
- PARAM(Grant_Type) | PARAM(Username) | PARAM(Password),
- PARAM(Scope) | PARAM(Authorization)
- );
-}
-
-/* perform a grant of flow Flow_Client_Credentials_Grant */
-static void grant_client_credentials(struct args *args)
-{
- perform(args, string_token_endpoint, "client_credentials",
- PARAM(Grant_Type),
- PARAM(Scope) | PARAM(Authorization)
- );
-}
-
-/* switches the requests depending on 'flow' */
-static void grant(struct args *args, enum oidc_grant_flow flow)
-{
- /* ensure args is valid */
- if (!args)
- return;
-
- /* process for flow */
- switch(flow) {
-
- case Flow_Resource_Owner_Password_Credentials_Grant:
- grant_owner_password(args);
- break;
-
- case Flow_Client_Credentials_Grant:
- grant_client_credentials(args);
- break;
-
- case Flow_Authorization_Code_Grant:
- case Flow_Implicit_Grant:
- case Flow_Extension_Grant:
- args_send_error(args, "Unsupported flow", NULL);
- break;
-
- case Flow_Invalid:
- default:
- args_send_error(args, "Invalid flow", NULL);
- break;
- }
-}
-
-/*
- * Initiates a grant with the given 'flow'.
- * 'appli' and 'idp' designates the appli and the idp that have been recorded.
- * when idp == NULL or idp == "", the default idp of 'appli' is used.
- * 'args' contains parameters expected in plus for the grant transaction.
- * 'cb' describes the callback actions that are called before
- * the function returns.
- */
-void oidc_grant(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb, enum oidc_grant_flow flow)
-{
- grant(mkargs(appli, idp, args, cb), flow);
-}
-
-/*
- * Like oidc_grant for flow Flow_Resource_Owner_Password_Credentials_Grant
- */
-void oidc_grant_owner_password(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb)
-{
- grant(mkargs(appli, idp, args, cb), Flow_Resource_Owner_Password_Credentials_Grant);
-}
-
-/*
- * Like oidc_grant for flow Flow_Client_Credentials_Grant
- */
-void oidc_grant_client_credentials(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb)
-{
- grant(mkargs(appli, idp, args, cb), Flow_Client_Credentials_Grant);
-}
-
-/*
- * Refreshes the 'token' for the 'appli' and the 'idp'.
- * 'cb' describes the callback actions that are called before
- * the function returns.
- */
-void oidc_token_refresh(const char *appli, const char *idp, struct json_object *token, const struct oidc_grant_cb *cb)
-{
- struct args *args;
-
- args = mkargs(appli, idp, token, cb);
- if (!args)
- return;
- args->refresh = 1;
- perform(args, string_token_endpoint, "refresh_token",
- PARAM(Grant_Type) | PARAM(Refresh_Token),
- PARAM(Scope) | PARAM(Authorization)
- );
-}
-
-/*
- * Adds the header "authorisation" with the bearer access_token of 'token'.
- * Return 1 on case of success or 0 otherwise.
- */
-int oidc_add_bearer(CURL *curl, struct json_object *token)
-{
- struct json_object *bearer;
-
- return json_object_object_get_ex(token, "authorization", &bearer)
- && curl_wrap_add_header_value(curl, "authorization", json_object_get_string(bearer));
-}
-
-
diff --git a/agl-identity-service/src/oidc-agent.h b/agl-identity-service/src/oidc-agent.h
deleted file mode 100644
index de5918d..0000000
--- a/agl-identity-service/src/oidc-agent.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-struct json_object;
-#include
-
-/***************** IDP **************************/
-
-extern int oidc_idp_set(
- const char *name,
- struct json_object *desc
- );
-
-extern int oidc_idp_exists(
- const char *name
- );
-
-extern void oidc_idp_delete(
- const char *name
- );
-
-
-/***************** APPLI **************************/
-
-extern int oidc_appli_set(
- const char *name,
- const char *idp,
- struct json_object *desc,
- int make_default
- );
-
-extern int oidc_appli_exists(
- const char *name
- );
-
-extern int oidc_appli_has_idp(
- const char *name,
- const char *idp
- );
-
-extern int oidc_appli_set_default_idp(
- const char *name,
- const char *idp
- );
-
-extern void oidc_appli_delete(
- const char *name
- );
-
-/***************** APPLI **************************/
-
-struct oidc_grant_cb
-{
- void *closure;
- void (*success)(void *closure, struct json_object *result);
- void (*error)(void *closure, const char *message, const char *indice);
-};
-
-enum oidc_grant_flow
-{
- Flow_Invalid,
- Flow_Authorization_Code_Grant,
- Flow_Implicit_Grant,
- Flow_Resource_Owner_Password_Credentials_Grant,
- Flow_Client_Credentials_Grant,
- Flow_Extension_Grant
-};
-
-
-extern void oidc_grant(
- const char *appli,
- const char *idp,
- struct json_object *args,
- const struct oidc_grant_cb *cb,
- enum oidc_grant_flow flow
- );
-
-extern void oidc_grant_owner_password(
- const char *appli,
- const char *idp,
- struct json_object *args,
- const struct oidc_grant_cb *cb
- );
-
-extern void oidc_grant_client_credentials(
- const char *appli,
- const char *idp,
- struct json_object *args,
- const struct oidc_grant_cb *cb
- );
-
-extern void oidc_token_refresh(
- const char *appli,
- const char *idp,
- struct json_object *token,
- const struct oidc_grant_cb *cb
- );
-
-extern int oidc_add_bearer(
- CURL *curl,
- struct json_object *token
- );
-
diff --git a/agl-identity-service/src/test-aia-uds-bluez.c b/agl-identity-service/src/test-aia-uds-bluez.c
deleted file mode 100644
index 4a084a5..0000000
--- a/agl-identity-service/src/test-aia-uds-bluez.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include "aia-uds-bluez.h"
-
-
-void p(const char *tag, const struct aia_uds_value *value)
-{
- printf("%10s %c %.*s\n", tag, value->changed?'*':' ', (int)value->length, value->data);
-}
-
-void onchg(const struct aia_uds *uds)
-{
- printf("\n");
- p("first name", &uds->first_name);
- p("last name", &uds->last_name);
- p("email", &uds->email);
- p("language", &uds->language);
-}
-
-int main()
-{
- sd_bus *bus;
- sd_id128_t id;
- int rc;
-
- aia_uds_set_on_change(onchg);
- rc = sd_bus_default_system(&bus);
- rc = sd_id128_randomize(&id);
- rc = sd_bus_set_server(bus, 1, id);
- rc = sd_bus_start(bus);
- rc = aia_uds_init(bus);
- rc = aia_uds_advise(1, NULL, NULL);
- for (;;) {
- rc = sd_bus_process(bus, NULL);
- if (rc < 0)
- break;
- else if (rc == 0)
- rc = sd_bus_wait(bus, (uint64_t) -1);
- }
-}
-
diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake
new file mode 100644
index 0000000..6e2aa26
--- /dev/null
+++ b/conf.d/cmake/config.cmake
@@ -0,0 +1,201 @@
+###########################################################################
+# Copyright 2015, 2016, 2017 IoT.bzh
+#
+# author: Fulup Ar Foll
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+# Project Info
+# ------------------
+set(PROJECT_NAME agl-identity-service)
+set(PROJECT_VERSION "0.1")
+set(PROJECT_PRETTY_NAME "AGL identity service")
+set(PROJECT_DESCRIPTION "AGL identity service")
+set(PROJECT_URL "https://gerrit.automotivelinux.org/gerrit/p/apps/agl-service-identity-agent.git")
+set(PROJECT_ICON "icon.png")
+set(PROJECT_AUTHOR "José Bollo")
+set(PROJECT_AUTHOR_MAIL "jose.bollo@iot.bzh")
+set(PROJECT_LICENSE "APL2.0")
+set(PROJECT_LANGUAGES,"C")
+
+# Where are stored default templates files from submodule or subtree app-templates in your project tree
+# relative to the root project directory
+set(PROJECT_APP_TEMPLATES_DIR "conf.d/app-templates")
+
+# Where are stored your external libraries for your project. This is 3rd party library that you don't maintain
+# but used and must be built and linked.
+# set(PROJECT_LIBDIR "libs")
+
+# Where are stored data for your application. Pictures, static resources must be placed in that folder.
+# set(PROJECT_RESOURCES "data")
+
+# Which directories inspect to find CMakeLists.txt target files
+# set(PROJECT_SRC_DIR_PATTERN "*")
+
+# Compilation Mode (DEBUG, RELEASE)
+# ----------------------------------
+set(USE_EFENCE 0)
+
+# Kernel selection if needed. You can choose between a
+# mandatory version to impose a minimal version.
+# Or check Kernel minimal version and just print a Warning
+# about missing features and define a preprocessor variable
+# to be used as preprocessor condition in code to disable
+# incompatibles features. Preprocessor define is named
+# KERNEL_MINIMAL_VERSION_OK.
+#
+# NOTE*** FOR NOW IT CHECKS KERNEL Yocto environment and
+# Yocto SDK Kernel version.
+# -----------------------------------------------
+#set (kernel_mandatory_version 4.8)
+#set (kernel_minimal_version 4.8)
+
+# Compiler selection if needed. Impose a minimal version.
+# -----------------------------------------------
+set (gcc_minimal_version 4.9)
+
+# PKG_CONFIG required packages
+# -----------------------------
+set (PKG_REQUIRED_LIST
+ json-c
+ afb-daemon
+)
+
+# Prefix path where will be installed the files
+# Default: /usr/local (need root permission to write in)
+# ------------------------------------------------------
+#set(CMAKE_INSTALL_PREFIX $ENV{HOME}/opt)
+
+# Customize link option
+# -----------------------------
+#list(APPEND link_libraries -an-option)
+
+# Compilation options definition
+# Use CMake generator expressions to specify only for a specific language
+# Values are prefilled with default options that is currently used.
+# Either separate options with ";", or each options must be quoted separately
+# DO NOT PUT ALL OPTION QUOTED AT ONCE , COMPILATION COULD FAILED !
+# ----------------------------------------------------------------------------
+#set(COMPILE_OPTIONS
+# -Wall
+# -Wextra
+# -Wconversion
+# -Wno-unused-parameter
+# -Wno-sign-compare
+# -Wno-sign-conversion
+# -Werror=maybe-uninitialized
+# -Werror=implicit-function-declaration
+# -ffunction-sections
+# -fdata-sections
+# -fPIC
+# CACHE STRING "Compilation flags")
+#set(C_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C language.")
+#set(CXX_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C++ language.")
+#set(PROFILING_COMPILE_OPTIONS
+# -g
+# -O0
+# -pg
+# -Wp,-U_FORTIFY_SOURCE
+# CACHE STRING "Compilation flags for PROFILING build type.")
+#set(DEBUG_COMPILE_OPTIONS
+# -g
+# -ggdb
+# -Wp,-U_FORTIFY_SOURCE
+# CACHE STRING "Compilation flags for DEBUG build type.")
+#set(CCOV_COMPILE_OPTIONS
+# -g
+# -O2
+# --coverage
+# CACHE STRING "Compilation flags for CCOV build type.")
+#set(RELEASE_COMPILE_OPTIONS
+# -g
+# -O2
+# CACHE STRING "Compilation flags for RELEASE build type.")
+
+# (BUG!!!) as PKG_CONFIG_PATH does not work [should be an env variable]
+# ---------------------------------------------------------------------
+set(CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}/lib64/pkgconfig ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
+set(LD_LIBRARY_PATH ${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib)
+
+# Optional location for config.xml.in
+# -----------------------------------
+#set(WIDGET_ICON conf.d/wgt/${PROJECT_ICON} CACHE PATH "Path to the widget icon")
+set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in CACHE PATH "Path to widget config file template (config.xml.in)")
+
+# Mandatory widget Mimetype specification of the main unit
+# --------------------------------------------------------------------------
+# Choose between :
+#- text/html : HTML application,
+# content.src designates the home page of the application
+#
+#- application/vnd.agl.native : AGL compatible native,
+# content.src designates the relative path of the binary.
+#
+# - application/vnd.agl.service: AGL service, content.src is not used.
+#
+#- ***application/x-executable***: Native application,
+# content.src designates the relative path of the binary.
+# For such application, only security setup is made.
+#
+set(WIDGET_TYPE application/vnd.agl.service)
+
+# Mandatory Widget entry point file of the main unit
+# --------------------------------------------------------------
+# This is the file that will be executed, loaded,
+# at launch time by the application framework.
+#
+set(WIDGET_ENTRY_POINT config.xml)
+
+# Optional dependencies order
+# ---------------------------
+#set(EXTRA_DEPENDENCIES_ORDER)
+
+# Optional Extra global include path
+# -----------------------------------
+#set(EXTRA_INCLUDE_DIRS)
+
+# Optional extra libraries
+# -------------------------
+#set(EXTRA_LINK_LIBRARIES)
+
+# Optional force binding Linking flag
+# ------------------------------------
+# set(BINDINGS_LINK_FLAG LinkOptions )
+
+# Optional force package prefix generation, like widget
+# -----------------------------------------------------
+# set(PKG_PREFIX DestinationPath)
+
+# Optional Application Framework security token
+# and port use for remote debugging.
+#------------------------------------------------------------
+set(AFB_TOKEN "" CACHE PATH "Default binder security token")
+set(AFB_REMPORT "1234" CACHE PATH "Default binder listening port")
+
+# Print a helper message when every thing is finished
+# ----------------------------------------------------
+set(CLOSING_MESSAGE "Typical binding launch: afb-daemon --port=${AFB_REMPORT} --workdir=${CMAKE_BINARY_DIR}/package --ldpaths=lib --roothttp=htdocs --token=\"${AFB_TOKEN}\" --tracereq=common --verbose")
+set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt")
+
+# Optional schema validator about now only XML, LUA and JSON
+# are supported
+#------------------------------------------------------------
+#set(LUA_CHECKER "luac" "-p" CACHE STRING "LUA compiler")
+#set(XML_CHECKER "xmllint" CACHE STRING "XML linter")
+#set(JSON_CHECKER "json_verify" CACHE STRING "JSON linter")
+
+# This include is mandatory and MUST happens at the end
+# of this file, else you expose you to unexpected behavior
+# -----------------------------------------------------------
+include(${PROJECT_APP_TEMPLATES_DIR}/cmake/common.cmake)
diff --git a/conf.d/wgt/config.xml.in b/conf.d/wgt/config.xml.in
new file mode 100644
index 0000000..cd66c2b
--- /dev/null
+++ b/conf.d/wgt/config.xml.in
@@ -0,0 +1,21 @@
+
+
+ @PROJECT_NAME@
+
+
+ @PROJECT_DESCRIPTION@
+ @PROJECT_AUTHOR@ <@PROJECT_AUTHOR_MAIL@>
+ @PROJECT_LICENSE@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/etc/config.json b/etc/config.json
new file mode 100644
index 0000000..c69e5be
--- /dev/null
+++ b/etc/config.json
@@ -0,0 +1,23 @@
+{
+ "endpoint": "https://agl-graphapi.forgerocklabs.org:443/getuserprofilefromtoken",
+ "vin": "WVGGF7BP7HD005986",
+ "autoadvise": true,
+ "delay": 5,
+ "idp": {
+ "authorization_endpoint": "",
+ "token_endpoint": "https://agl-am.forgerocklabs.org:8043/openam/oauth2/stateless/access_token"
+ }/*,
+ "appli": {
+ "authorization": "Basic c3RhdGVsZXNzOnBhc3N3b3JkMg==",
+ "username": "bjensen",
+ "password": "Passw0rd",
+ "scope": "openid profile email cn sn givenName ou mail postalAddress departmentNumber physicalDeliveryOfficeName facsimileTelephoneNumber"
+ }
+*/
+}
+/*
+ "endpoint": "https://frdemo-graphapi.forgerocklabs.org/getuserprofilefromtoken",
+ "vin": "JTEBU4BF6EK189816",
+ "delay": 10
+*/
+
diff --git a/htdocs/identity/AFB-websock.js b/htdocs/identity/AFB-websock.js
new file mode 100644
index 0000000..08a7ffe
--- /dev/null
+++ b/htdocs/identity/AFB-websock.js
@@ -0,0 +1,174 @@
+AFB = function(base, initialtoken){
+
+var urlws = "ws://"+window.location.host+"/"+base;
+var urlhttp = "http://"+window.location.host+"/"+base;
+
+/*********************************************/
+/**** ****/
+/**** AFB_context ****/
+/**** ****/
+/*********************************************/
+var AFB_context;
+{
+ var UUID = undefined;
+ var TOKEN = initialtoken;
+
+ var context = function(token, uuid) {
+ this.token = token;
+ this.uuid = uuid;
+ }
+
+ context.prototype = {
+ get token() {return TOKEN;},
+ set token(tok) {if(tok) TOKEN=tok;},
+ get uuid() {return UUID;},
+ set uuid(id) {if(id) UUID=id;}
+ };
+
+ AFB_context = new context();
+}
+/*********************************************/
+/**** ****/
+/**** AFB_websocket ****/
+/**** ****/
+/*********************************************/
+var AFB_websocket;
+{
+ var CALL = 2;
+ var RETOK = 3;
+ var RETERR = 4;
+ var EVENT = 5;
+
+ var PROTO1 = "x-afb-ws-json1";
+
+ AFB_websocket = function(onopen, onabort) {
+ var u = urlws;
+ if (AFB_context.token) {
+ u = u + '?x-afb-token=' + AFB_context.token;
+ if (AFB_context.uuid)
+ u = u + '&x-afb-uuid=' + AFB_context.uuid;
+ }
+ this.ws = new WebSocket(u, [ PROTO1 ]);
+ this.pendings = {};
+ this.awaitens = {};
+ this.counter = 0;
+ this.ws.onopen = onopen.bind(this);
+ this.ws.onerror = onerror.bind(this);
+ this.ws.onclose = onclose.bind(this);
+ this.ws.onmessage = onmessage.bind(this);
+ this.onopen = onopen;
+ this.onabort = onabort;
+ this.onclose = onabort;
+ }
+
+ function onerror(event) {
+ var f = this.onabort;
+ if (f) {
+ delete this.onopen;
+ delete this.onabort;
+ f && f(this);
+ }
+ this.onerror && this.onerror(this);
+ }
+
+ function onopen(event) {
+ var f = this.onopen;
+ delete this.onopen;
+ delete this.onabort;
+ f && f(this);
+ }
+
+ function onclose(event) {
+ for (var id in this.pendings) {
+ var ferr = this.pendings[id].onerror;
+ ferr && ferr(null, this);
+ }
+ this.pendings = {};
+ this.onclose && this.onclose();
+ }
+
+ function fire(awaitens, name, data) {
+ var a = awaitens[name];
+ if (a)
+ a.forEach(function(handler){handler(data);});
+ var i = name.indexOf("/");
+ if (i >= 0) {
+ a = awaitens[name.substring(0,i)];
+ if (a)
+ a.forEach(function(handler){handler(data);});
+ }
+ a = awaitens["*"];
+ if (a)
+ a.forEach(function(handler){handler(data);});
+ }
+
+ function reply(pendings, id, ans, offset) {
+ if (id in pendings) {
+ var p = pendings[id];
+ delete pendings[id];
+ var f = p[offset];
+ f(ans);
+ }
+ }
+
+ function onmessage(event) {
+ var obj = JSON.parse(event.data);
+ var code = obj[0];
+ var id = obj[1];
+ var ans = obj[2];
+ AFB_context.token = obj[3];
+ switch (code) {
+ case RETOK:
+ reply(this.pendings, id, ans, 0);
+ break;
+ case RETERR:
+ reply(this.pendings, id, ans, 1);
+ break;
+ case EVENT:
+ default:
+ fire(this.awaitens, id, ans);
+ break;
+ }
+ }
+
+ function close() {
+ this.ws.close();
+ this.onabort();
+ }
+
+ function call(method, request) {
+ return new Promise((function(resolve, reject){
+ var id, arr;
+ do {
+ id = String(this.counter = 4095 & (this.counter + 1));
+ } while (id in this.pendings);
+ this.pendings[id] = [ resolve, reject ];
+ arr = [CALL, id, method, request ];
+ if (AFB_context.token) arr.push(AFB_context.token);
+ this.ws.send(JSON.stringify(arr));
+ }).bind(this));
+ }
+
+ function onevent(name, handler) {
+ var id = name;
+ var list = this.awaitens[id] || (this.awaitens[id] = []);
+ list.push(handler);
+ }
+
+ AFB_websocket.prototype = {
+ close: close,
+ call: call,
+ onevent: onevent
+ };
+}
+/*********************************************/
+/**** ****/
+/**** ****/
+/**** ****/
+/*********************************************/
+return {
+ context: AFB_context,
+ ws: AFB_websocket
+};
+};
+
diff --git a/htdocs/identity/binding-debug.css b/htdocs/identity/binding-debug.css
new file mode 100644
index 0000000..f41c940
--- /dev/null
+++ b/htdocs/identity/binding-debug.css
@@ -0,0 +1,61 @@
+#debug-panel {
+ float: right;
+}
+
+#debug-panel.collapsed {
+ background-color: transparent;
+ overflow-x: hidden;
+}
+
+#debug-panel.expanded {
+ background-color: lightyellow;
+ max-width: 25%;
+ overflow-x: scroll;
+}
+
+#debug-panel.collapsed > #debug-panel-collapse {
+ display: none;
+}
+
+#debug-panel.expanded > #debug-panel-collapse {
+ display: block;
+}
+
+#debug-panel.collapsed > #debug-panel-expand {
+ display: block;
+}
+
+#debug-panel.expanded > #debug-panel-expand {
+ display: none;
+}
+
+#debug-panel.expanded > #debug-panel-content {
+ display: block;
+}
+
+#debug-panel.collapsed > #debug-panel-content {
+ display: none;
+}
+
+.json-key {
+ color: cornflowerblue;
+ font-weight: bold;
+}
+
+.json-string {
+ color: crimson;
+}
+
+.json-number {
+ color: sandybrown;
+}
+
+.json-boolean {
+ color: fuchsia;
+ font-weight: bold;
+}
+
+.json-null {
+ color: black;
+ font-weight: bold;
+}
diff --git a/htdocs/identity/identity-binding.js b/htdocs/identity/identity-binding.js
new file mode 100644
index 0000000..55dbb96
--- /dev/null
+++ b/htdocs/identity/identity-binding.js
@@ -0,0 +1,158 @@
+var afb = new AFB("api", "HELLO");
+var ws;
+
+function add_debbug_panel() {
+
+ if (document.getElementById("debug-panel"))
+ return;
+
+ var itm = document.getElementById("debug-panel-container");
+ if (itm)
+ {
+ var pnl =
+ "\n" +
+ "
\n" +
+ "
\n" +
+ "
\n" +
+ "
Debug
\n" +
+ "
Call
\n" +
+ "
\n" +
+ " - api :
\n" +
+ " - verb :
\n" +
+ " - query :
\n" +
+ "
\n" +
+ "
\n" +
+ "
\n" +
+ "
Response
\n" +
+ "
Event
\n" +
+ "
\n" +
+ "
\n";
+ itm.insertAdjacentHTML("afterbegin", pnl);
+ }
+}
+
+function createClass(name,rules) {
+ var style = document.createElement('style');
+ style.type = 'text/css';
+ document.getElementsByTagName('head')[0].appendChild(style);
+ if(!(style.sheet||{}).insertRule)
+ (style.styleSheet || style.sheet).addRule(name, rules);
+ else
+ style.sheet.insertRule(name+"{"+rules+"}",0);
+}
+
+function syntaxHighlight(json) {
+ if (typeof json != 'string')
+ json = JSON.stringify(json, undefined, 2);
+
+ json = json.replace(/&/g, '&').replace(//g, '>');
+ return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
+ var cls = 'json-number';
+ if (/^"/.test(match)) {
+ if (/:$/.test(match)) {
+ cls = 'json-key';
+ } else {
+ cls = 'json-string';
+ }
+ } else if (/true|false/.test(match)) {
+ cls = 'json-boolean';
+ } else if (/null/.test(match)) {
+ cls = 'json-null';
+ }
+ return '' + match + '';
+ });
+}
+
+function set_item_html(id, text)
+{
+ var itm = document.getElementById(id);
+ if (itm) itm.innerHTML = text;
+}
+
+function set_item_text(id, text)
+{
+ var itm = document.getElementById(id);
+ if (itm) itm.innerText = text;
+}
+
+function debug_panel_collapse() {
+ var pnl = document.getElementById('debug-panel');
+ if (pnl)
+ {
+ pnl.classList.remove('expanded');
+ pnl.classList.add('collapsed');
+ }
+}
+
+function debug_panel_expand() {
+ var pnl = document.getElementById('debug-panel');
+ if (pnl)
+ {
+ pnl.classList.remove('collapsed');
+ pnl.classList.add('expanded');
+ }
+}
+
+function init() {
+ add_debbug_panel();
+ ws = new afb.ws(onopen, onabort);
+}
+
+function onopen() {
+ //callbinder("ll-auth", "getuser", "");
+ ws.onevent("*", gotevent);
+}
+
+function onabort() {
+}
+
+function replyok(obj) {
+ console.log("replyok:" + JSON.stringify(obj));
+ set_item_html("debug-panel-response", syntaxHighlight(JSON.stringify(obj, null, 4)));
+}
+
+function replyerr(obj) {
+ console.log("replyerr:" + JSON.stringify(obj));
+ set_item_html("debug-panel-response", syntaxHighlight(JSON.stringify(obj, null, 4)));
+}
+
+function gotevent(obj) {
+ console.log("gotevent:" + JSON.stringify(obj));
+ set_item_html("debug-panel-event", syntaxHighlight(JSON.stringify(obj, null, 4)));
+}
+
+function callbinder(api, verb, query) {
+ console.log ("subscribe api="+api+" verb="+verb+" query=" +query);
+
+ set_item_text("debug-panel-call-api", api);
+ set_item_text("debug-panel-call-verb", verb);
+ set_item_html("debug-panel-call-query", syntaxHighlight(JSON.stringify(query, null, 4)));
+
+ ws.call(api+"/"+verb, query).then(replyok, replyerr);
+}
+
+function subscribe() {
+ callbinder("identity", "subscribe", {});
+}
+
+function getIdentity() {
+ callbinder("identity", "get", {});
+}
+
+function logout() {
+ callbinder("identity", "logout", {});
+}
+
+function fakeAuth() {
+
+ var e = document.getElementById("fake-auth-kind");
+ var arg = {
+ "kind": e.options[e.selectedIndex].value,
+ "key": (document.getElementById("fake-auth-key").value === "custom" ? document.getElementById("fake-auth-key-custom").value : document.getElementById("fake-auth-key").value)
+ }
+ callbinder("identity", "fake-auth", arg);
+}
+
+function updateNfcUi() {
+ document.getElementById('fake-auth-key-custom').disabled = !(document.getElementById("fake-auth-key").value === "custom");
+}
diff --git a/htdocs/identity/index.html b/htdocs/identity/index.html
new file mode 100644
index 0000000..bbeee51
--- /dev/null
+++ b/htdocs/identity/index.html
@@ -0,0 +1,41 @@
+
+
+
+ agl-service-identity
+
+
+
+
+
+
+
+
+ agl-service-identity
+
+
+
+
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..e4a744b
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,49 @@
+###########################################################################
+# Copyright 2016, 2017 IoT.bzh
+#
+# author: José Bollo
+# author: Stéphane Desneux
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+PROJECT_TARGET_ADD(afb-identity-binding)
+
+add_library(afb-identity-binding MODULE
+ agl-identity-binding.c
+ agl-forgerock.c
+ aia-get.c
+ authorization.c
+ base64.c
+ curl-wrap.c
+ escape.c
+ oidc-agent.c
+)
+
+pkg_check_modules(EXTRAS REQUIRED libcurl)
+
+set_target_properties(afb-identity-binding PROPERTIES
+ LABELS "BINDING"
+ PREFIX ""
+ COMPILE_FLAGS "${EXTRAS_CFLAGS} -DFOR_AFB_BINDING"
+ LINK_FLAGS "${BINDINGS_LINK_FLAG}"
+ LINK_LIBRARIES "${EXTRAS_LIBRARIES}"
+ OUTPUT_NAME "${TARGET_NAME}"
+)
+
+add_custom_command(TARGET ${TARGET_NAME}
+PRE_BUILD
+COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/../package/htdocs
+COMMAND cp -rv ${CMAKE_CURRENT_SOURCE_DIR}/../htdocs ${CMAKE_CURRENT_BINARY_DIR}/../package/
+COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/../package/etc
+COMMAND cp -rv ${CMAKE_CURRENT_SOURCE_DIR}/../etc ${CMAKE_CURRENT_BINARY_DIR}/../package/)
diff --git a/src/agl-forgerock.c b/src/agl-forgerock.c
new file mode 100644
index 0000000..97cc4b9
--- /dev/null
+++ b/src/agl-forgerock.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+
+#include
+#include
+
+#include
+
+#define AFB_BINDING_VERSION 2
+#include
+
+#include "oidc-agent.h"
+#include "aia-get.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+static int expiration_delay = 5;
+
+static const char default_endpoint[] = "https://agl-graphapi.forgerocklabs.org/getuserprofilefromtoken";
+static const char *oidc_name;
+
+static char *endpoint;
+
+static void (*onloaded)(struct json_object *data, const char *error);
+
+/***** configuration ********************************************/
+
+static void confsetstr(struct json_object *conf, const char *name, char **value, const char *def)
+{
+ struct json_object *v;
+ const char *s;
+ char *p;
+
+ s = conf && json_object_object_get_ex(conf, name, &v) ? json_object_get_string(v) : def;
+ p = *value;
+ if (s && p != s) {
+ *value = strdup(s);
+ free(p);
+ }
+}
+
+static void confsetint(struct json_object *conf, const char *name, int *value, int def)
+{
+ struct json_object *v;
+
+ *value = conf && json_object_object_get_ex(conf, name, &v) ? json_object_get_int(v) : def;
+}
+
+static void confsetoidc(struct json_object *conf, const char *name)
+{
+ struct json_object *idp, *appli;
+
+ if (conf
+ && json_object_object_get_ex(conf, "idp", &idp)
+ && json_object_object_get_ex(conf, "appli", &appli)) {
+ if (oidc_idp_set(name, idp) && oidc_appli_set(name, name, appli, 1)) {
+ oidc_name = name;
+ }
+ }
+}
+
+/****************************************************************/
+
+static void loaded(struct json_object *data, const char *error)
+{
+ if (onloaded)
+ onloaded(data, error);
+}
+
+static void downloaded(void *closure, int status, const void *buffer, size_t size)
+{
+ struct json_object *object, *subobj;
+ struct json_object *objkey = closure;
+ struct json_object *tmp;
+
+ json_object_object_get_ex(objkey, "url", &tmp);
+ const char *url = json_object_get_string(tmp);
+
+ /* checks whether discarded */
+ if (status == 0 && !buffer) {
+ AFB_ERROR("discarded");
+ loaded(NULL, "discarded");
+ goto end; /* discarded */
+ }
+
+ /* scan for the status */
+ if (status == 0 || !buffer) {
+ AFB_ERROR("uploading %s failed %s", url ? : "?", (const char*)buffer ? : "");
+ loaded(NULL, "failed");
+ goto end;
+ }
+
+ /* get the object */
+ AFB_DEBUG("received data: %.*s", (int)size, (char*)buffer);
+ object = json_tokener_parse(buffer); /* okay because 0 appended */
+
+ /* extract useful part */
+ subobj = NULL;
+ if (object && !json_object_object_get_ex(object, "results", &subobj))
+ subobj = NULL;
+ if (subobj)
+ subobj = json_object_array_get_idx(subobj, 0);
+ if (subobj && !json_object_object_get_ex(subobj, "data", &subobj))
+ subobj = NULL;
+ if (subobj)
+ subobj = json_object_array_get_idx(subobj, 0);
+ if (subobj && !json_object_object_get_ex(subobj, "row", &subobj))
+ subobj = NULL;
+ if (subobj)
+ subobj = json_object_array_get_idx(subobj, 0);
+
+ /* is it a recognized user ? */
+ if (!subobj) {
+ /* not recognized!! */
+ AFB_INFO("unrecognized key for %s", url ? : "?");
+ json_object_put(object);
+ loaded(NULL, "malformed");
+ goto end;
+ }
+
+ // Save the profile to the database
+ struct json_object* dbr;
+ struct json_object* record = json_object_new_object();
+ json_object_object_add(record, "key", objkey);
+ json_object_object_add(record, "value", json_object_get(subobj));
+ afb_service_call_sync("persistence", "update", record, &dbr);
+
+ loaded(subobj, NULL);
+ json_object_put(object);
+end:
+ json_object_put(objkey);
+}
+
+/** public **************************************************************/
+
+void agl_forgerock_setconfig(struct json_object *conf)
+{
+ confsetstr(conf, "endpoint", &endpoint, endpoint ? : default_endpoint);
+ confsetint(conf, "delay", &expiration_delay, expiration_delay);
+ confsetoidc(conf, "oidc-aia");
+ AFB_NOTICE("Forgerock endpoint is: %s", endpoint);
+}
+
+void agl_forgerock_setcb(void (*callback)(struct json_object *data, const char *error))
+{
+ onloaded = callback;
+}
+
+void reply_from_db(void* closure, int status, struct json_object* result)
+{
+ if (status)
+ {
+ AFB_WARNING("Failed to retrieve profile from persistence!");
+ return;
+ }
+
+ struct json_object* tmp;
+ json_object_object_get_ex(result, "response", &tmp);
+ json_object_object_get_ex(tmp, "value", &tmp);
+ AFB_NOTICE("User profile retrieved from persistence: %s", json_object_to_json_string(tmp));
+ loaded(json_object_get(tmp), NULL);
+}
+
+void agl_forgerock_download_request(const char *vin, const char *kind, const char *key)
+{
+ int rc;
+ char *url;
+
+ rc = asprintf(&url, "%s?vin=%s&kind=%s&keytoken=%s", endpoint, vin, kind, key);
+ if (rc >= 0)
+ {
+ struct json_object* obj = json_object_new_object();
+ json_object_object_add(obj, "url", json_object_new_string(url));
+ json_object_object_add(obj, "vin", json_object_new_string(vin));
+ json_object_object_add(obj, "kind", json_object_new_string(kind));
+ json_object_object_add(obj, "key", json_object_new_string(key));
+
+ // Async get from database and from forgerock
+ struct json_object* key = json_object_new_object();
+ json_object_object_add(key, "key", json_object_get(obj));
+ afb_service_call("persistence", "read", key, reply_from_db, NULL);
+
+ // Async get from forgerock
+ aia_get(url, expiration_delay, oidc_name, oidc_name, downloaded, obj);
+ free(url);
+ }
+ else
+ AFB_ERROR("out of memory");
+}
+
+/* vim: set colorcolumn=80: */
+
diff --git a/src/agl-forgerock.h b/src/agl-forgerock.h
new file mode 100644
index 0000000..1aee680
--- /dev/null
+++ b/src/agl-forgerock.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+struct json_object;
+
+extern void agl_forgerock_setconfig(struct json_object *conf);
+extern void agl_forgerock_setcb(void (*callback)(struct json_object *data, const char *error));
+extern void agl_forgerock_download_request(const char *vin, const char *kind, const char *key);
diff --git a/src/agl-identity-binding.c b/src/agl-identity-binding.c
new file mode 100644
index 0000000..12f43bd
--- /dev/null
+++ b/src/agl-identity-binding.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#define AFB_BINDING_VERSION 2
+#include
+
+#include "agl-forgerock.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+static struct afb_event event;
+
+static struct json_object *current_identity;
+
+static const char default_vin[] = "4T1BF1FK5GU260429";
+static char *vin;
+
+/***** configuration ********************************************/
+
+static struct json_object *readjson(int fd)
+{
+ char *buffer;
+ struct stat s;
+ struct json_object *result = NULL;
+ int rc;
+
+ rc = fstat(fd, &s);
+ if (rc == 0 && S_ISREG(s.st_mode)) {
+ buffer = alloca((size_t)(s.st_size)+1);
+ if (read(fd, buffer, (size_t)s.st_size) == (ssize_t)s.st_size) {
+ buffer[s.st_size] = 0;
+ //AFB_NOTICE("Config file: %s", buffer);
+ result = json_tokener_parse(buffer);
+ //if (!result)
+ //{
+ // AFB_ERROR("Config file is not a valid JSON: %s", json_tokener_error_desc(json_tokener_get_error(NULL)));
+ //}
+ }
+ }
+ close(fd);
+
+ return result;
+}
+
+static struct json_object *get_global_config(const char *name, const char *locale)
+{
+ int fd = afb_daemon_rootdir_open_locale(name, O_RDONLY, locale);
+ if (fd < 0) AFB_ERROR("Config file not found: %s", name);
+ return fd < 0 ? NULL : readjson(fd);
+}
+
+static struct json_object *get_local_config(const char *name)
+{
+ int fd = openat(AT_FDCWD, name, O_RDONLY, 0);
+ return fd < 0 ? NULL : readjson(fd);
+}
+
+static void confsetstr(struct json_object *conf, const char *name, char **value, const char *def)
+{
+ struct json_object *v;
+ const char *s;
+ char *p;
+
+ s = conf && json_object_object_get_ex(conf, name, &v) ? json_object_get_string(v) : def;
+ p = *value;
+ if (s && p != s) {
+ *value = strdup(s);
+ free(p);
+ }
+}
+
+static void setconfig(struct json_object *conf)
+{
+ if (conf) {
+ confsetstr(conf, "vin", &vin, vin ? : default_vin);
+ agl_forgerock_setconfig(conf);
+ }
+}
+
+static void readconfig()
+{
+ setconfig(get_global_config("etc/config.json", NULL));
+ setconfig(get_local_config("/etc/agl/identity-agent-config.json"));
+ setconfig(get_local_config("config.json"));
+}
+
+/****************************************************************/
+
+static struct json_object *make_event_object(const char *name, const char *id, const char *nick)
+{
+ struct json_object *object = json_object_new_object();
+
+ /* TODO: errors */
+ json_object_object_add(object, "eventName", json_object_new_string(name));
+ json_object_object_add(object, "accountid", json_object_new_string(id));
+ if (nick)
+ json_object_object_add(object, "nickname", json_object_new_string(nick));
+ return object;
+}
+
+static int send_event_object(const char *name, const char *id, const char *nick)
+{
+ return afb_event_push(event, make_event_object(name, id, nick));
+}
+
+static void do_login(struct json_object *desc)
+{
+ if (current_identity == NULL && desc == NULL) return; // Switching from NULL to NULL -> do nothing
+ if (current_identity && desc)
+ {
+ const char* a = json_object_to_json_string(current_identity);
+ const char* b = json_object_to_json_string(desc);
+ if (strcmp(a, b) == 0)
+ {
+ AFB_NOTICE("Reloging of the same user.");
+ return; // Switching from one user to the same user -> do nothing
+ }
+ }
+
+ struct json_object *object;
+
+ /* switching the user */
+ AFB_INFO("Switching to user %s", desc ? json_object_to_json_string(desc) : "null");
+ object = current_identity;
+ current_identity = json_object_get(desc);
+ json_object_put(object);
+
+ if (!json_object_object_get_ex(desc, "name", &object))
+ object = 0;
+ send_event_object("login", !object ? "null" : json_object_get_string(object)? : "?", 0);
+}
+
+static void do_logout()
+{
+ struct json_object *object;
+
+ AFB_INFO("Switching to no user");
+ object = current_identity;
+ current_identity = 0;
+ json_object_put(object);
+
+ send_event_object("logout", "null", 0);
+}
+
+static void on_forgerock_data(struct json_object *data, const char *error)
+{
+ if (error) {
+ AFB_ERROR("Can't get data: %s", error);
+ } else {
+ do_login(data);
+ }
+}
+
+/****************************************************************/
+
+static void subscribe (struct afb_req request)
+{
+ int rc;
+
+ rc = afb_req_subscribe(request, event);
+ if (rc < 0)
+ afb_req_fail(request, "failed", "subscribtion failed");
+ else
+ afb_req_success(request, NULL, NULL);
+}
+
+static void unsubscribe (struct afb_req request)
+{
+ afb_req_unsubscribe(request, event);
+ afb_req_success(request, NULL, NULL);
+}
+
+static void logout (struct afb_req request)
+{
+ do_logout();
+ afb_req_success(request, NULL, NULL);
+}
+
+static void fake_login (struct afb_req request)
+{
+ struct json_object *desc = afb_req_json(request);
+ do_logout();
+ if (desc)
+ do_login(desc);
+ afb_req_success(request, NULL, NULL);
+}
+
+static void get (struct afb_req request)
+{
+ afb_req_success(request, json_object_get(current_identity), NULL);
+}
+
+static void on_nfc_subscribed(void *closure, int status, struct json_object *result)
+{
+ if(status)
+ AFB_ERROR("Failed to subscribe to nfc events.");
+}
+
+static void on_nfc_started(void *closure, int status, struct json_object *result)
+{
+ if (!status) {
+ afb_service_call("nfc", "subscribe", NULL, on_nfc_subscribed, NULL);
+ }
+ else
+ AFB_ERROR("Failed to start nfc polling.");
+}
+
+static int service_init()
+{
+ agl_forgerock_setcb(on_forgerock_data);
+ event = afb_daemon_make_event("event");
+ if (!afb_event_is_valid(event))
+ return -1;
+
+ readconfig();
+
+ if (afb_daemon_require_api("nfc", 1))
+ return -1;
+
+ if (afb_daemon_require_api("persistence", 1))
+ return -1;
+
+ afb_service_call("nfc", "start", NULL, on_nfc_started, NULL);
+
+ return 0;
+}
+
+static void on_nfc_target_add(struct json_object *object)
+{
+ struct json_object * json_uid;
+ const char *uid;
+
+ if (json_object_object_get_ex(object, "UID", &json_uid))
+ {
+ uid = json_object_get_string(json_uid);
+ AFB_NOTICE("nfc tag detected, call forgerock with vincode=%s and key=%s", vin ? vin : default_vin, uid);
+ send_event_object("incoming", uid, uid);
+ agl_forgerock_download_request(vin ? vin : default_vin, "nfc", uid);
+ }
+ else AFB_ERROR("nfc target add event is received but no UID found: %s", json_object_to_json_string(object));
+}
+
+static void onevent(const char *event, struct json_object *object)
+{
+ AFB_NOTICE("Received event: %s", event);
+ if (!strcmp("nfc/on-nfc-target-add", event))
+ {
+ on_nfc_target_add(object);
+ return;
+ }
+ AFB_WARNING("Unhandled event: %s", event);
+}
+
+static void fake_auth(struct afb_req req)
+{
+ struct json_object* req_object;
+ struct json_object* kind_object;
+ struct json_object* key_object;
+
+ req_object = afb_req_json(req);
+
+ if (!json_object_object_get_ex(req_object, "kind", &kind_object))
+ {
+ afb_req_fail(req, "Missing arg: kind", NULL);
+ return;
+ }
+
+ if (!json_object_object_get_ex(req_object, "key", &key_object))
+ {
+ afb_req_fail(req, "Missing arg: key", NULL);
+ return;
+ }
+
+ const char* kind = json_object_get_string(kind_object);
+ const char* key = json_object_get_string(key_object);
+
+ send_event_object("incoming", key, key);
+ agl_forgerock_download_request(vin ? vin : default_vin, kind, key);
+
+ afb_req_success(req, NULL, "fake auth success!");
+}
+
+// NOTE: this sample does not use session to keep test a basic as possible
+// in real application most APIs should be protected with AFB_SESSION_CHECK
+static const struct afb_verb_v2 verbs[]=
+{
+ {"subscribe" , subscribe , NULL, "subscribe to events" , AFB_SESSION_NONE },
+ {"unsubscribe", unsubscribe , NULL, "unsubscribe to events" , AFB_SESSION_NONE },
+ {"fake-login" , fake_login , NULL, "fake a login" , AFB_SESSION_NONE },
+ {"logout" , logout , NULL, "log the current user out", AFB_SESSION_NONE },
+ {"get" , get , NULL, "get data" , AFB_SESSION_NONE },
+ {"fake-auth" , fake_auth , NULL, "fake an authentication" , AFB_SESSION_NONE },
+ {NULL}
+};
+
+const struct afb_binding_v2 afbBindingV2 =
+{
+ .api = "identity",
+ .specification = NULL,
+ .info = "AGL identity service",
+ .verbs = verbs,
+ .preinit = NULL,
+ .init = service_init,
+ .onevent = onevent,
+ .noconcurrency = 0
+};
+
+/* vim: set colorcolumn=80: */
diff --git a/src/aia-get.c b/src/aia-get.c
new file mode 100644
index 0000000..56c82b0
--- /dev/null
+++ b/src/aia-get.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "curl-wrap.h"
+#include "oidc-agent.h"
+
+/*
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+
+#include "u2f-bluez.h"
+*/
+
+
+struct keyrequest {
+ struct keyrequest *next;
+ int dead;
+ time_t expiration;
+ const char *url;
+ const char *appli;
+ const char *idp;
+ void (*callback)(void *closure, int status, const void *buffer, size_t size);
+ void *closure;
+ json_object *token;
+ pthread_t tid;
+};
+
+static struct keyrequest *keyrequests = 0;
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int curl_initialized = 0;
+
+static void perform_query_callback(void *closure, int status, CURL *curl, const char *result, size_t size)
+{
+ struct keyrequest *kr = closure;
+ kr->callback(kr->closure, status, result, size);
+}
+
+static void perform_query(struct keyrequest *kr)
+{
+ CURL *curl;
+
+ curl = curl_wrap_prepare_get_url(kr->url);
+ if (!curl)
+ kr->callback(kr->closure, 0, "out of memory", 0);
+ else {
+ oidc_add_bearer(curl, kr->token);
+ curl_wrap_do(curl, perform_query_callback, kr);
+ }
+}
+
+static void token_success(void *closure, struct json_object *token)
+{
+ struct keyrequest *kr = closure;
+ kr->token = token;
+ perform_query(kr);
+}
+
+static void token_error(void *closure, const char *message, const char *indice)
+{
+ struct keyrequest *kr = closure;
+ kr->callback(kr->closure, 0, message, 0);
+}
+
+static void *kr_get_thread(void *closure)
+{
+ struct oidc_grant_cb cb;
+ struct keyrequest *kr = closure;
+
+ if (!kr->appli)
+ perform_query(kr);
+ else {
+ cb.closure = kr;
+ cb.success = token_success;
+ cb.error = token_error;
+ oidc_grant_owner_password(kr->appli, kr->idp, NULL, &cb);
+ }
+ kr->dead = 1;
+ return NULL;
+}
+
+static void kr_free(struct keyrequest *kr)
+{
+ json_object_put(kr->token);
+ free(kr);
+}
+
+static struct keyrequest *kr_alloc(
+ const char *url,
+ time_t expiration,
+ const char *appli,
+ const char *idp,
+ void (*callback)(void *closure, int status, const void *buffer, size_t size),
+ void *closure
+)
+{
+ struct keyrequest *result;
+ char *buf;
+ size_t surl, sappli, sidp;
+
+ surl = 1 + strlen(url);
+ sappli = appli ? 1 + strlen(appli) : 0;
+ sidp = idp ? 1 + strlen(idp) : 0;
+
+ result = calloc(1, surl + sappli + sidp + sizeof *result);
+ if (result) {
+ result->next = NULL;
+ result->dead = 0;
+ result->expiration = expiration;
+ result->callback = callback;
+ result->closure = closure;
+ result->token = NULL;
+ result->tid = 0;
+
+ buf = (char*)(&result[1]);
+ result->url = buf;
+ buf = mempcpy(buf, url, surl);
+ if (!appli)
+ result->appli = NULL;
+ else {
+ result->appli = buf;
+ buf = mempcpy(buf, appli, sappli);
+ }
+ if (!idp)
+ result->idp = NULL;
+ else {
+ result->idp = buf;
+ buf = mempcpy(buf, idp, sidp);
+ }
+ }
+ return result;
+}
+
+void aia_get(
+ const char *url,
+ int delay,
+ const char *appli,
+ const char *idp,
+ void (*callback)(void *closure, int status, const void *buffer, size_t size),
+ void *closure
+)
+{
+ int rc;
+ time_t now;
+ struct keyrequest **pkr, *kr, *found_kr;
+
+ /* initialize CURL component */
+ pthread_mutex_lock(&mutex);
+ if (!curl_initialized) {
+ curl_initialized = 1;
+ curl_global_init(CURL_GLOBAL_DEFAULT);
+ }
+
+ /* search for the same request and also cleanup deads */
+ now = time(NULL);
+ found_kr = 0;
+ pkr = &keyrequests;
+ kr = *pkr;
+ while (kr) {
+ if (now > kr->expiration) {
+ if (kr->dead) {
+ *pkr = kr->next;
+ kr_free(kr);
+ } else {
+ pkr = &kr->next;
+ }
+ } else {
+ if (!strcmp(url, kr->url))
+ found_kr = kr;
+ pkr = &kr->next;
+ }
+ kr = *pkr;
+ }
+
+ /* check if found and pending */
+ if (found_kr) {
+ /* found -> cancel */
+ pthread_mutex_unlock(&mutex);
+ callback(closure, 0, NULL, 0);
+ return;
+ }
+
+ /* allocates the keyrequest */
+ kr = kr_alloc(url, now + delay, appli, idp, callback, closure);
+ if (!kr) {
+ pthread_mutex_unlock(&mutex);
+ callback(closure, 0, "Out of memory", 0);
+ return;
+ }
+
+ /* link the request */
+ kr->next = keyrequests;
+ keyrequests = kr;
+
+ /* makes the request in a new thread */
+ rc = pthread_create(&kr->tid, 0, kr_get_thread, kr);
+ if (rc != 0) {
+ /* error, unlink */
+ keyrequests = kr->next;
+ pthread_mutex_unlock(&mutex);
+ kr_free(kr);
+ callback(closure, 0, "Can't create a new thread", 0);
+ return;
+ }
+ pthread_mutex_unlock(&mutex);
+}
+
+/* vim: set colorcolumn=80: */
+
diff --git a/src/aia-get.h b/src/aia-get.h
new file mode 100644
index 0000000..be1a1f8
--- /dev/null
+++ b/src/aia-get.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+extern void aia_get(
+ const char *url,
+ int delay,
+ const char *appli,
+ const char *idp,
+ void (*callback)(void *closure, int status, const void *buffer, size_t size),
+ void *closure
+);
+
diff --git a/src/authorization.c b/src/authorization.c
new file mode 100644
index 0000000..ae00923
--- /dev/null
+++ b/src/authorization.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include
+#include
+
+#include "base64.h"
+
+char *authorization_basic_make(const char *user, const char *password)
+{
+ const char *array[3] = { user, ":", password };
+ return base64_encode_array(array, 3);
+}
+
+char *authorization_basic_make_header(const char *user, const char *password)
+{
+ char *key, *result;
+
+ key = authorization_basic_make(user, password);
+ if (!key || asprintf(&result, "Authorization: Basic %s", key) < 0)
+ result = NULL;
+ free(key);
+ return result;
+}
+
+/* vim: set colorcolumn=80: */
+
diff --git a/src/authorization.h b/src/authorization.h
new file mode 100644
index 0000000..bd26c1a
--- /dev/null
+++ b/src/authorization.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+extern char *authorization_basic_make(const char *user, const char *password);
+extern char *authorization_basic_make_header(const char *user, const char *password);
+
+/* vim: set colorcolumn=80: */
diff --git a/src/base64.c b/src/base64.c
new file mode 100644
index 0000000..0841aba
--- /dev/null
+++ b/src/base64.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+
+const char base64_variant_standard[] = "+/=";
+const char base64_variant_url[] = "-_=";
+const char base64_variant_trunc[] = "+/";
+const char base64_variant_url_trunc[] = "-_";
+
+static char eb64(int x, const char *variant)
+{
+ if (x < 52)
+ return (char)(x + (x < 26 ? 'A' : 'a'-26));
+ else
+ return x < 62 ? (char)(x + '0' - 52) : variant[x - 62];
+}
+
+char *base64_encode_array_variant(const char * const *args, size_t count, const char *variant)
+{
+ const char *v, *s;
+ char *buffer, c;
+ size_t i, j, n;
+ uint16_t x;
+
+ /* compute size and allocate */
+ i = n = 0;
+ while (n < count)
+ i += strlen(args[n++]);
+ buffer = malloc(5 + ((i / 3) << 2));
+ if (!buffer)
+ return NULL;
+
+ /* encode */
+ v = variant ? : base64_variant_standard;
+ n = 0;
+ j = 0;
+ x = 0;
+ while (n < count) {
+ s = args[n++];
+ c = s[i = 0];
+ while (c) {
+ x = (uint16_t)((uint16_t)(x << 8) | (uint16_t)(uint8_t)c);
+ switch (j & 3) {
+ case 0:
+ buffer[j++] = eb64((x >> 2) & 63, v);
+ break;
+ case 1:
+ buffer[j++] = eb64((x >> 4) & 63, v);
+ break;
+ case 2:
+ buffer[j++] = eb64((x >> 6) & 63, v);
+ buffer[j++] = eb64(x & 63, v);
+ break;
+ }
+ c = s[++i];
+ }
+ }
+
+ /* pad */
+ if (v[2]) {
+ switch (j & 3) {
+ case 1:
+ buffer[j++] = eb64((x << 4) & 63, v);
+ buffer[j++] = v[2];
+ buffer[j++] = v[2];
+ break;
+ case 2:
+ buffer[j++] = eb64((x << 2) & 63, v);
+ buffer[j++] = v[2];
+ break;
+ }
+ }
+
+ /* done */
+ buffer[j] = 0;
+ return buffer;
+}
+
+char *base64_encode_multi_variant(const char * const *args, const char *variant)
+{
+ size_t count;
+
+ for (count = 0 ; args[count] ; count++);
+ return base64_encode_array_variant(args, count, variant);
+}
+
+char *base64_encode_variant(const char *arg, const char *variant)
+{
+ return base64_encode_array_variant(&arg, !!arg, variant);
+}
+
diff --git a/src/base64.h b/src/base64.h
new file mode 100644
index 0000000..5a944df
--- /dev/null
+++ b/src/base64.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+extern const char base64_variant_standard[];
+extern const char base64_variant_trunc[];
+
+extern const char base64_variant_url[];
+extern const char base64_variant_url_trunc[];
+
+extern char *base64_encode_array_variant(const char * const *args, size_t count, const char *variant);
+extern char *base64_encode_multi_variant(const char * const *args, const char *variant);
+extern char *base64_encode_variant(const char *arg, const char *variant);
+
+#define base64_encode_array(args,count) base64_encode_array_variant(args,count,base64_variant_standard)
+#define base64_encode_multi(args) base64_encode_multi_variant(args,base64_variant_standard)
+#define base64_encode(arg) base64_encode_variant(arg,base64_variant_standard)
+
+#define base64_encode_array_standard(args,count) base64_encode_array_variant(args,count,base64_variant_standard)
+#define base64_encode_multi_standard(args) base64_encode_multi_variant(args,base64_variant_standard)
+#define base64_encode_standard(arg) base64_encode_variant(arg,base64_variant_standard)
+
+#define base64_encode_array_url(args,count) base64_encode_array_variant(args,count,base64_variant_url)
+#define base64_encode_multi_url(args) base64_encode_multi_variant(args,base64_variant_url)
+#define base64_encode_url(arg) base64_encode_variant(arg,base64_variant_url)
+
+#define base64_encode_array_trunc(args,count) base64_encode_array_variant(args,count,base64_variant_trunc)
+#define base64_encode_multi_trunc(args) base64_encode_multi_variant(args,base64_variant_trunc)
+#define base64_encode_trunc(arg) base64_encode_variant(arg,base64_variant_trunc)
+
+#define base64_encode_array_url_trunc(args,count) base64_encode_array_variant(args,count,base64_variant_url_trunc)
+#define base64_encode_multi_url_trunc(args) base64_encode_multi_variant(args,base64_variant_url_trunc)
+#define base64_encode_url_trunc(arg) base64_encode_variant(arg,base64_variant_url_trunc)
+
+
+
diff --git a/src/curl-wrap.c b/src/curl-wrap.c
new file mode 100644
index 0000000..3c566a3
--- /dev/null
+++ b/src/curl-wrap.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "curl-wrap.h"
+#include "escape.h"
+
+
+/* internal representation of buffers */
+struct buffer {
+ size_t size;
+ char *data;
+};
+
+/* write callback for filling buffers with the response */
+static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ struct buffer *buffer = userdata;
+ size_t sz = size * nmemb;
+ size_t old_size = buffer->size;
+ size_t new_size = old_size + sz;
+ char *data = realloc(buffer->data, new_size + 1);
+ if (!data)
+ return 0;
+ memcpy(&data[old_size], ptr, sz);
+ data[new_size] = 0;
+ buffer->size = new_size;
+ buffer->data = data;
+ return sz;
+}
+
+/*
+ * Perform the CURL operation for 'curl' and put the result in
+ * memory. If 'result' isn't NULL it receives the returned content
+ * that then must be freed. If 'size' isn't NULL, it receives the
+ * size of the returned content. Note that if not NULL, the real
+ * content is one byte greater than the read size and the last byte
+ * zero. This facility allows to handle the returned content as a
+ * null terminated C-string.
+ */
+int curl_wrap_perform(CURL *curl, char **result, size_t *size)
+{
+ int rc;
+ struct buffer buffer;
+ CURLcode code;
+
+ /* init tthe buffer */
+ buffer.size = 0;
+ buffer.data = NULL;
+
+ /* Perform the request, res will get the return code */
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
+
+ /* Perform the request, res will get the return code */
+ code = curl_easy_perform(curl);
+ rc = code == CURLE_OK;
+
+ /* Check for no errors */
+ if (rc) {
+ /* no error */
+ if (size)
+ *size = buffer.size;
+ if (result)
+ *result = buffer.data;
+ else
+ free(buffer.data);
+ } else {
+ /* had error */
+ if (size)
+ *size = 0;
+ if (result)
+ *result = NULL;
+ free(buffer.data);
+ }
+
+ return rc;
+}
+
+void curl_wrap_do(CURL *curl, void (*callback)(void *closure, int status, CURL *curl, const char *result, size_t size), void *closure)
+{
+ int rc;
+ char *result;
+ size_t size;
+ char errbuf[CURL_ERROR_SIZE];
+
+ curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
+ rc = curl_wrap_perform(curl, &result, &size);
+ if (rc)
+ callback(closure, rc, curl, result, size);
+ else
+ callback(closure, rc, curl, errbuf, 0);
+ free(result);
+ curl_easy_cleanup(curl);
+}
+
+int curl_wrap_content_type_is(CURL *curl, const char *value)
+{
+ char *actual;
+ CURLcode code;
+
+ code = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &actual);
+ if (code != CURLE_OK || !actual)
+ return 0;
+
+ return !strncasecmp(actual, value, strcspn(actual, "; "));
+}
+
+CURL *curl_wrap_prepare_get_url(const char *url)
+{
+ CURL *curl;
+ CURLcode code;
+
+ curl = curl_easy_init();
+ if(curl) {
+ code = curl_easy_setopt(curl, CURLOPT_URL, url);
+ if (code == CURLE_OK)
+ return curl;
+ curl_easy_cleanup(curl);
+ }
+ return NULL;
+}
+
+CURL *curl_wrap_prepare_get(const char *base, const char *path, const char * const *args)
+{
+ CURL *res;
+ char *url;
+
+ url = escape_url(base, path, args, NULL);
+ res = url ? curl_wrap_prepare_get_url(url) : NULL;
+ free(url);
+ return res;
+}
+
+int curl_wrap_add_header(CURL *curl, const char *header)
+{
+ int rc;
+ struct curl_slist *list;
+
+ list = curl_slist_append(NULL, header);
+ rc = list ? curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list) == CURLE_OK : 0;
+/*
+ curl_slist_free_all(list);
+*/
+ return rc;
+}
+
+int curl_wrap_add_header_value(CURL *curl, const char *name, const char *value)
+{
+ char *h;
+ int rc;
+
+ rc = asprintf(&h, "%s: %s", name, value);
+ rc = rc < 0 ? 0 : curl_wrap_add_header(curl, h);
+ free(h);
+ return rc;
+}
+
+
+CURL *curl_wrap_prepare_post_url_data(const char *url, const char *datatype, const char *data, size_t szdata)
+{
+ CURL *curl;
+
+ curl = curl_easy_init();
+ if (curl
+ && CURLE_OK == curl_easy_setopt(curl, CURLOPT_URL, url)
+ && (!szdata || CURLE_OK == curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, szdata))
+ && CURLE_OK == curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data)
+ && (!datatype || curl_wrap_add_header_value(curl, "content-type", datatype)))
+ return curl;
+ curl_easy_cleanup(curl);
+ return NULL;
+}
+
+CURL *curl_wrap_prepare_post(const char *base, const char *path, const char * const *args)
+{
+ CURL *res;
+ char *url;
+ char *data;
+ size_t szdata;
+
+ url = escape_url(base, path, NULL, NULL);
+ data = escape_args(args, &szdata);
+ res = url ? curl_wrap_prepare_post_url_data(url, NULL, data, szdata) : NULL;
+ free(url);
+ return res;
+}
+
+/* vim: set colorcolumn=80: */
diff --git a/src/curl-wrap.h b/src/curl-wrap.h
new file mode 100644
index 0000000..2e44f47
--- /dev/null
+++ b/src/curl-wrap.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#pragma once
+
+#include
+
+extern char *curl_wrap_url (const char *base, const char *path,
+ const char *const *query, size_t * size);
+
+extern int curl_wrap_perform (CURL * curl, char **result, size_t * size);
+
+extern void curl_wrap_do(CURL *curl, void (*callback)(void *closure, int status, CURL *curl, const char *result, size_t size), void *closure);
+
+extern int curl_wrap_content_type_is (CURL * curl, const char *value);
+
+extern CURL *curl_wrap_prepare_get_url(const char *url);
+
+extern CURL *curl_wrap_prepare_get(const char *base, const char *path, const char * const *args);
+
+extern CURL *curl_wrap_prepare_post_url_data(const char *url, const char *datatype, const char *data, size_t szdata);
+
+extern CURL *curl_wrap_prepare_post(const char *base, const char *path, const char * const *args);
+
+extern int curl_wrap_add_header(CURL *curl, const char *header);
+
+extern int curl_wrap_add_header_value(CURL *curl, const char *name, const char *value);
+
+/* vim: set colorcolumn=80: */
+
diff --git a/src/escape.c b/src/escape.c
new file mode 100644
index 0000000..3bb25c2
--- /dev/null
+++ b/src/escape.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+
+/*
+ * Test if 'c' is to be escaped or not.
+ * Any character that is not in [-.0-9A-Z_a-z~]
+ * must be escaped.
+ * Note that space versus + is not managed here.
+ */
+static inline int should_escape(char c)
+{
+/* ASCII CODES OF UNESCAPED CHARS
+car hx/oct idx
+'-' 2d/055 1
+'.' 2e/056 2
+'0' 30/060 3
+... ..
+'9' 39/071 12
+'A' 41/101 13
+... ..
+'Z' 5a/132 38
+'_' 5f/137 39
+'a' 61/141 40
+... ..
+'z' 7a/172 65
+'~' 7e/176 66
+*/
+ /* [-.0-9A-Z_a-z~] */
+ if (c <= 'Z') {
+ /* [-.0-9A-Z] */
+ if (c < '0') {
+ /* [-.] */
+ return c != '-' && c != '.';
+ } else {
+ /* [0-9A-Z] */
+ return c < 'A' && c > '9';
+ }
+ } else {
+ /* [_a-z~] */
+ if (c <= 'z') {
+ /* [_a-z] */
+ return c < 'a' && c != '_';
+ } else {
+ /* [~] */
+ return c != '~';
+ }
+ }
+}
+
+/*
+ * returns the ASCII char for the hexadecimal
+ * digit of the binary value 'f'.
+ * returns 0 if f isn't in [0 ... 15].
+ */
+static inline char bin2hex(int f)
+{
+ if ((f & 15) != f)
+ f = 0;
+ else if (f < 10)
+ f += '0';
+ else
+ f += 'A' - 10;
+ return (char)f;
+}
+
+/*
+ * returns the binary value for the hexadecimal
+ * digit whose char is 'c'.
+ * returns -1 if c isn't i n[0-9A-Fa-f]
+ */
+static inline int hex2bin(char c)
+{
+ /* [0-9A-Fa-f] */
+ if (c <= 'F') {
+ /* [0-9A-F] */
+ if (c <= '9') {
+ /* [0-9] */
+ if (c >= '0') {
+ return (int)(c - '0');
+ }
+ } else if (c >= 'A') {
+ /* [A-F] */
+ return (int)(c - ('A' - 10));
+ }
+ } else {
+ /* [a-f] */
+ if (c >= 'a' && c <= 'f') {
+ return (int)(c - ('a' - 10));
+ }
+ }
+ return -1;
+}
+
+/*
+ * returns the length that will have the text 'itext' of length
+ * 'ilen' when escaped. When 'ilen' == 0, strlen is used to
+ * compute the size of 'itext'.
+ */
+static size_t escaped_length(const char *itext, size_t ilen)
+{
+ char c;
+ size_t i, r;
+
+ if (!ilen)
+ ilen = strlen(itext);
+ c = itext[i = r = 0];
+ while (i < ilen) {
+ r += c != ' ' && should_escape(c) ? 3 : 1;
+ c = itext[++i];
+ }
+ return r;
+}
+
+/*
+ * Escapes the text 'itext' of length 'ilen'.
+ * When 'ilen' == 0, strlen is used to compute the size of 'itext'.
+ * The escaped text is put in 'otext' of length 'olen'.
+ * Returns the length of the escaped text (it can be greater than 'olen').
+ * When 'olen' is greater than the needed length, an extra null terminator
+ * is appened to the escaped string.
+ */
+static size_t escape_to(const char *itext, size_t ilen, char *otext, size_t olen)
+{
+ char c;
+ size_t i, r;
+
+ if (!ilen)
+ ilen = strlen(itext);
+ c = itext[i = r = 0];
+ while (i < ilen) {
+ if (c == ' ')
+ c = '+';
+ else if (should_escape(c)) {
+ if (r < olen)
+ otext[r] = '%';
+ r++;
+ if (r < olen)
+ otext[r] = bin2hex((c >> 4) & 15);
+ r++;
+ c = bin2hex(c & 15);
+ }
+ if (r < olen)
+ otext[r] = c;
+ r++;
+ c = itext[++i];
+ }
+ if (r < olen)
+ otext[r] = 0;
+ return r;
+}
+
+/*
+ * returns the length of 'itext' of length 'ilen' that can be unescaped.
+ * compute the size of 'itext' when 'ilen' == 0.
+ */
+static size_t unescapable_length(const char *itext, size_t ilen)
+{
+ char c;
+ size_t i;
+
+ c = itext[i = 0];
+ while (i < ilen) {
+ if (c != '%')
+ i++;
+ else {
+ if (i + 3 > ilen
+ || hex2bin(itext[i + 1]) < 0
+ || hex2bin(itext[i + 2]) < 0)
+ break;
+ i += 3;
+ }
+ c = itext[i];
+ }
+ return i;
+}
+
+/*
+ * returns the length that will have the text 'itext' of length
+ * 'ilen' when escaped. When 'ilen' == 0, strlen is used to
+ * compute the size of 'itext'.
+ */
+static size_t unescaped_length(const char *itext, size_t ilen)
+{
+ char c;
+ size_t i, r;
+
+ c = itext[i = r = 0];
+ while (i < ilen) {
+ i += (size_t)(1 + ((c == '%') << 1));
+ r++;
+ c = itext[i];
+ }
+ return r;
+}
+
+static size_t unescape_to(const char *itext, size_t ilen, char *otext, size_t olen)
+{
+ char c;
+ size_t i, r;
+ int h, l;
+
+ ilen = unescapable_length(itext, ilen);
+ c = itext[i = r = 0];
+ while (i < ilen) {
+ if (c != '%') {
+ if (c == '+')
+ c = ' ';
+ i++;
+ } else {
+ if (i + 2 >= ilen)
+ break;
+ h = hex2bin(itext[i + 1]);
+ l = hex2bin(itext[i + 2]);
+ c = (char)((h << 4) | l);
+ i += 3;
+ }
+ if (r < olen)
+ otext[r] = c;
+ r++;
+ c = itext[i];
+ }
+ if (r < olen)
+ otext[r] = 0;
+ return r;
+}
+
+/* create an url */
+char *escape_url(const char *base, const char *path, const char * const *args, size_t *length)
+{
+ int i;
+ size_t lb, lp, lq, l, L;
+ const char *null;
+ char *result;
+
+ /* ensure args */
+ if (!args) {
+ null = NULL;
+ args = &null;
+ }
+
+ /* compute lengths */
+ lb = base ? strlen(base) : 0;
+ lp = path ? strlen(path) : 0;
+ lq = 0;
+ i = 0;
+ while (args[i]) {
+ lq += 1 + escaped_length(args[i], strlen(args[i]));
+ i++;
+ if (args[i])
+ lq += 1 + escaped_length(args[i], strlen(args[i]));
+ i++;
+ }
+
+ /* allocation */
+ L = lb + lp + lq + 1;
+ result = malloc(L + 1);
+ if (result) {
+ /* make the resulting url */
+ l = lb;
+ if (lb) {
+ memcpy(result, base, lb);
+ if (result[l - 1] != '/' && path && path[0] != '/')
+ result[l++] = '/';
+ }
+ if (lp) {
+ memcpy(result + l, path, lp);
+ l += lp;
+ }
+ i = 0;
+ while (args[i]) {
+ if (i) {
+ result[l++] = '&';
+ } else if (base || path) {
+ result[l] = memchr(result, '?', l) ? '&' : '?';
+ l++;
+ }
+ l += escape_to(args[i], strlen(args[i]), result + l, L - l);
+ i++;
+ if (args[i]) {
+ result[l++] = '=';
+ l += escape_to(args[i], strlen(args[i]), result + l, L - l);
+ }
+ i++;
+ }
+ result[l] = 0;
+ if (length)
+ *length = l;
+ }
+ return result;
+}
+
+char *escape_args(const char * const *args, size_t *length)
+{
+ return escape_url(NULL, NULL, args, length);
+}
+
+const char **unescape_args(const char *args)
+{
+ const char **r, **q;
+ char c, *p;
+ size_t j, z, l, n, lt;
+
+ lt = n = 0;
+ if (args[0]) {
+ z = 0;
+ do {
+ l = strcspn(&args[z], "&=");
+ j = 1 + unescaped_length(&args[z], l);
+ lt += j;
+ z += l;
+ c = args[z++];
+ if (c == '=') {
+ l = strcspn(&args[z], "&");
+ j = 1 + unescaped_length(&args[z], l);
+ lt += j;
+ z += l;
+ c = args[z++];
+ }
+ n++;
+ } while(c);
+ }
+
+ l = lt + (2 * n + 1) * sizeof(char *);
+ r = malloc(l);
+ if (!r)
+ return r;
+
+ q = r;
+ p = (void*)&r[2 * n + 1];
+ if (args[0]) {
+ z = 0;
+ do {
+ q[0] = p;
+ l = strcspn(&args[z], "&=");
+ j = 1 + unescape_to(&args[z], l, p, lt);
+ lt -= j;
+ p += j;
+ z += l;
+ c = args[z++];
+ if (c != '=')
+ q[1] = NULL;
+ else {
+ q[1] = p;
+ l = strcspn(&args[z], "&");
+ j = 1 + unescape_to(&args[z], l, p, lt);
+ lt -= j;
+ p += j;
+ z += l;
+ c = args[z++];
+ }
+ q = &q[2];
+ } while(c);
+ }
+ q[0] = NULL;
+ return r;
+}
+
+char *escape(const char *text, size_t textlen, size_t *reslength)
+{
+ size_t len;
+ char *result;
+
+ len = 1 + escaped_length(text, textlen);
+ result = malloc(len);
+ if (result)
+ escape_to(text, textlen, result, len);
+ if (reslength)
+ *reslength = len - 1;
+ return result;
+}
+
+char *unescape(const char *text, size_t textlen, size_t *reslength)
+{
+ size_t len;
+ char *result;
+
+ len = 1 + unescaped_length(text, textlen);
+ result = malloc(len);
+ if (result)
+ unescape_to(text, textlen, result, len);
+ if (reslength)
+ *reslength = len - 1;
+ return result;
+}
+
+#if 1
+#include
+int main(int ac, char **av)
+{
+ int i;
+ char *x = escape_args((void*)++av, NULL);
+ char *y = escape(x, strlen(x), NULL);
+ char *z = unescape(y, strlen(y), NULL);
+ const char **v = unescape_args(x);
+
+ printf("%s\n%s\n%s\n", x, y, z);
+ free(x);
+ free(y);
+ free(z);
+ i = 0;
+ while(v[i]) {
+ printf("%s=%s / %s=%s\n", av[i], av[i+1], v[i], v[i+1]);
+ i += 2;
+ }
+ free(v);
+ return 0;
+}
+#endif
+/* vim: set colorcolumn=80: */
diff --git a/src/escape.h b/src/escape.h
new file mode 100644
index 0000000..7d548db
--- /dev/null
+++ b/src/escape.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+extern char *escape_url(const char *base, const char *path, const char * const *args, size_t *length);
+extern char *escape_args(const char * const *args, size_t *length);
+extern const char **unescape_args(const char *args);
+
+/* vim: set colorcolumn=80: */
diff --git a/src/export.map b/src/export.map
new file mode 100644
index 0000000..ee2f413
--- /dev/null
+++ b/src/export.map
@@ -0,0 +1 @@
+{ global: afbBindingV*; local: *; };
diff --git a/src/memo.txt b/src/memo.txt
new file mode 100644
index 0000000..3a6ed50
--- /dev/null
+++ b/src/memo.txt
@@ -0,0 +1,11 @@
+
+gcc --shared -fPIC -o aia.so [^t]*.c -lcurl -lsystemd -ljson-c
+
+afb-daemon --rootdir=. --ldpaths=. --port=1212 --token= --verbose --verbose --verbose
+
+
+afb-client-demo localhost:1212/api?token=t
+agl-identity-agent subscribe
+
+
+gcc -o taia *aia-uds-bluez.c -lsystemd
diff --git a/src/oidc-agent.c b/src/oidc-agent.c
new file mode 100644
index 0000000..1f09e7a
--- /dev/null
+++ b/src/oidc-agent.c
@@ -0,0 +1,812 @@
+/*
+ * Copyright (C) 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "oidc-agent.h"
+#include "escape.h"
+#include "curl-wrap.h"
+
+/***************** utilities *************************/
+
+static const char string_empty[] = "";
+static const char string_authorization_endpoint[] = "authorization_endpoint";
+static const char string_token_endpoint[] = "token_endpoint";
+#if 0
+static const char string_issuer[] = "issuer";
+static const char string_userinfo_endpoint[] = "userinfo_endpoint";
+static const char string_revocation_endpoint[] = "revocation_endpoint";
+static const char string_jwks_uri[] = "jwks_uri";
+#endif
+
+#define MAX_IDP_COUNT 20
+#define MAX_APPLI_COUNT 100
+
+static struct json_object *idps;
+static struct json_object *applis;
+
+static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
+
+/***************** utilities *************************/
+
+/*
+ * Get the object of 'name' in the 'container' and return it.
+ * Creates the result if needed and add it to the container.
+ * When 'maxcount' isn't zero the final count will not exceed 'maxcount'.
+ */
+static struct json_object *j_container_item(struct json_object *container, const char *name, int maxcount)
+{
+ struct json_object *result;
+
+ /* ensure object of 'name' exists */
+ if (!json_object_object_get_ex(container, name, &result)) {
+ if (maxcount && json_object_object_length(container) >= maxcount)
+ return NULL;
+ result = json_object_new_object();
+ if (!result)
+ return NULL;
+ json_object_object_add (container, name, result);
+ }
+ return result;
+}
+
+/*
+ * Like 'j_container_item' but also creates the 'container' if needed.
+ */
+static struct json_object *j_container_item_make(struct json_object **container, const char *name, int maxcount)
+{
+ struct json_object *cont;
+
+ /* ensure container exists */
+ cont = *container;
+ if (!cont) {
+ cont = json_object_new_object();
+ if (!cont)
+ return NULL;
+ *container = cont;
+ }
+ return j_container_item(cont, name, maxcount);
+}
+
+/*
+ * Adds in 'dest' the fields of 'src'
+ * Also when the value of a field of 'src' is null, delete the field of 'dst'
+ */
+static void j_merge(struct json_object *dest, struct json_object *src)
+{
+ struct json_object_iter i;
+ json_object_object_foreachC(src, i) {
+ if (json_object_is_type(i.val, json_type_null))
+ json_object_object_del(dest, i.key);
+ else
+ json_object_object_add(dest, i.key, json_object_get(i.val));
+ }
+}
+
+/***************** IDP **************************/
+
+/*
+ * Set the values of 'desc' for the idp of 'name'.
+ * Return 0 on error or 1 on success.
+ */
+int oidc_idp_set(const char *name, struct json_object *desc)
+{
+ struct json_object *idp;
+ int result = 0;
+
+ pthread_rwlock_wrlock(&rwlock);
+ idp = j_container_item_make(&idps, name, MAX_IDP_COUNT);
+ if (idp) {
+ j_merge(idp, desc);
+ result = 1;
+ }
+ pthread_rwlock_unlock(&rwlock);
+ return result;
+}
+
+/*
+ * Return 1 if idp of 'name' exists or 0 otherwise.
+ */
+int oidc_idp_exists(const char *name)
+{
+ int result;
+
+ pthread_rwlock_rdlock(&rwlock);
+ result = json_object_object_get_ex(idps, name, NULL);
+ pthread_rwlock_unlock(&rwlock);
+
+ return result;
+}
+
+/*
+ * Deletes the idp of 'name'.
+ */
+void oidc_idp_delete(const char *name)
+{
+ pthread_rwlock_wrlock(&rwlock);
+ json_object_object_del(idps, name);
+ pthread_rwlock_unlock(&rwlock);
+}
+
+/***************** APPLI **************************/
+
+/*
+ * Returns the name of the idp of the 'appli'.
+ * Returns NULL when appli isn't set or default idp isn't set.
+ */
+static const char *get_default_idp(const char *appli)
+{
+ struct json_object *a, *i;
+
+ if (!json_object_object_get_ex(applis, appli, &a))
+ return NULL;
+ if (!json_object_object_get_ex(a, string_empty, &i))
+ return NULL;
+ return json_object_get_string(i);
+}
+
+/*
+ * Returns the application data related to the 'appli' for the 'idp'.
+ * If 'ja' isn't null, returns in it the object for the application 'appli'.
+ * Returns NULL in case of error.
+ */
+static struct json_object *get_appli_idp(const char *appli, const char *idp, struct json_object **ja)
+{
+ struct json_object *a, *i;
+
+ if (!json_object_object_get_ex(applis, appli, &a) || !json_object_object_get_ex(a, idp, &i))
+ return NULL;
+ if (ja)
+ *ja = a;
+ return i;
+}
+
+/*
+ * Set the description 'desc' for the application of 'name' and
+ * the 'idp'. When 'make_default' is set it, make it the default idp
+ * for the application.
+ * Return 0 on error or 1 on success.
+ */
+int oidc_appli_set(const char *name, const char *idp, struct json_object *desc, int make_default)
+{
+ struct json_object *a, *ai;
+ int result = 0;
+
+ pthread_rwlock_wrlock(&rwlock);
+ a = j_container_item_make(&applis, name, MAX_APPLI_COUNT);
+ if (a) {
+ ai = j_container_item(a, idp, 0);
+ if (ai) {
+ j_merge(ai, desc);
+ if (make_default || !json_object_object_get_ex(a, string_empty, NULL))
+ json_object_object_add(a, string_empty, json_object_new_string(idp));
+ result = 1;
+ }
+ }
+ pthread_rwlock_unlock(&rwlock);
+ return result;
+}
+
+/*
+ * Is the appli of 'name' defined?
+ * Return 1 if answer is yes or 0 for no.
+ */
+int oidc_appli_exists(const char *name)
+{
+ int result;
+
+ pthread_rwlock_rdlock(&rwlock);
+ result = json_object_object_get_ex(applis, name, NULL);
+ pthread_rwlock_unlock(&rwlock);
+
+ return result;
+}
+
+/*
+ * Does the appli of 'name' has the 'idp' defined?
+ * Return 1 if answer is yes or 0 for no.
+ */
+int oidc_appli_has_idp(const char *name, const char *idp)
+{
+ int result;
+
+ pthread_rwlock_rdlock(&rwlock);
+ result = !!get_appli_idp(name, idp, NULL);
+ pthread_rwlock_unlock(&rwlock);
+
+ return result;
+}
+
+/*
+ * Set 'idp' as default for the application of 'name'.
+ * Returns 0 on error (appli or idp for appli not existing)
+ * or 1 in case of success.
+ */
+int oidc_appli_set_default_idp(const char *name, const char *idp)
+{
+ struct json_object *a, *i;
+
+ pthread_rwlock_wrlock(&rwlock);
+ i = get_appli_idp(name, idp, &a);
+ if (i)
+ json_object_object_add(a, string_empty, json_object_new_string(idp));
+ pthread_rwlock_unlock(&rwlock);
+
+ return !!i;
+}
+
+/*
+ * Deletes the application of 'name'
+ */
+void oidc_appli_delete(const char *name)
+{
+ pthread_rwlock_wrlock(&rwlock);
+ json_object_object_del(applis, name);
+ pthread_rwlock_unlock(&rwlock);
+}
+
+/***************** AUTHORISATION **************************/
+
+/* parameters */
+enum param
+{
+ Param_Access_Token,
+ Param_Acr_Values,
+ Param_Authorization,
+ Param_Client_Id,
+ Param_Client_Secret,
+ Param_Code,
+ Param_Display,
+ Param_Error,
+ Param_Error_Description,
+ Param_Error_Uri,
+ Param_Expires_In,
+ Param_Grant_Type,
+ Param_Id_Token,
+ Param_Id_Token_Hint,
+ Param_Login_Hint,
+ Param_Max_Age,
+ Param_Nonce,
+ Param_Password,
+ Param_Prompt,
+ Param_Redirect_Uri,
+ Param_Refresh_Token,
+ Param_Response_Type,
+ Param_Scope,
+ Param_State,
+ Param_Token_Type,
+ Param_Ui_Locales,
+ Param_Username,
+ PARAM_COUNT
+};
+
+#if PARAM_COUNT > 30
+# error "Too much parameters"
+#endif
+#define PARAM(p) ((uint32_t)((uint32_t)1 << (Param_##p)))
+
+/* args of authorization requests */
+struct args
+{
+ struct json_object *appli;
+ struct json_object *idp;
+ struct json_object *args;
+ struct oidc_grant_cb cb;
+ int locked;
+ int refresh;
+ uint32_t mandatory;
+ uint32_t all;
+ struct json_object *header;
+ struct json_object *query;
+};
+
+/* Release the lock if needed */
+static void args_unlock(struct args *args)
+{
+ if (!args->locked) {
+ pthread_rwlock_unlock(&rwlock);
+ args->locked = 0;
+ }
+}
+
+/* Release the memory needed by args */
+static void args_destroy(struct args *args)
+{
+ json_object_put(args->appli);
+ json_object_put(args->idp);
+ json_object_put(args->header);
+ json_object_put(args->query);
+ free(args);
+}
+
+/* Send the success event with the gained tokens */
+static void args_send_success(struct args *args, struct json_object *result)
+{
+ args_unlock(args);
+ args->cb.success(args->cb.closure, result);
+ args_destroy(args);
+}
+
+/* Sends the error event with the indice to the client of args */
+static void args_send_error(struct args *args, const char *message, const char *indice)
+{
+ args_unlock(args);
+ args->cb.error(args->cb.closure, message, indice);
+ args_destroy(args);
+}
+
+/* Send the error and also return NULL */
+static inline struct args *args_send_error_null(struct args *args, const char *message, const char *indice)
+{
+ args_send_error(args, message, indice);
+ return NULL;
+}
+
+/* creates a struct args from the arguments, returns NULL on error */
+struct args *mkargs(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb)
+{
+ struct args *result;
+ struct json_object *obj;
+
+ /* allocates the args */
+ result = calloc(1, sizeof *result);
+ if (!result) {
+ cb->error(cb->closure, "Out of memory", NULL);
+ return NULL;
+ }
+
+ /* init of the structure */
+ result->cb = *cb;
+ result->args = args;
+ result->header = json_object_new_object();
+ result->query = json_object_new_object();
+
+ /* lock in read */
+ pthread_rwlock_rdlock(&rwlock);
+ result->locked = 1;
+
+ /* check previous allocations */
+ if (!result->query || !result->header) {
+ return args_send_error_null(result, "Out of memory", NULL);
+ }
+
+ /* check whether default idp */
+ if (!idp) {
+ idp = get_default_idp(appli);
+ if (!idp)
+ return args_send_error_null(result, "No default IDP", NULL);
+ }
+
+ /* get the IDP */
+ if (!json_object_object_get_ex(idps, idp, &obj))
+ return args_send_error_null(result, "Unknown IDP", idp);
+ result->idp = json_object_get(obj);
+
+ /* get the appli */
+ obj = get_appli_idp(appli, idp, NULL);
+ if (!obj)
+ return args_send_error_null(result, "Unknown APPLI for IDP", appli);
+ result->appli = json_object_get(obj);
+
+ return result;
+}
+
+/* get a value for a struct args */
+static struct json_object *args_object(struct args *args, const char *name)
+{
+ struct json_object *result;
+
+ if (!json_object_object_get_ex(args->appli, name, &result)
+ && !json_object_object_get_ex(args->idp, name, &result)
+ && !json_object_object_get_ex(args->args, name, &result))
+ result = NULL;
+ return result;
+}
+
+/* get a string value for a struct args */
+static const char *args_string(struct args *args, const char *name)
+{
+ struct json_object *object = args_object(args, name);
+ return object ? json_object_get_string(object) : NULL;
+}
+
+/* add a data */
+static int args_add(struct args *args, uint32_t val, const char *name, int query)
+{
+ struct json_object *obj, *dest;
+
+ if (val & args->all) {
+ obj = args_object(args, name);
+ if (obj) {
+ dest = query ? args->query : args->header;
+ json_object_object_add(dest, name, json_object_get(obj));
+ }
+ else if (val & args->mandatory) {
+ args_send_error(args, "Mandatory field missing", name);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Makes the CURL object for the given 'url' for either GET or POST depending
+ * on 'post' with the added 'header' fields and the given query parameters.
+ * Returns NULL on error.
+ * Ex:
+ *
+ * curl_json("http://iot.bzh/api", 0, {"X-Index": "no"}, {"fast":true,"item":"2345-hellfest"})
+ *
+ * produces the query:
+ *
+ * GET /api?fast=true&item=2345-hellfest HTTP/1.1
+ * Host: iot.bzh
+ * X-Index: no
+ *
+ * while the same but with post not null produces:
+ *
+ * POST /api HTTP/1.1
+ * Host: iot.bzh
+ * X-Index: no
+ * Content-Type: application/x-www-form-urlencoded
+ *
+ * fast=true&item=2345-hellfest
+ *
+ */
+static CURL *curl_json(const char *url, int post, struct json_object *header, struct json_object *query)
+{
+ const char **args, *str;
+ struct json_object_iter i;
+ int idx;
+ CURL *result;
+
+ /* create args array */
+ idx = 1 + (json_object_object_length(query) << 1);
+ args = malloc((unsigned)idx * sizeof *args);
+ if (!args)
+ return NULL;
+
+ /* fill the args array */
+ args[--idx] = NULL;
+ json_object_object_foreachC(query, i) {
+ str = json_object_get_string(i.val);
+ args[--idx] = str;
+ args[--idx] = i.key;
+ }
+
+ /* prepare the query */
+ if (post)
+ result = curl_wrap_prepare_post(url, NULL, args);
+ else
+ result = curl_wrap_prepare_get(url, NULL, args);
+ free(args);
+ if(!result)
+ return NULL;
+
+ /* add headers */
+ if (header) {
+ json_object_object_foreachC(header, i) {
+ str = json_object_get_string(i.val);
+ if (!curl_wrap_add_header_value(result, i.key, str)) {
+ curl_easy_cleanup(result);
+ return NULL;
+ }
+ }
+ }
+ return result;
+}
+
+/*
+ * Extract from the answer of 'curl' whose 'content' has 'size' bytes the
+ * embeded JSON object (if any).
+ * Returns it or returns NULL if the answer can't be interpreted.
+ */
+static struct json_object *decode_perform_result(CURL *curl, const char *content, size_t size)
+{
+ int i;
+ const char **args;
+ struct json_object *result;
+
+ /* is it an url encoded answer? */
+ if (curl_wrap_content_type_is(curl, "application/x-www-form-urlencoded")) {
+ /* yes, unescape as an array of strings */
+ args = unescape_args(content);
+ if (!args)
+ result = NULL;
+ else {
+ /* wrap the key=value pairs in an object */
+ result = json_object_new_object();
+ if (result) {
+ for (i = 0 ; args[i] ; i += 2)
+ json_object_object_add(result, args[i],
+ json_object_new_string(args[i+1]));
+ }
+ free(args);
+ }
+ } else if (curl_wrap_content_type_is(curl, "application/json")) {
+ /* interpret the json */
+ result = json_tokener_parse (content);
+ } else {
+ /* by default, still try to interpret the answer as if json */
+ result = json_tokener_parse (content);
+ }
+ return result;
+}
+
+/*
+ * Treats the result of the query 'curl' of 'content' of 'size' bytes for the 'args'
+ */
+static void perform_result(struct args *args, CURL *curl, const char *content, size_t size)
+{
+ struct json_object *obj, *at, *tt;
+ char *txt;
+
+ /* get answer */
+ obj = decode_perform_result(curl, content, size);
+ if (!obj)
+ return args_send_error(args, "unable to extract answer", content);
+
+ /* process the answer */
+ if (json_object_object_get_ex(obj, "access_token", &at) && json_object_object_get_ex(obj, "token_type", &tt)) {
+ if (!strcmp(json_object_get_string(tt), "bearer")) {
+ if (asprintf(&txt, "Bearer %s", json_object_get_string(at)) > 0) {
+ json_object_object_add(obj, "authorization", json_object_new_string(txt));
+ free(txt);
+ }
+ }
+ }
+
+ /* merge the answer to the token args in case of refresh */
+ if (args->refresh)
+ j_merge(args->args, obj);
+
+ /* send the answer */
+ args_send_success(args, obj);
+}
+
+/*
+ * Treats the redirect answer of the query 'curl' of 'content' of 'size' bytes for the 'args'
+ */
+static void perform_redirect(struct args *args, CURL *curl, const char *content, size_t size)
+{
+ /* TODO: handle redirection for the normal flow */
+ return args_send_error(args, "unhandled redirection", content);
+}
+
+/*
+ * Handle the result of the query 'curl' of 'status'. If a data is returned, it is available in
+ * 'content' of 'size' bytes.
+ * When 'status' is 0, an error occured. Otherwise, 'statu' isn't zero.
+ */
+static void perform_callback(void *closure, int status, CURL *curl, const char *content, size_t size)
+{
+ long code;
+ struct args *args = closure;
+
+ /* query error ? */
+ if (!status
+ || curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code) != CURLE_OK)
+ return args_send_error(args, "query error", NULL); /* TODO: IMPROVE? */
+
+ /* get the returned code */
+ switch (code) {
+ case 200:
+ return perform_result(args, curl, content, size);
+ case 302:
+ return perform_redirect(args, curl, content, size);
+ case 400:
+ case 401:
+ return args_send_error(args, content ? : "returned code error", content ? "returned code error" : content);
+ default:
+ return args_send_error(args, content ? : "unexpected code error", content ? "unexpected code error" : content);
+ }
+}
+
+/*
+ * Main function for performing OAuth2/OpenId Connect transactions.
+ * The structure 'args' is filled with the needed values:
+ * Application data as json object, IDP data as json object
+ * Contextual arguments for the transaction.
+ * 'endpoint' must be the name of an endpoint in the context of 'args'.
+ * 'operation' is the value that will get either response_type or grant_type,
+ * depending on the nature of the required parameters 'mandatory'.
+ * 'mandatory' designates the mandatory parameters.
+ * 'optional' designate the optional parameters.
+ */
+static void perform(struct args *args, const char *endpoint, const char *operation, uint32_t mandatory, uint32_t optional)
+{
+ int post;
+ const char *url, *type;
+ CURL *curl;
+
+ /* set the flags */
+ args->mandatory = mandatory;
+ args->all = mandatory | optional;
+
+ /* get the endpoint */
+ url = args_string(args, endpoint);
+ if (!url)
+ return args_send_error(args, "No endpoint", endpoint);
+
+ /* get the operation type */
+ if ((mandatory & PARAM(Response_Type)) == PARAM(Response_Type)) {
+ type = "response_type";
+ post = 0; /* can be 1 sometimes so not risk here */
+ } else if ((mandatory & PARAM(Grant_Type)) == PARAM(Grant_Type)) {
+ type = "grant_type";
+ post = 1; /* must be 1 */
+ } else
+ return args_send_error(args, "Unexpected operation Type", NULL);
+
+ json_object_object_add(args->query, type, json_object_new_string(operation));
+
+ /* get the arguments */
+ if (1
+ && args_add(args, PARAM(Access_Token), "access_token", 1)
+ && args_add(args, PARAM(Acr_Values), "acr_values", 1)
+ && args_add(args, PARAM(Authorization), "authorization", 0)
+ && args_add(args, PARAM(Client_Id), "client_id", 1)
+ && args_add(args, PARAM(Client_Secret), "client_secret", 1)
+ && args_add(args, PARAM(Code), "code", 1)
+ && args_add(args, PARAM(Display), "display", 1)
+ && args_add(args, PARAM(Expires_In), "expires_in", 1)
+ && args_add(args, PARAM(Id_Token_Hint), "id_token_hint", 1)
+ && args_add(args, PARAM(Login_Hint), "login_hint", 1)
+ && args_add(args, PARAM(Max_Age), "max_age", 1)
+ && args_add(args, PARAM(Nonce), "nonce", 1)
+ && args_add(args, PARAM(Password), "password", 1)
+ && args_add(args, PARAM(Prompt), "prompt", 1)
+ && args_add(args, PARAM(Redirect_Uri), "redirect_uri", 1)
+ && args_add(args, PARAM(Refresh_Token), "refresh_token", 1)
+ && args_add(args, PARAM(Scope), "scope", 1)
+ && args_add(args, PARAM(State), "state", 1)
+ && args_add(args, PARAM(Token_Type), "token_type", 1)
+ && args_add(args, PARAM(Ui_Locales), "ui_locales", 1)
+ && args_add(args, PARAM(Username), "username", 1)
+ ) {
+ /* creates the curl query */
+ curl = curl_json(url, post, args->header, args->query);
+ if (!curl)
+ return args_send_error(args, "out of memory", NULL);
+
+ /* release data */
+ args_unlock(args);
+
+ /* perform the request to the server */
+ curl_wrap_do(curl, perform_callback, args);
+ }
+}
+
+/* perform a grant of flow Flow_Resource_Owner_Password_Credentials_Grant */
+static void grant_owner_password(struct args *args)
+{
+ perform(args, string_token_endpoint, "password",
+ PARAM(Grant_Type) | PARAM(Username) | PARAM(Password),
+ PARAM(Scope) | PARAM(Authorization)
+ );
+}
+
+/* perform a grant of flow Flow_Client_Credentials_Grant */
+static void grant_client_credentials(struct args *args)
+{
+ perform(args, string_token_endpoint, "client_credentials",
+ PARAM(Grant_Type),
+ PARAM(Scope) | PARAM(Authorization)
+ );
+}
+
+/* switches the requests depending on 'flow' */
+static void grant(struct args *args, enum oidc_grant_flow flow)
+{
+ /* ensure args is valid */
+ if (!args)
+ return;
+
+ /* process for flow */
+ switch(flow) {
+
+ case Flow_Resource_Owner_Password_Credentials_Grant:
+ grant_owner_password(args);
+ break;
+
+ case Flow_Client_Credentials_Grant:
+ grant_client_credentials(args);
+ break;
+
+ case Flow_Authorization_Code_Grant:
+ case Flow_Implicit_Grant:
+ case Flow_Extension_Grant:
+ args_send_error(args, "Unsupported flow", NULL);
+ break;
+
+ case Flow_Invalid:
+ default:
+ args_send_error(args, "Invalid flow", NULL);
+ break;
+ }
+}
+
+/*
+ * Initiates a grant with the given 'flow'.
+ * 'appli' and 'idp' designates the appli and the idp that have been recorded.
+ * when idp == NULL or idp == "", the default idp of 'appli' is used.
+ * 'args' contains parameters expected in plus for the grant transaction.
+ * 'cb' describes the callback actions that are called before
+ * the function returns.
+ */
+void oidc_grant(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb, enum oidc_grant_flow flow)
+{
+ grant(mkargs(appli, idp, args, cb), flow);
+}
+
+/*
+ * Like oidc_grant for flow Flow_Resource_Owner_Password_Credentials_Grant
+ */
+void oidc_grant_owner_password(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb)
+{
+ grant(mkargs(appli, idp, args, cb), Flow_Resource_Owner_Password_Credentials_Grant);
+}
+
+/*
+ * Like oidc_grant for flow Flow_Client_Credentials_Grant
+ */
+void oidc_grant_client_credentials(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb)
+{
+ grant(mkargs(appli, idp, args, cb), Flow_Client_Credentials_Grant);
+}
+
+/*
+ * Refreshes the 'token' for the 'appli' and the 'idp'.
+ * 'cb' describes the callback actions that are called before
+ * the function returns.
+ */
+void oidc_token_refresh(const char *appli, const char *idp, struct json_object *token, const struct oidc_grant_cb *cb)
+{
+ struct args *args;
+
+ args = mkargs(appli, idp, token, cb);
+ if (!args)
+ return;
+ args->refresh = 1;
+ perform(args, string_token_endpoint, "refresh_token",
+ PARAM(Grant_Type) | PARAM(Refresh_Token),
+ PARAM(Scope) | PARAM(Authorization)
+ );
+}
+
+/*
+ * Adds the header "authorisation" with the bearer access_token of 'token'.
+ * Return 1 on case of success or 0 otherwise.
+ */
+int oidc_add_bearer(CURL *curl, struct json_object *token)
+{
+ struct json_object *bearer;
+
+ return json_object_object_get_ex(token, "authorization", &bearer)
+ && curl_wrap_add_header_value(curl, "authorization", json_object_get_string(bearer));
+}
+
+
diff --git a/src/oidc-agent.h b/src/oidc-agent.h
new file mode 100644
index 0000000..de5918d
--- /dev/null
+++ b/src/oidc-agent.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+struct json_object;
+#include
+
+/***************** IDP **************************/
+
+extern int oidc_idp_set(
+ const char *name,
+ struct json_object *desc
+ );
+
+extern int oidc_idp_exists(
+ const char *name
+ );
+
+extern void oidc_idp_delete(
+ const char *name
+ );
+
+
+/***************** APPLI **************************/
+
+extern int oidc_appli_set(
+ const char *name,
+ const char *idp,
+ struct json_object *desc,
+ int make_default
+ );
+
+extern int oidc_appli_exists(
+ const char *name
+ );
+
+extern int oidc_appli_has_idp(
+ const char *name,
+ const char *idp
+ );
+
+extern int oidc_appli_set_default_idp(
+ const char *name,
+ const char *idp
+ );
+
+extern void oidc_appli_delete(
+ const char *name
+ );
+
+/***************** APPLI **************************/
+
+struct oidc_grant_cb
+{
+ void *closure;
+ void (*success)(void *closure, struct json_object *result);
+ void (*error)(void *closure, const char *message, const char *indice);
+};
+
+enum oidc_grant_flow
+{
+ Flow_Invalid,
+ Flow_Authorization_Code_Grant,
+ Flow_Implicit_Grant,
+ Flow_Resource_Owner_Password_Credentials_Grant,
+ Flow_Client_Credentials_Grant,
+ Flow_Extension_Grant
+};
+
+
+extern void oidc_grant(
+ const char *appli,
+ const char *idp,
+ struct json_object *args,
+ const struct oidc_grant_cb *cb,
+ enum oidc_grant_flow flow
+ );
+
+extern void oidc_grant_owner_password(
+ const char *appli,
+ const char *idp,
+ struct json_object *args,
+ const struct oidc_grant_cb *cb
+ );
+
+extern void oidc_grant_client_credentials(
+ const char *appli,
+ const char *idp,
+ struct json_object *args,
+ const struct oidc_grant_cb *cb
+ );
+
+extern void oidc_token_refresh(
+ const char *appli,
+ const char *idp,
+ struct json_object *token,
+ const struct oidc_grant_cb *cb
+ );
+
+extern int oidc_add_bearer(
+ CURL *curl,
+ struct json_object *token
+ );
+
diff --git a/src/test-aia-uds-bluez.c b/src/test-aia-uds-bluez.c
new file mode 100644
index 0000000..4a084a5
--- /dev/null
+++ b/src/test-aia-uds-bluez.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
+ * Author: José Bollo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "aia-uds-bluez.h"
+
+
+void p(const char *tag, const struct aia_uds_value *value)
+{
+ printf("%10s %c %.*s\n", tag, value->changed?'*':' ', (int)value->length, value->data);
+}
+
+void onchg(const struct aia_uds *uds)
+{
+ printf("\n");
+ p("first name", &uds->first_name);
+ p("last name", &uds->last_name);
+ p("email", &uds->email);
+ p("language", &uds->language);
+}
+
+int main()
+{
+ sd_bus *bus;
+ sd_id128_t id;
+ int rc;
+
+ aia_uds_set_on_change(onchg);
+ rc = sd_bus_default_system(&bus);
+ rc = sd_id128_randomize(&id);
+ rc = sd_bus_set_server(bus, 1, id);
+ rc = sd_bus_start(bus);
+ rc = aia_uds_init(bus);
+ rc = aia_uds_advise(1, NULL, NULL);
+ for (;;) {
+ rc = sd_bus_process(bus, NULL);
+ if (rc < 0)
+ break;
+ else if (rc == 0)
+ rc = sd_bus_wait(bus, (uint64_t) -1);
+ }
+}
+
diff --git a/uds-ble-id-init-service/CMakeLists.txt b/uds-ble-id-init-service/CMakeLists.txt
deleted file mode 100644
index 14b6d55..0000000
--- a/uds-ble-id-init-service/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-###########################################################################
-# Copyright 2017 IoT.bzh
-#
-# author: Jose Bollo
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-###########################################################################
-
-cmake_minimum_required(VERSION 3.6)
-SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/)
-include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake)
diff --git a/uds-ble-id-init-service/btle-advise.service b/uds-ble-id-init-service/btle-advise.service
deleted file mode 100644
index 1a34237..0000000
--- a/uds-ble-id-init-service/btle-advise.service
+++ /dev/null
@@ -1,8 +0,0 @@
-[Unit]
-Description=activates advertising of BlueTooth Low-Energy on hci0
-
-[Service]
-Type=oneshot
-ExecStart=/bin/bash -c "rfkill list|sed '/[bB]luetooth/!d;s/:.*//'|xargs -n1 rfkill unblock"
-ExecStart=/bin/bash -c "hcitool dev|tail -n+2|cut -f2|xargs -n1 -IX hciconfig X leadv"
-
diff --git a/uds-ble-id-init-service/btle-advise.timer b/uds-ble-id-init-service/btle-advise.timer
deleted file mode 100644
index b02594c..0000000
--- a/uds-ble-id-init-service/btle-advise.timer
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=Ensure BLE advise is up
-
-[Timer]
-AccuracySec=1min
-OnUnitActiveSec=1min
diff --git a/uds-ble-id-init-service/conf.d/cmake/config.cmake b/uds-ble-id-init-service/conf.d/cmake/config.cmake
deleted file mode 100644
index 4ea1d79..0000000
--- a/uds-ble-id-init-service/conf.d/cmake/config.cmake
+++ /dev/null
@@ -1,201 +0,0 @@
-###########################################################################
-# Copyright 2015, 2016, 2017 IoT.bzh
-#
-# author: Fulup Ar Foll
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-###########################################################################
-
-# Project Info
-# ------------------
-set(PROJECT_NAME uds-ble-id-init)
-set(PROJECT_VERSION "0.1")
-set(PROJECT_PRETTY_NAME "AGL Identitity initiator above BLE's User Data Service")
-set(PROJECT_DESCRIPTION "AGL Identitity initiator above BLE's User Data Service")
-set(PROJECT_URL "https://github.com/iotbzh/aia-binding")
-set(PROJECT_ICON "icon.png")
-set(PROJECT_AUTHOR "José Bollo")
-set(PROJECT_AUTHOR_MAIL "jose.bollo@iot.bzh")
-set(PROJECT_LICENSE "APL2.0")
-set(PROJECT_LANGUAGES,"C")
-
-# Where are stored default templates files from submodule or subtree app-templates in your project tree
-# relative to the root project directory
-set(PROJECT_APP_TEMPLATES_DIR "../conf.d/app-templates")
-
-# Where are stored your external libraries for your project. This is 3rd party library that you don't maintain
-# but used and must be built and linked.
-# set(PROJECT_LIBDIR "libs")
-
-# Where are stored data for your application. Pictures, static resources must be placed in that folder.
-# set(PROJECT_RESOURCES "data")
-
-# Which directories inspect to find CMakeLists.txt target files
-# set(PROJECT_SRC_DIR_PATTERN "*")
-
-# Compilation Mode (DEBUG, RELEASE)
-# ----------------------------------
-
-# Kernel selection if needed. You can choose between a
-# mandatory version to impose a minimal version.
-# Or check Kernel minimal version and just print a Warning
-# about missing features and define a preprocessor variable
-# to be used as preprocessor condition in code to disable
-# incompatibles features. Preprocessor define is named
-# KERNEL_MINIMAL_VERSION_OK.
-#
-# NOTE*** FOR NOW IT CHECKS KERNEL Yocto environment and
-# Yocto SDK Kernel version.
-# -----------------------------------------------
-#set (kernel_mandatory_version 4.8)
-#set (kernel_minimal_version 4.8)
-
-# Compiler selection if needed. Impose a minimal version.
-# -----------------------------------------------
-set (gcc_minimal_version 4.9)
-
-# PKG_CONFIG required packages
-# -----------------------------
-set (PKG_REQUIRED_LIST
- json-c
- libsystemd>=222
- afb-daemon
-)
-
-# Prefix path where will be installed the files
-# Default: /usr/local (need root permission to write in)
-# ------------------------------------------------------
-#set(CMAKE_INSTALL_PREFIX $ENV{HOME}/opt)
-
-# Customize link option
-# -----------------------------
-#list(APPEND link_libraries -an-option)
-
-# Compilation options definition
-# Use CMake generator expressions to specify only for a specific language
-# Values are prefilled with default options that is currently used.
-# Either separate options with ";", or each options must be quoted separately
-# DO NOT PUT ALL OPTION QUOTED AT ONCE , COMPILATION COULD FAILED !
-# ----------------------------------------------------------------------------
-#set(COMPILE_OPTIONS
-# -Wall
-# -Wextra
-# -Wconversion
-# -Wno-unused-parameter
-# -Wno-sign-compare
-# -Wno-sign-conversion
-# -Werror=maybe-uninitialized
-# -Werror=implicit-function-declaration
-# -ffunction-sections
-# -fdata-sections
-# -fPIC
-# CACHE STRING "Compilation flags")
-#set(C_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C language.")
-#set(CXX_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C++ language.")
-#set(PROFILING_COMPILE_OPTIONS
-# -g
-# -O0
-# -pg
-# -Wp,-U_FORTIFY_SOURCE
-# CACHE STRING "Compilation flags for PROFILING build type.")
-#set(DEBUG_COMPILE_OPTIONS
-# -g
-# -ggdb
-# -Wp,-U_FORTIFY_SOURCE
-# CACHE STRING "Compilation flags for DEBUG build type.")
-#set(CCOV_COMPILE_OPTIONS
-# -g
-# -O2
-# --coverage
-# CACHE STRING "Compilation flags for CCOV build type.")
-#set(RELEASE_COMPILE_OPTIONS
-# -g
-# -O2
-# CACHE STRING "Compilation flags for RELEASE build type.")
-
-# (BUG!!!) as PKG_CONFIG_PATH does not work [should be an env variable]
-# ---------------------------------------------------------------------
-set(CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}/lib64/pkgconfig ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
-set(LD_LIBRARY_PATH ${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib)
-
-# Optional location for config.xml.in
-# -----------------------------------
-#set(WIDGET_ICON conf.d/wgt/${PROJECT_ICON} CACHE PATH "Path to the widget icon")
-set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in CACHE PATH "Path to widget config file template (config.xml.in)")
-
-# Mandatory widget Mimetype specification of the main unit
-# --------------------------------------------------------------------------
-# Choose between :
-#- text/html : HTML application,
-# content.src designates the home page of the application
-#
-#- application/vnd.agl.native : AGL compatible native,
-# content.src designates the relative path of the binary.
-#
-# - application/vnd.agl.service: AGL service, content.src is not used.
-#
-#- ***application/x-executable***: Native application,
-# content.src designates the relative path of the binary.
-# For such application, only security setup is made.
-#
-set(WIDGET_TYPE application/vnd.agl.service)
-
-# Mandatory Widget entry point file of the main unit
-# --------------------------------------------------------------
-# This is the file that will be executed, loaded,
-# at launch time by the application framework.
-#
-set(WIDGET_ENTRY_POINT irrelevant)
-
-# Optional dependencies order
-# ---------------------------
-#set(EXTRA_DEPENDENCIES_ORDER)
-
-# Optional Extra global include path
-# -----------------------------------
-#set(EXTRA_INCLUDE_DIRS)
-
-# Optional extra libraries
-# -------------------------
-#set(EXTRA_LINK_LIBRARIES)
-
-# Optional force binding Linking flag
-# ------------------------------------
-# set(BINDINGS_LINK_FLAG LinkOptions )
-
-# Optional force package prefix generation, like widget
-# -----------------------------------------------------
-# set(PKG_PREFIX DestinationPath)
-
-# Optional Application Framework security token
-# and port use for remote debugging.
-#------------------------------------------------------------
-set(AFB_TOKEN "" CACHE PATH "Default binder security token")
-set(AFB_REMPORT "1234" CACHE PATH "Default binder listening port")
-
-# Print a helper message when every thing is finished
-# ----------------------------------------------------
-set(CLOSING_MESSAGE "Typical binding launch: afb-daemon --port=${AFB_REMPORT} --workdir=${CMAKE_BINARY_DIR}/package --ldpaths=lib --roothttp=htdocs --token=\"${AFB_TOKEN}\" --tracereq=common --verbose")
-set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt")
-
-# Optional schema validator about now only XML, LUA and JSON
-# are supported
-#------------------------------------------------------------
-#set(LUA_CHECKER "luac" "-p" CACHE STRING "LUA compiler")
-#set(XML_CHECKER "xmllint" CACHE STRING "XML linter")
-#set(JSON_CHECKER "json_verify" CACHE STRING "JSON linter")
-
-# This include is mandatory and MUST happens at the end
-# of this file, else you expose you to unexpected behavior
-# -----------------------------------------------------------
-include(${PROJECT_APP_TEMPLATES_DIR}/cmake/common.cmake)
diff --git a/uds-ble-id-init-service/conf.d/wgt/config.xml.in b/uds-ble-id-init-service/conf.d/wgt/config.xml.in
deleted file mode 100644
index 0ccd9b5..0000000
--- a/uds-ble-id-init-service/conf.d/wgt/config.xml.in
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- @PROJECT_NAME@
-
-
- @PROJECT_DESCRIPTION@
- @PROJECT_AUTHOR@ <@PROJECT_AUTHOR_MAIL@>
- @PROJECT_LICENSE@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/uds-ble-id-init-service/src/CMakeLists.txt b/uds-ble-id-init-service/src/CMakeLists.txt
deleted file mode 100644
index 97e229a..0000000
--- a/uds-ble-id-init-service/src/CMakeLists.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-###########################################################################
-# Copyright 2017 IoT.bzh
-#
-# author: Jose Bollo
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-###########################################################################
-
-PROJECT_TARGET_ADD(afb-uds-ble-id-init-binding)
-
-add_library(afb-uds-ble-id-init-binding MODULE
- uds-ble-id-init-service.c
- aia-uds-bluez.c
-)
-
-set_target_properties(afb-uds-ble-id-init-binding PROPERTIES
- LABELS "BINDING"
- PREFIX ""
- COMPILE_FLAGS "${libsystemd_CFLAGS}"
- INCLUDE_DIRECTORIES "${libsystemd_INCLUDE_DIRS}"
- LINK_FLAGS "${BINDINGS_LINK_FLAG}"
- LINK_LIBRARIES "${libsystemd_LIBRARIES}"
- OUTPUT_NAME "${TARGET_NAME}"
-)
-
diff --git a/uds-ble-id-init-service/src/aia-uds-bluez.c b/uds-ble-id-init-service/src/aia-uds-bluez.c
deleted file mode 100644
index 35ba61d..0000000
--- a/uds-ble-id-init-service/src/aia-uds-bluez.c
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-
-#include
-#include
-#include
-#include
-
-#include
-
-#include "aia-uds-bluez.h"
-
-#define ROOT "/uds"
-
-#define ITF_SERVICE "org.bluez.GattService1"
-#define ITF_CHARACTERISTIC "org.bluez.GattCharacteristic1"
-#define ITF_DESCRIPTOR "org.bluez.GattDescriptor1"
-
-/****** internal types **********/
-
-struct item
-{
- const char *uuid;
- const char *path;
- struct item *parent;
- struct aia_uds_value *value;
-};
-
-/****** internal data **********/
-
-static sd_bus *busini;
-static int activation;
-
-static aia_uds_on_change on_change_callback;
-
-static struct aia_uds uds;
-
-static struct aia_uds uds_descs =
-{
- .first_name = { .data = "First name of the user" },
- .last_name = { .data = "Last name of the user" },
- .email = { .data = "Email of the user" },
- .language = { .data = "The Language definition is based on ISO639-1" }
-};
-
-static struct aia_uds_value woutf8 = { .data = "\031\000\047\000\001\000\000", .length = 7 };
-
-static struct item services[1] =
-{
- {
- .uuid = "0000181C-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0"
- }
-};
-
-static struct item characteristics[4] =
-{
- {
- .uuid = "00002A8A-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char0",
- .parent = &services[0],
- .value = &uds.first_name
- }, {
- .uuid = "00002A90-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char1",
- .parent = &services[0],
- .value = &uds.last_name
- }, {
- .uuid = "00002A87-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char2",
- .parent = &services[0],
- .value = &uds.email
- }, {
- .uuid = "00002AA2-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char3",
- .parent = &services[0],
- .value = &uds.language
- }
-};
-
-static struct item descriptors[8] =
-{
- {
- .uuid = "00002901-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char0/desc0",
- .parent = &characteristics[0],
- .value = &uds_descs.first_name
- }, {
- .uuid = "00002904-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char0/desc1",
- .parent = &characteristics[0],
- .value = &woutf8
- }, {
- .uuid = "00002901-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char1/desc0",
- .parent = &characteristics[1],
- .value = &uds_descs.last_name
- }, {
- .uuid = "00002904-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char1/desc1",
- .parent = &characteristics[1],
- .value = &woutf8
- }, {
- .uuid = "00002901-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char2/desc0",
- .parent = &characteristics[2],
- .value = &uds_descs.email
- }, {
- .uuid = "00002904-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char2/desc1",
- .parent = &characteristics[2],
- .value = &woutf8
- }, {
- .uuid = "00002901-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char3/desc0",
- .parent = &characteristics[3],
- .value = &uds_descs.language
- }, {
- .uuid = "00002904-0000-1000-8000-00805f9b34fb",
- .path = ROOT"/service0/char3/desc1",
- .parent = &characteristics[3],
- .value = &woutf8
- }
-};
-
-/****** utility ***********/
-
-static uint16_t get_offset(sd_bus_message *m)
-{
- uint16_t offset;
- const char *key;
-
- if (0 < sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) {
- while (sd_bus_message_read_basic(m, 's', &key) > 0) {
- if (strcmp(key,"offset"))
- sd_bus_message_skip(m, "v");
- else {
- if (sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "q")) {
- sd_bus_message_read_basic(m, 'q', &offset);
- sd_bus_message_exit_container(m);
- return offset;
- }
- }
- }
- sd_bus_message_exit_container(m);
- }
- return 0;
-}
-
-static int message_append_strings(sd_bus_message *m, const char **s)
-{
- int rc = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "s");
- while (rc >= 0 && *s)
- rc = sd_bus_message_append_basic(m, 's', *s++);
- if (rc >= 0)
- rc = sd_bus_message_close_container(m);
- return rc;
-}
-
-/****** common callbacks ***********/
-
-static int get_uuid(
- struct sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error)
-{
- struct item *item = userdata;
- return sd_bus_message_append_basic(reply, 's', item->uuid);
-}
-
-static int get_parent(
- struct sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error)
-{
- struct item *item = userdata;
- return sd_bus_message_append_basic(reply, 'o', item->parent->path);
-}
-
-static int get_children(
- struct sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error)
-{
- size_t i, n;
- int rc;
-
- rc = sd_bus_message_open_container(reply, SD_BUS_TYPE_ARRAY, "o");
- n = sizeof characteristics / sizeof *characteristics;
- i = 0;
- while (rc >= 0 && i < n) {
- if (characteristics[i].parent == userdata)
- rc = sd_bus_message_append_basic(reply, 'o', characteristics[i].path);
- i++;
- }
- n = sizeof descriptors / sizeof *descriptors;
- i = 0;
- while (rc >= 0 && i < n) {
- if (descriptors[i].parent == userdata)
- rc = sd_bus_message_append_basic(reply, 'o', descriptors[i].path);
- i++;
- }
- if (rc >= 0)
- rc = sd_bus_message_close_container(reply);
- return rc;
-}
-
-static int read_value_offset(
- struct item *item,
- size_t offset,
- sd_bus_message *reply)
-{
- struct aia_uds_value *value = item->value;
- const char *data = value ? value->data : NULL;
- size_t size = !value ? 0 : value->length ? value->length : data ? strlen(data) : 0;
- return sd_bus_message_append_array(reply, 'y', &data[offset], offset > size ? 0 : size - offset);
-}
-
-static int read_value(
- sd_bus_message *m,
- void *userdata,
- sd_bus_error *ret_error)
-{
- int rc;
- sd_bus_message *r;
-
- rc = sd_bus_message_new_method_return(m, &r);
- rc = read_value_offset(userdata, get_offset(m), r);
- rc = sd_bus_send(NULL, r, NULL);
- return 1;
-}
-
-static int write_value_offset(
- struct item *item,
- size_t offset,
- const char *buffer,
- size_t length)
-{
- struct aia_uds_value *value = item->value;
- const char *data = value ? value->data : NULL;
- size_t size = !value ? 0 : value->length ? value->length : data ? strlen(data) : 0;
-
-
- char *next = malloc(offset + length + 1);
- if (!next)
- return -ENOMEM;
- if (offset) {
- if (size >= offset)
- memcpy(next, data, offset);
- else {
- memcpy(next, data, size);
- memset(&next[size], 0, offset - size);
- }
- }
- memcpy(&next[offset], buffer, length);
- next[offset + length] = 0;
- value->data = next;
- value->length = offset + length;
- free((char*)data);
-
- return 0;
-}
-
-static int write_value(
- sd_bus_message *m,
- void *userdata,
- sd_bus_error *ret_error)
-{
- int rc;
- struct item *item = userdata;
- const void *data;
- size_t size;
- sd_bus_message *r;
-
- rc = sd_bus_message_read_array(m, 'y', &data, &size);
- rc = write_value_offset(item, get_offset(m), data, size);
-
- rc = sd_bus_message_new_method_return(m, &r);
- rc = sd_bus_send(NULL, r, NULL);
-
- sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), item->path, ITF_CHARACTERISTIC, "Value", NULL);
-
- if (on_change_callback) {
- item->value->changed = 1;
- on_change_callback(&uds);
- item->value->changed = 0;
- }
-
- return 1;
-}
-
-static int get_value(
- struct sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error)
-{
- return read_value_offset(userdata, 0, reply);
-}
-
-static int get_true(
- struct sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error)
-{
- int v = 1;
- return sd_bus_message_append_basic(reply, 'b', &v);
-}
-
-static int get_false(
- struct sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error)
-{
- int v = 0;
- return sd_bus_message_append_basic(reply, 'b', &v);
-}
-
-static int not_supported(
- sd_bus_message *m,
- void *userdata,
- sd_bus_error *ret_error)
-{
- return sd_bus_reply_method_errorf(m, "org.bluez.Error.NotSupported", "not supported");
-}
-
-static int not_permitted(
- sd_bus_message *m,
- void *userdata,
- sd_bus_error *ret_error)
-{
- return sd_bus_reply_method_errorf(m, "org.bluez.Error.NotPermitted", "not permitted");
-}
-
-static int failed(
- sd_bus_message *m,
- void *userdata,
- sd_bus_error *ret_error)
-{
- return sd_bus_reply_method_errorf(m, "org.bluez.Error.Failed", "failed");
-}
-
-/****** service's callbacks ***********/
-
-static int get_srv_includes(
- struct sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error)
-{
- int rc = sd_bus_message_open_container(reply, SD_BUS_TYPE_ARRAY, "o");
- if (rc >= 0)
- rc = sd_bus_message_close_container(reply);
- return rc;
-}
-
-/****** characteristic's callbacks ***********/
-
-static int get_char_flags(
- struct sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error)
-{
- static const char *flags[] = { "read", "write", NULL };
- return message_append_strings(reply, flags);
-}
-
-/****** descriptor's callbacks ***********/
-
-static int get_desc_flags(
- struct sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error)
-{
- static const char *flags[] = { "read", NULL };
- return message_append_strings(reply, flags);
-}
-
-/****** description ***********/
-
-static struct sd_bus_vtable vservice[] = {
- SD_BUS_VTABLE_START(0),
-
- SD_BUS_PROPERTY("UUID", "s", get_uuid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Primary", "b", get_true, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Includes", "ao", get_srv_includes, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Characteristics", "ao", get_children, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-
- SD_BUS_VTABLE_END
-};
-
-
-static struct sd_bus_vtable vcharacteristic[] = {
- SD_BUS_VTABLE_START(0),
-
- SD_BUS_METHOD("ReadValue", "a{sv}", "ay", read_value, 0),
- SD_BUS_METHOD("WriteValue", "aya{sv}", "", write_value, 0),
- SD_BUS_METHOD("StartNotify", "", "", not_supported, 0),
- SD_BUS_METHOD("StopNotify", "", "", failed, 0),
-
- SD_BUS_PROPERTY("UUID", "s", get_uuid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Service", "o", get_parent, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Value", "ay", get_value, 0, 0),
- SD_BUS_PROPERTY("WriteAcquired", "b", get_false, 0, 0),
- SD_BUS_PROPERTY("NotifyAcquired", "b", get_false, 0, 0),
- SD_BUS_PROPERTY("Notifying", "b", get_false, 0, 0),
- SD_BUS_PROPERTY("Flags", "as", get_char_flags, 0, 0),
- SD_BUS_PROPERTY("Descriptors", "ao", get_children, 0, 0),
-
- SD_BUS_VTABLE_END
-};
-
-
-static struct sd_bus_vtable vdescriptor[] = {
- SD_BUS_VTABLE_START(0),
-
- SD_BUS_METHOD("ReadValue", "a{sv}", "ay", read_value, 0),
- SD_BUS_METHOD("WriteValue", "aya{sv}", "", not_permitted, 0),
-
- SD_BUS_PROPERTY("UUID", "s", get_uuid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Characteristic", "o", get_parent, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Value", "ay", get_value, 0, 0),
- SD_BUS_PROPERTY("Flags", "as", get_desc_flags, 0, 0),
-
- SD_BUS_VTABLE_END
-};
-
-
-/******** Integration ***************/
-
-aia_uds_on_change aia_uds_set_on_change(aia_uds_on_change callback)
-{
- aia_uds_on_change prev = on_change_callback;
- on_change_callback = callback;
- return prev;
-}
-
-int aia_uds_init(struct sd_bus *bus)
-{
- int rc;
-
- if (busini)
- return 0;
-
- rc = sd_bus_add_object_manager(bus, NULL, ROOT);
-
- rc = sd_bus_add_object_vtable(bus, NULL, services[0].path,
- ITF_SERVICE, vservice, &services[0]);
-
- rc = sd_bus_add_object_vtable(bus, NULL, characteristics[0].path,
- ITF_CHARACTERISTIC, vcharacteristic, &characteristics[0]);
- rc = sd_bus_add_object_vtable(bus, NULL, characteristics[1].path,
- ITF_CHARACTERISTIC, vcharacteristic, &characteristics[1]);
- rc = sd_bus_add_object_vtable(bus, NULL, characteristics[2].path,
- ITF_CHARACTERISTIC, vcharacteristic, &characteristics[2]);
- rc = sd_bus_add_object_vtable(bus, NULL, characteristics[3].path,
- ITF_CHARACTERISTIC, vcharacteristic, &characteristics[3]);
-
- rc = sd_bus_add_object_vtable(bus, NULL, descriptors[0].path,
- ITF_DESCRIPTOR, vdescriptor, &descriptors[0]);
- rc = sd_bus_add_object_vtable(bus, NULL, descriptors[1].path,
- ITF_DESCRIPTOR, vdescriptor, &descriptors[1]);
- rc = sd_bus_add_object_vtable(bus, NULL, descriptors[2].path,
- ITF_DESCRIPTOR, vdescriptor, &descriptors[2]);
- rc = sd_bus_add_object_vtable(bus, NULL, descriptors[3].path,
- ITF_DESCRIPTOR, vdescriptor, &descriptors[3]);
- rc = sd_bus_add_object_vtable(bus, NULL, descriptors[4].path,
- ITF_DESCRIPTOR, vdescriptor, &descriptors[4]);
- rc = sd_bus_add_object_vtable(bus, NULL, descriptors[5].path,
- ITF_DESCRIPTOR, vdescriptor, &descriptors[5]);
- rc = sd_bus_add_object_vtable(bus, NULL, descriptors[6].path,
- ITF_DESCRIPTOR, vdescriptor, &descriptors[6]);
- rc = sd_bus_add_object_vtable(bus, NULL, descriptors[7].path,
- ITF_DESCRIPTOR, vdescriptor, &descriptors[7]);
-
- busini = sd_bus_ref(bus);
- return 0;
-}
-
-struct cb {
- void *callback;
- void *closure;
- int onoff;
-};
-
-static struct cb *alloccb(void *callback, void *closure, int onoff)
-{
- struct cb *cb = malloc(sizeof *cb);
- if (cb) {
- cb->callback = callback;
- cb->closure = closure;
- }
- return cb;
-}
-
-static int register_uds_cb(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
-{
- struct cb *cb = userdata;
- void (*callback)(void *closure, int error, int state);
- int iserr;
-
- iserr = sd_bus_message_is_method_error(m, NULL);
- if (!iserr)
- activation = cb->onoff;
- callback = cb->callback;
- if (callback)
- callback(cb->closure, iserr, activation);
- free(cb);
-
- return 1;
-}
-
-static int register_uds(int onoff, void *data)
-{
- int rc;
- sd_bus_message *m;
-
- rc = sd_bus_message_new_method_call(busini, &m, "org.bluez",
- "/org/bluez/hci0", "org.bluez.GattManager1",
- onoff ? "RegisterApplication" : "UnregisterApplication" );
- rc = sd_bus_message_append_basic(m, 'o', ROOT);
- if (onoff) {
- rc = sd_bus_message_open_container(m, 'a', "{sv}");
- rc = sd_bus_message_close_container(m);
- }
- rc = sd_bus_call_async(busini, NULL, m, register_uds_cb, data, 5*1000*1000);
- sd_bus_message_unref(m);
- return rc;
-}
-
-int aia_uds_activate(int onoff, void (*callback)(void *closure, int error, int state), void *closure)
-{
- int rc;
- struct cb *cb;
-
- if (!busini)
- return -EINVAL;
-
- onoff = !!onoff;
- if (activation == onoff)
- return 0;
-
- cb = alloccb(callback, closure, onoff);
- if (!cb)
- return -ENOMEM;
-
- rc = register_uds(onoff, cb);
- if (rc < 0)
- free(cb);
-
- return rc < 0 ? rc : 1;
-}
-
-int aia_uds_advise(int onoff, void (*callback)(void *closure, int error, int state), void *closure)
-{
- return aia_uds_activate(onoff, callback, closure);
-}
-
diff --git a/uds-ble-id-init-service/src/aia-uds-bluez.h b/uds-ble-id-init-service/src/aia-uds-bluez.h
deleted file mode 100644
index 856da4e..0000000
--- a/uds-ble-id-init-service/src/aia-uds-bluez.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-
-
-#pragma once
-
-struct aia_uds_value
-{
- const char *data;
- size_t length;
- int changed;
-};
-
-struct aia_uds
-{
- struct aia_uds_value first_name;
- struct aia_uds_value last_name;
- struct aia_uds_value email;
- struct aia_uds_value language;
-};
-
-typedef void (*aia_uds_on_change)(const struct aia_uds *);
-
-extern aia_uds_on_change aia_uds_set_on_change(aia_uds_on_change callback);
-
-extern int aia_uds_activate(int onoff, void (*callback)(void *closure, int error, int state), void *closure);
-
-extern int aia_uds_advise(int onoff, void (*callback)(void *closure, int error, int state), void *closure);
-
-extern int aia_uds_init(struct sd_bus *bus);
-
diff --git a/uds-ble-id-init-service/src/uds-ble-id-init-service.c b/uds-ble-id-init-service/src/uds-ble-id-init-service.c
deleted file mode 100644
index f887963..0000000
--- a/uds-ble-id-init-service/src/uds-ble-id-init-service.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
- * Author: José Bollo
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#define AFB_BINDING_VERSION 2
-#include
-
-#include "aia-uds-bluez.h"
-
-#if !defined(AUTO_START_ADVISE)
-#define AUTO_START_ADVISE 1
-#endif
-
-static int advising;
-
-static struct afb_event event;
-
-static int autoadvise = AUTO_START_ADVISE;
-
-/****************************************************************/
-
-static void on_uds_change(const struct aia_uds *uds)
-{
- struct json_object *object;
-
- AFB_INFO("UDS changed"
- " first-name%s[%.*s]"
- " last-name%s[%.*s]"
- " email%s[%.*s]"
- " language%s[%.*s]",
- uds->first_name.changed ? "*" : "", (int)uds->first_name.length, uds->first_name.data ?:"",
- uds->last_name.changed ? "*" : "", (int)uds->last_name.length, uds->last_name.data ?:"",
- uds->email.changed ? "*" : "", (int)uds->email.length, uds->email.data ?:"",
- uds->language.changed ? "*" : "", (int)uds->language.length, uds->language.data ?:"");
-
- if (uds->email.changed) {
- object = json_object_new_object();
- json_object_object_add(object, "incoming", json_object_new_string(uds->email.data));
- afb_event_push(event, object);
- }
-}
-
-static void start (struct afb_req request)
-{
- int rc;
-
- if (!advising) {
- rc = aia_uds_advise(1, NULL, NULL);
- if (rc < 0) {
-/*
-TODO: solve the issue
- afb_req_fail(request, "failed", "start scan failed");
- return;
-*/
- AFB_ERROR("Ignoring scan start failed, because probably already in progress");
- }
- }
- advising = advising + 1;
- afb_req_subscribe(request, event);
- afb_req_success(request, NULL, NULL);
-}
-
-
-static void stop (struct afb_req request)
-{
- if (advising) {
- advising = advising - 1;
- if (!advising)
- aia_uds_advise(0, NULL, NULL);
- }
- afb_req_success(request, NULL, NULL);
-}
-
-static int init()
-{
- sd_bus *bus;
- int rc;
-
- bus = afb_daemon_get_system_bus();
- rc = bus ? aia_uds_init(bus) : -ENOTSUP;
- if (rc < 0) {
- errno = -rc;
- return -1;
- }
-
- aia_uds_set_on_change(on_uds_change);
-
- event = afb_daemon_make_event("event");
- if (!afb_event_is_valid(event))
- return -1;
-
- rc = aia_uds_advise(autoadvise, NULL, NULL);
- advising = autoadvise && rc >= 0;
- return rc < 0 ? rc : 0;
-}
-
-
-// NOTE: this sample does not use session to keep test a basic as possible
-// in real application most APIs should be protected with AFB_SESSION_CHECK
-static const struct afb_verb_v2 verbs[]=
-{
- {"start" , start, NULL, "start User Data Service", AFB_SESSION_NONE },
- {"stop" , stop , NULL, "stop User Data Service" , AFB_SESSION_NONE },
- {NULL}
-};
-
-const struct afb_binding_v2 afbBindingV2 =
-{
- .api = "uds-ble-init-id",
- .specification = NULL,
- .info = "AGL Identitity initiator above BLE's User Data Service",
- .verbs = verbs,
- .preinit = NULL,
- .init = init,
- .onevent = NULL,
- .noconcurrency = 1
-};
-
-/* vim: set colorcolumn=80: */
-
--
cgit 1.2.3-korg