LDAP & Samba synchronization fixes + improvements
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
parent
5e5dcf26c6
commit
9b563cb8bf
|
@ -9,7 +9,7 @@
|
|||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
"id": true
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
|
@ -56,7 +56,8 @@
|
|||
"roles": {
|
||||
"type": "hasMany",
|
||||
"model": "RoleRole",
|
||||
"foreignKey": "role"
|
||||
"foreignKey": "role",
|
||||
"primaryKey": "roleFk"
|
||||
},
|
||||
"emailUser": {
|
||||
"type": "hasOne",
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE `account`.`roleRole`
|
||||
ADD `id` INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
|
||||
ADD PRIMARY KEY (`id`);
|
File diff suppressed because it is too large
Load Diff
|
@ -62,31 +62,27 @@ module.exports = Self => {
|
|||
let roles = await $.Role.find({
|
||||
fields: ['id', 'name']
|
||||
});
|
||||
let roleRoles = await $.RoleRole.find({
|
||||
fields: ['role', 'inheritsFrom']
|
||||
});
|
||||
let roleMap = toMap(roleRoles, e => {
|
||||
return {key: e.inheritsFrom, val: e.role};
|
||||
});
|
||||
|
||||
let accounts = await $.UserAccount.find({
|
||||
fields: ['id'],
|
||||
include: {
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['name'],
|
||||
include: {
|
||||
relation: 'roles',
|
||||
scope: {
|
||||
fields: ['inheritsFrom']
|
||||
}
|
||||
}
|
||||
fields: ['name', 'roleFk'],
|
||||
where: {active: true}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let map = new Map();
|
||||
for (let account of accounts) {
|
||||
let user = account.user();
|
||||
for (let inherit of user.roles()) {
|
||||
let roleId = inherit.inheritsFrom;
|
||||
if (!map.has(roleId)) map.set(roleId, []);
|
||||
map.get(roleId).push(user.name);
|
||||
}
|
||||
}
|
||||
let accountMap = toMap(accounts, e => {
|
||||
let user = e.user();
|
||||
return {key: user.roleFk, val: user.name};
|
||||
});
|
||||
|
||||
reqs = [];
|
||||
for (let role of roles) {
|
||||
|
@ -96,8 +92,14 @@ module.exports = Self => {
|
|||
gidNumber: accountConfig.idBase + role.id
|
||||
};
|
||||
|
||||
let memberUid = map.get(role.id);
|
||||
if (memberUid) newEntry.memberUid = memberUid;
|
||||
let memberUid = [];
|
||||
for (subrole of roleMap.get(role.id) || [])
|
||||
memberUid = memberUid.concat(accountMap.get(subrole) || []);
|
||||
|
||||
if (memberUid.length) {
|
||||
memberUid.sort((a, b) => a.localeCompare(b));
|
||||
newEntry.memberUid = memberUid;
|
||||
}
|
||||
|
||||
let dn = `cn=${role.name},${ldapConfig.groupDn}`;
|
||||
reqs.push(client.add(dn, newEntry));
|
||||
|
@ -112,3 +114,14 @@ module.exports = Self => {
|
|||
if (err) throw err;
|
||||
};
|
||||
};
|
||||
|
||||
function toMap(array, fn) {
|
||||
let map = new Map();
|
||||
for (let item of array) {
|
||||
let keyVal = fn(item);
|
||||
let key = keyVal.key;
|
||||
if (!map.has(key)) map.set(key, []);
|
||||
map.get(key).push(keyVal.val);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
const ldap = require('../../util/ldapjs-extra');
|
||||
const ssh = require('node-ssh');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('syncAll', {
|
||||
description: 'Synchronizes user database with LDAP and Samba',
|
||||
http: {
|
||||
path: `/syncAll`,
|
||||
verb: 'PATCH'
|
||||
}
|
||||
});
|
||||
|
||||
Self.syncAll = async function() {
|
||||
let $ = Self.app.models;
|
||||
let usersToSync = new Set();
|
||||
|
||||
// Database
|
||||
|
||||
let accounts = await $.UserAccount.find({
|
||||
fields: ['id'],
|
||||
include: {
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['name'],
|
||||
where: {active: true}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (let account of accounts)
|
||||
usersToSync.add(account.user().name);
|
||||
|
||||
// LDAP
|
||||
|
||||
let ldapConfig = await $.LdapConfig.findOne({
|
||||
fields: ['host', 'rdn', 'password', 'baseDn']
|
||||
});
|
||||
|
||||
if (ldapConfig) {
|
||||
let ldapClient = ldap.createClient({
|
||||
url: `ldap://${ldapConfig.host}:389`
|
||||
});
|
||||
|
||||
let ldapPassword = Buffer
|
||||
.from(ldapConfig.password, 'base64')
|
||||
.toString('ascii');
|
||||
await ldapClient.bind(ldapConfig.rdn, ldapPassword);
|
||||
|
||||
res = await ldapClient.search(ldapConfig.baseDn, {
|
||||
scope: 'sub',
|
||||
attributes: ['uid'],
|
||||
filter: `uid=*`
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
res.on('error', reject);
|
||||
res.on('searchEntry', e => usersToSync.add(e.object.uid));
|
||||
res.on('end', resolve);
|
||||
});
|
||||
|
||||
// FIXME: Cannot disconnect, hangs on undind() call
|
||||
// await ldapClient.unbind();
|
||||
}
|
||||
|
||||
// Samba
|
||||
|
||||
let sambaConfig = await $.SambaConfig.findOne({
|
||||
fields: ['host', 'sshUser', 'sshPass']
|
||||
});
|
||||
|
||||
if (sambaConfig) {
|
||||
let sshPassword = Buffer
|
||||
.from(sambaConfig.sshPass, 'base64')
|
||||
.toString('ascii');
|
||||
|
||||
let sshClient = new ssh.NodeSSH();
|
||||
await sshClient.connect({
|
||||
host: sambaConfig.host,
|
||||
username: sambaConfig.sshUser,
|
||||
password: sshPassword
|
||||
});
|
||||
|
||||
let res = await sshClient.execCommand('samba-tool user list');
|
||||
let users = res.stdout.split('\n');
|
||||
for (let user of users) usersToSync.add(user.trim());
|
||||
|
||||
await sshClient.dispose();
|
||||
}
|
||||
|
||||
// Syncing
|
||||
|
||||
$.RoleInherit.sync();
|
||||
|
||||
let sync = await Self.syncInit();
|
||||
for (let user of usersToSync.values()) {
|
||||
try {
|
||||
await Self.doSync(sync, user);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
await Self.syncDeinit(sync);
|
||||
};
|
||||
};
|
|
@ -19,7 +19,7 @@ module.exports = Self => {
|
|||
}
|
||||
],
|
||||
http: {
|
||||
path: `/sync`,
|
||||
path: `/:userName/sync`,
|
||||
verb: 'PATCH'
|
||||
}
|
||||
});
|
||||
|
@ -35,45 +35,121 @@ module.exports = Self => {
|
|||
|
||||
if (user && isSync) return;
|
||||
|
||||
let accountConfig;
|
||||
let mailConfig;
|
||||
let sync = await Self.syncInit();
|
||||
try {
|
||||
await Self.doSync(sync, userName, password);
|
||||
} finally {
|
||||
await Self.syncDeinit(sync);
|
||||
}
|
||||
};
|
||||
|
||||
Self.syncInit = async function() {
|
||||
let $ = Self.app.models;
|
||||
|
||||
let accountConfig = await $.AccountConfig.findOne({
|
||||
fields: ['homedir', 'shell', 'idBase']
|
||||
});
|
||||
let mailConfig = await $.MailConfig.findOne({
|
||||
fields: ['domain']
|
||||
});
|
||||
|
||||
// LDAP
|
||||
|
||||
let ldapClient;
|
||||
let ldapConfig = await $.LdapConfig.findOne({
|
||||
fields: ['host', 'rdn', 'password', 'baseDn', 'groupDn']
|
||||
});
|
||||
|
||||
if (ldapConfig) {
|
||||
ldapClient = ldap.createClient({
|
||||
url: `ldap://${ldapConfig.host}:389`
|
||||
});
|
||||
|
||||
let ldapPassword = Buffer
|
||||
.from(ldapConfig.password, 'base64')
|
||||
.toString('ascii');
|
||||
await ldapClient.bind(ldapConfig.rdn, ldapPassword);
|
||||
}
|
||||
|
||||
// Samba
|
||||
|
||||
let sambaClient;
|
||||
let sambaConfig = await $.SambaConfig.findOne({
|
||||
fields: ['host', 'sshUser', 'sshPass']
|
||||
});
|
||||
|
||||
if (sambaConfig) {
|
||||
let sshPassword = Buffer
|
||||
.from(sambaConfig.sshPass, 'base64')
|
||||
.toString('ascii');
|
||||
|
||||
sambaClient = new ssh.NodeSSH();
|
||||
await sambaClient.connect({
|
||||
host: sambaConfig.host,
|
||||
username: sambaConfig.sshUser,
|
||||
password: sshPassword
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
accountConfig,
|
||||
mailConfig,
|
||||
ldapConfig,
|
||||
ldapClient,
|
||||
sambaClient
|
||||
};
|
||||
};
|
||||
|
||||
Self.syncDeinit = async function(sync) {
|
||||
// FIXME: Cannot disconnect, hangs on undind() call
|
||||
// if (sync.ldapClient)
|
||||
// await sync.ldapClient.unbind();
|
||||
|
||||
if (sync.sambaClient)
|
||||
await sync.sambaClient.dispose();
|
||||
};
|
||||
|
||||
Self.doSync = async function(sync, userName, password) {
|
||||
let $ = Self.app.models;
|
||||
let {
|
||||
accountConfig,
|
||||
mailConfig,
|
||||
ldapConfig,
|
||||
ldapClient,
|
||||
sambaClient
|
||||
} = sync;
|
||||
|
||||
let user = await $.Account.findOne({
|
||||
where: {name: userName},
|
||||
fields: [
|
||||
'id',
|
||||
'nickname',
|
||||
'email',
|
||||
'lang',
|
||||
'roleFk',
|
||||
'sync',
|
||||
'active',
|
||||
'created',
|
||||
'bcryptPassword',
|
||||
'updated'
|
||||
],
|
||||
include: {
|
||||
relation: 'roles',
|
||||
scope: {
|
||||
include: {
|
||||
relation: 'inherits',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let extraParams;
|
||||
let hasAccount = false;
|
||||
|
||||
if (user) {
|
||||
accountConfig = await $.AccountConfig.findOne({
|
||||
fields: ['homedir', 'shell', 'idBase']
|
||||
});
|
||||
mailConfig = await $.MailConfig.findOne({
|
||||
fields: ['domain']
|
||||
});
|
||||
|
||||
user = await $.Account.findById(user.id, {
|
||||
fields: [
|
||||
'id',
|
||||
'nickname',
|
||||
'email',
|
||||
'lang',
|
||||
'roleFk',
|
||||
'sync',
|
||||
'active',
|
||||
'created',
|
||||
'updated'
|
||||
],
|
||||
where: {name: userName},
|
||||
include: {
|
||||
relation: 'roles',
|
||||
scope: {
|
||||
include: {
|
||||
relation: 'inherits',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
extraParams = {
|
||||
corporateMail: `${userName}@${mailConfig.domain}`,
|
||||
uidNumber: accountConfig.idBase + user.id
|
||||
|
@ -83,8 +159,12 @@ module.exports = Self => {
|
|||
&& await $.UserAccount.exists(user.id);
|
||||
}
|
||||
|
||||
// Database
|
||||
|
||||
if (user) {
|
||||
let bcryptPassword = $.User.hashPassword(password);
|
||||
let bcryptPassword = password
|
||||
? $.User.hashPassword(password)
|
||||
: user.bcryptPassword;
|
||||
|
||||
await $.Account.upsertWithWhere({id: user.id},
|
||||
{bcryptPassword}
|
||||
|
@ -101,7 +181,7 @@ module.exports = Self => {
|
|||
|
||||
// SIP
|
||||
|
||||
if (hasAccount) {
|
||||
if (hasAccount && password) {
|
||||
await Self.rawSql('CALL pbx.sip_setPassword(?, ?)',
|
||||
[user.id, password]
|
||||
);
|
||||
|
@ -109,155 +189,169 @@ module.exports = Self => {
|
|||
|
||||
// LDAP
|
||||
|
||||
let ldapConfig = await $.LdapConfig.findOne({
|
||||
fields: ['host', 'rdn', 'password', 'baseDn', 'groupDn']
|
||||
});
|
||||
if (ldapClient) {
|
||||
// Deletes user
|
||||
|
||||
if (ldapConfig) {
|
||||
let ldapClient = ldap.createClient({
|
||||
url: `ldap://${ldapConfig.host}:389`
|
||||
res = await ldapClient.search(ldapConfig.baseDn, {
|
||||
scope: 'sub',
|
||||
attributes: ['userPassword', 'sambaNTPassword'],
|
||||
filter: `&(uid=${userName})(objectClass=inetOrgPerson)`
|
||||
});
|
||||
|
||||
let ldapPassword = Buffer
|
||||
.from(ldapConfig.password, 'base64')
|
||||
.toString('ascii');
|
||||
await ldapClient.bind(ldapConfig.rdn, ldapPassword);
|
||||
let oldUser;
|
||||
await new Promise((resolve, reject) => {
|
||||
res.on('error', reject);
|
||||
res.on('searchEntry', e => oldUser = e.object);
|
||||
res.on('end', resolve);
|
||||
});
|
||||
|
||||
let err;
|
||||
try {
|
||||
// Deletes user
|
||||
|
||||
try {
|
||||
let dn = `uid=${userName},${ldapConfig.baseDn}`;
|
||||
await ldapClient.del(dn);
|
||||
} catch (e) {
|
||||
if (e.name !== 'NoSuchObjectError') throw e;
|
||||
}
|
||||
|
||||
// Removes user from groups
|
||||
|
||||
let opts = {
|
||||
scope: 'sub',
|
||||
attributes: ['dn'],
|
||||
filter: `&(memberUid=${userName})(objectClass=posixGroup)`
|
||||
};
|
||||
res = await ldapClient.search(ldapConfig.groupDn, opts);
|
||||
|
||||
let oldGroups = [];
|
||||
await new Promise((resolve, reject) => {
|
||||
res.on('error', reject);
|
||||
res.on('searchEntry', e => oldGroups.push(e.object));
|
||||
res.on('end', resolve);
|
||||
});
|
||||
|
||||
let reqs = [];
|
||||
for (oldGroup of oldGroups) {
|
||||
let change = new ldap.Change({
|
||||
operation: 'delete',
|
||||
modification: {memberUid: userName}
|
||||
});
|
||||
reqs.push(ldapClient.modify(oldGroup.dn, change));
|
||||
}
|
||||
await Promise.all(reqs);
|
||||
|
||||
if (hasAccount) {
|
||||
// Recreates user
|
||||
|
||||
let nameArgs = user.nickname.split(' ');
|
||||
let sshaPassword = crypto
|
||||
.createHash('sha1')
|
||||
.update(password)
|
||||
.digest('base64');
|
||||
|
||||
let dn = `uid=${userName},${ldapConfig.baseDn}`;
|
||||
let newEntry = {
|
||||
uid: userName,
|
||||
objectClass: [
|
||||
'inetOrgPerson',
|
||||
'posixAccount',
|
||||
'sambaSamAccount'
|
||||
],
|
||||
cn: user.nickname || userName,
|
||||
displayName: user.nickname,
|
||||
givenName: nameArgs[0],
|
||||
sn: nameArgs[1] || 'Empty',
|
||||
mail: extraParams.corporateMail,
|
||||
userPassword: `{SSHA}${sshaPassword}`,
|
||||
preferredLanguage: user.lang,
|
||||
homeDirectory: `${accountConfig.homedir}/${userName}`,
|
||||
loginShell: accountConfig.shell,
|
||||
uidNumber: extraParams.uidNumber,
|
||||
gidNumber: accountConfig.idBase + user.roleFk,
|
||||
sambaSID: '-',
|
||||
sambaNTPassword: nthash(password)
|
||||
};
|
||||
await ldapClient.add(dn, newEntry);
|
||||
|
||||
// Adds user to groups
|
||||
|
||||
let reqs = [];
|
||||
for (let role of user.roles()) {
|
||||
let change = new ldap.Change({
|
||||
operation: 'add',
|
||||
modification: {memberUid: userName}
|
||||
});
|
||||
let roleName = role.inherits().name;
|
||||
let dn = `cn=${roleName},${ldapConfig.groupDn}`;
|
||||
reqs.push(ldapClient.modify(dn, change));
|
||||
}
|
||||
await Promise.all(reqs);
|
||||
}
|
||||
let dn = `uid=${userName},${ldapConfig.baseDn}`;
|
||||
await ldapClient.del(dn);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
if (e.name !== 'NoSuchObjectError') throw e;
|
||||
}
|
||||
|
||||
// FIXME: Cannot disconnect, hangs on undind() call
|
||||
// await ldapClient.unbind();
|
||||
if (err) throw err;
|
||||
// Removes user from groups
|
||||
|
||||
res = await ldapClient.search(ldapConfig.groupDn, {
|
||||
scope: 'sub',
|
||||
attributes: ['dn'],
|
||||
filter: `&(memberUid=${userName})(objectClass=posixGroup)`
|
||||
});
|
||||
|
||||
let oldGroups = [];
|
||||
await new Promise((resolve, reject) => {
|
||||
res.on('error', reject);
|
||||
res.on('searchEntry', e => oldGroups.push(e.object));
|
||||
res.on('end', resolve);
|
||||
});
|
||||
|
||||
let reqs = [];
|
||||
for (oldGroup of oldGroups) {
|
||||
let change = new ldap.Change({
|
||||
operation: 'delete',
|
||||
modification: {memberUid: userName}
|
||||
});
|
||||
reqs.push(ldapClient.modify(oldGroup.dn, change));
|
||||
}
|
||||
await Promise.all(reqs);
|
||||
|
||||
if (hasAccount) {
|
||||
// Recreates user
|
||||
|
||||
let nameArgs = user.nickname.split(' ');
|
||||
let sn = nameArgs.length > 1
|
||||
? nameArgs.splice(1).join(' ')
|
||||
: '-';
|
||||
|
||||
let dn = `uid=${userName},${ldapConfig.baseDn}`;
|
||||
let newEntry = {
|
||||
uid: userName,
|
||||
objectClass: [
|
||||
'inetOrgPerson',
|
||||
'posixAccount',
|
||||
'sambaSamAccount'
|
||||
],
|
||||
cn: user.nickname || userName,
|
||||
displayName: user.nickname,
|
||||
givenName: nameArgs[0],
|
||||
sn,
|
||||
mail: extraParams.corporateMail,
|
||||
preferredLanguage: user.lang,
|
||||
homeDirectory: `${accountConfig.homedir}/${userName}`,
|
||||
loginShell: accountConfig.shell,
|
||||
uidNumber: extraParams.uidNumber,
|
||||
gidNumber: accountConfig.idBase + user.roleFk,
|
||||
sambaSID: '-'
|
||||
};
|
||||
|
||||
let passwords;
|
||||
if (password) {
|
||||
let salt = crypto
|
||||
.randomBytes(8)
|
||||
.toString('base64');
|
||||
|
||||
let hash = crypto.createHash('sha1');
|
||||
hash.update(password);
|
||||
hash.update(salt, 'binary');
|
||||
let digest = hash.digest('binary');
|
||||
|
||||
let ssha = Buffer
|
||||
.from(digest + salt, 'binary')
|
||||
.toString('base64');
|
||||
|
||||
passwords = {
|
||||
userPassword: `{SSHA}${ssha}`,
|
||||
sambaNTPassword: nthash(password)
|
||||
};
|
||||
} else if (oldUser) {
|
||||
passwords = {
|
||||
userPassword: oldUser.userPassword,
|
||||
sambaNTPassword: oldUser.sambaNTPassword
|
||||
};
|
||||
}
|
||||
|
||||
if (passwords)
|
||||
Object.assign(newEntry, passwords);
|
||||
|
||||
await ldapClient.add(dn, newEntry);
|
||||
|
||||
// Adds user to groups
|
||||
|
||||
let reqs = [];
|
||||
for (let role of user.roles()) {
|
||||
let change = new ldap.Change({
|
||||
operation: 'add',
|
||||
modification: {memberUid: userName}
|
||||
});
|
||||
let roleName = role.inherits().name;
|
||||
let dn = `cn=${roleName},${ldapConfig.groupDn}`;
|
||||
reqs.push(ldapClient.modify(dn, change));
|
||||
}
|
||||
await Promise.all(reqs);
|
||||
}
|
||||
}
|
||||
|
||||
// Samba
|
||||
|
||||
let sambaConfig = await $.SambaConfig.findOne({
|
||||
fields: ['host', 'sshUser', 'sshPass']
|
||||
});
|
||||
|
||||
if (sambaConfig) {
|
||||
let sshPassword = Buffer
|
||||
.from(sambaConfig.sshPass, 'base64')
|
||||
.toString('ascii');
|
||||
|
||||
let sshClient = new ssh.NodeSSH();
|
||||
await sshClient.connect({
|
||||
host: sambaConfig.host,
|
||||
username: sambaConfig.sshUser,
|
||||
password: sshPassword
|
||||
});
|
||||
|
||||
let commands;
|
||||
|
||||
if (sambaClient) {
|
||||
if (hasAccount) {
|
||||
commands = [
|
||||
`samba-tool user create "${userName}" `
|
||||
+ `--uid-number=${extraParams.uidNumber} `
|
||||
+ `--mail-address="${extraParams.corporateMail}" `
|
||||
+ `--random-password`,
|
||||
`samba-tool user setexpiry "${userName}" `
|
||||
+ `--noexpiry`,
|
||||
`samba-tool user setpassword "${userName}" `
|
||||
+ `--newpassword="${password}"`,
|
||||
`mkhomedir_helper "${userName}" 0027`
|
||||
];
|
||||
try {
|
||||
await sambaClient.exec('samba-tool user create', [
|
||||
userName,
|
||||
'--uid-number', `${extraParams.uidNumber}`,
|
||||
'--mail-address', extraParams.corporateMail,
|
||||
'--random-password'
|
||||
]);
|
||||
} catch (e) {}
|
||||
|
||||
await sambaClient.exec('samba-tool user setexpiry', [
|
||||
userName,
|
||||
'--noexpiry'
|
||||
]);
|
||||
|
||||
if (password) {
|
||||
await sambaClient.exec('samba-tool user setpassword', [
|
||||
userName,
|
||||
'--newpassword', password
|
||||
]);
|
||||
await sambaClient.exec('samba-tool user enable', [
|
||||
userName
|
||||
]);
|
||||
}
|
||||
|
||||
await sambaClient.exec('mkhomedir_helper', [
|
||||
userName,
|
||||
'0027'
|
||||
]);
|
||||
} else {
|
||||
commands = [
|
||||
`samba-tool user delete "${userName}"`
|
||||
];
|
||||
try {
|
||||
await sambaClient.exec('samba-tool user disable', [
|
||||
userName
|
||||
]);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
for (let command of commands)
|
||||
await sshClient.execCommand(command);
|
||||
|
||||
await sshClient.dispose();
|
||||
}
|
||||
|
||||
// Mark as synchronized
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
}
|
||||
},
|
||||
"properties": {
|
||||
"role": {
|
||||
"id": {
|
||||
"id": true
|
||||
}
|
||||
},
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/user-account/sync')(Self);
|
||||
require('../methods/user-account/sync-by-id')(Self);
|
||||
require('../methods/user-account/sync-all')(Self);
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue