mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
243 lines
6.3 KiB
Lua
243 lines
6.3 KiB
Lua
-- vim:sts=4 sw=4
|
|
|
|
-- Metronome IM
|
|
-- Copyright (C) 2008-2010 Matthew Wild
|
|
-- Copyright (C) 2008-2010 Waqas Hussain
|
|
-- Copyright (C) 2012 Rob Hoelz
|
|
-- Copyright (C) 2015 YUNOHOST.ORG
|
|
--
|
|
-- This project is MIT/X11 licensed. Please see the
|
|
-- COPYING file in the source package for more information.
|
|
|
|
----------------------------------------
|
|
-- Constants and such --
|
|
----------------------------------------
|
|
|
|
local setmetatable = setmetatable;
|
|
|
|
local get_config = require "core.configmanager".get;
|
|
local ldap = module:require 'ldap';
|
|
local vcardlib = module:require 'vcard';
|
|
local st = require 'util.stanza';
|
|
local gettime = require 'socket'.gettime;
|
|
|
|
local log = module._log
|
|
|
|
if not ldap then
|
|
return;
|
|
end
|
|
|
|
local CACHE_EXPIRY = 300;
|
|
|
|
----------------------------------------
|
|
-- Utility Functions --
|
|
----------------------------------------
|
|
|
|
local function ldap_record_to_vcard(record, format)
|
|
return vcardlib.create {
|
|
record = record,
|
|
format = format,
|
|
}
|
|
end
|
|
|
|
local get_alias_for_user;
|
|
|
|
do
|
|
local user_cache;
|
|
local last_fetch_time;
|
|
|
|
local function populate_user_cache()
|
|
local user_c = get_config(module.host, 'ldap').user;
|
|
if not user_c then return; end
|
|
|
|
local ld = ldap.getconnection();
|
|
|
|
local usernamefield = user_c.usernamefield;
|
|
local namefield = user_c.namefield;
|
|
|
|
user_cache = {};
|
|
|
|
for _, attrs in ld:search { base = user_c.basedn, scope = 'onelevel', filter = user_c.filter } do
|
|
user_cache[attrs[usernamefield]] = attrs[namefield];
|
|
end
|
|
last_fetch_time = gettime();
|
|
end
|
|
|
|
function get_alias_for_user(user)
|
|
if last_fetch_time and last_fetch_time + CACHE_EXPIRY < gettime() then
|
|
user_cache = nil;
|
|
end
|
|
if not user_cache then
|
|
populate_user_cache();
|
|
end
|
|
return user_cache[user];
|
|
end
|
|
end
|
|
|
|
----------------------------------------
|
|
-- Base LDAP store class --
|
|
----------------------------------------
|
|
|
|
local function ldap_store(config)
|
|
local self = {};
|
|
local config = config;
|
|
|
|
function self:get(username)
|
|
return nil, "Data getting is not available for this storage backend";
|
|
end
|
|
|
|
function self:set(username, data)
|
|
return nil, "Data setting is not available for this storage backend";
|
|
end
|
|
|
|
return self;
|
|
end
|
|
|
|
local adapters = {};
|
|
|
|
----------------------------------------
|
|
-- Roster Storage Implementation --
|
|
----------------------------------------
|
|
|
|
adapters.roster = function (config)
|
|
-- Validate configuration requirements
|
|
if not config.groups then return nil; end
|
|
|
|
local self = ldap_store(config)
|
|
|
|
function self:get(username)
|
|
local ld = ldap.getconnection();
|
|
local contacts = {};
|
|
|
|
local memberfield = config.groups.memberfield;
|
|
local namefield = config.groups.namefield;
|
|
local filter = memberfield .. '=' .. tostring(username);
|
|
|
|
local groups = {};
|
|
for _, config in ipairs(config.groups) do
|
|
groups[ config[namefield] ] = config.name;
|
|
end
|
|
|
|
log("debug", "Found %d group(s) for user %s", select('#', groups), username)
|
|
|
|
-- XXX this kind of relies on the way we do groups at INOC
|
|
for _, attrs in ld:search { base = config.groups.basedn, scope = 'onelevel', filter = filter } do
|
|
if groups[ attrs[namefield] ] then
|
|
local members = attrs[memberfield];
|
|
|
|
for _, user in ipairs(members) do
|
|
if user ~= username then
|
|
local jid = user .. '@' .. module.host;
|
|
local record = contacts[jid];
|
|
|
|
if not record then
|
|
record = {
|
|
subscription = 'both',
|
|
groups = {},
|
|
name = get_alias_for_user(user),
|
|
};
|
|
contacts[jid] = record;
|
|
end
|
|
|
|
record.groups[ groups[ attrs[namefield] ] ] = true;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return contacts;
|
|
end
|
|
|
|
function self:set(username, data)
|
|
log("warn", "Setting data in Roster LDAP storage is not supported yet")
|
|
return nil, "not supported";
|
|
end
|
|
|
|
return self;
|
|
end
|
|
|
|
----------------------------------------
|
|
-- vCard Storage Implementation --
|
|
----------------------------------------
|
|
|
|
adapters.vcard = function (config)
|
|
-- Validate configuration requirements
|
|
if not config.vcard_format or not config.user then return nil; end
|
|
|
|
local self = ldap_store(config)
|
|
|
|
function self:get(username)
|
|
local ld = ldap.getconnection();
|
|
local filter = config.user.usernamefield .. '=' .. tostring(username);
|
|
|
|
log("debug", "Retrieving vCard for user '%s'", username);
|
|
|
|
local match = ldap.singlematch {
|
|
base = config.user.basedn,
|
|
filter = filter,
|
|
};
|
|
if match then
|
|
match.jid = username .. '@' .. module.host
|
|
return st.preserialize(ldap_record_to_vcard(match, config.vcard_format));
|
|
else
|
|
return nil, "username not found";
|
|
end
|
|
end
|
|
|
|
function self:set(username, data)
|
|
log("warn", "Setting data in vCard LDAP storage is not supported yet")
|
|
return nil, "not supported";
|
|
end
|
|
|
|
return self;
|
|
end
|
|
|
|
----------------------------------------
|
|
-- Driver Definition --
|
|
----------------------------------------
|
|
|
|
cache = {};
|
|
|
|
local driver = { name = "ldap" };
|
|
|
|
function driver:open(store)
|
|
log("debug", "Opening ldap storage backend for host '%s' and store '%s'", module.host, store);
|
|
|
|
if not cache[module.host] then
|
|
log("debug", "Caching adapters for the host '%s'", module.host);
|
|
|
|
local ad_config = get_config(module.host, "ldap");
|
|
local ad_cache = {};
|
|
for k, v in pairs(adapters) do
|
|
ad_cache[k] = v(ad_config);
|
|
end
|
|
|
|
cache[module.host] = ad_cache;
|
|
end
|
|
|
|
local adapter = cache[module.host][store];
|
|
|
|
if not adapter then
|
|
log("info", "Unavailable adapter for store '%s'", store);
|
|
return nil, "unsupported-store";
|
|
end
|
|
return adapter;
|
|
end
|
|
|
|
function driver:stores(username, type, pattern)
|
|
return nil, "not implemented";
|
|
end
|
|
|
|
function driver:store_exists(username, datastore, type)
|
|
return nil, "not implemented";
|
|
end
|
|
|
|
function driver:purge(username)
|
|
return nil, "not implemented";
|
|
end
|
|
|
|
function driver:users()
|
|
return nil, "not implemented";
|
|
end
|
|
|
|
module:add_item("data-driver", driver);
|