New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

koishi-plugin-common

Package Overview
Dependencies
Maintainers
1
Versions
141
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

koishi-plugin-common - npm Package Compare versions

Comparing version 2.1.0 to 2.1.1

2

dist/admin.js

@@ -69,3 +69,3 @@ "use strict";

if (!commands.length)
commands = Object.keys(usage);
commands = Object.keys(usage).filter(k => !k.startsWith('_'));
if (!commands.length)

@@ -72,0 +72,0 @@ return meta.$send('用户今日没有调用过指令。');

@@ -6,2 +6,3 @@ "use strict";

const { authorizeUser = {}, authorizeGroup = {} } = config;
const logger = ctx.logger('authorize');
/**

@@ -12,7 +13,12 @@ * array of `AuthorizeInfo`

/**
* a map of users' authority (buffered)
* a map of users' new authority
* to make sure every user gets maximum possible authority
*/
const userAuthorityMap = {};
const newAuthorityMap = new Map();
/**
* a map of users' old authority
* to prevent from duplicate data fetching
*/
const oldAuthorityMap = new Map();
/**
* inversion of `config.authorizeUser`

@@ -31,3 +37,5 @@ */

async function updateAuthorizeInfo(authority, ids) {
const users = await database.getUsers(ids, ['id', 'authority']);
const idsToFetch = ids.filter(id => !oldAuthorityMap.has(id));
const users = await database.getUsers(idsToFetch, ['id', 'authority']);
users.forEach((user) => oldAuthorityMap.set(user.id, user.authority));
const info = authorizeInfoList[authority] || (authorizeInfoList[authority] = {

@@ -38,15 +46,15 @@ insert: new Set(),

for (const id of ids) {
const oldAuthority = userAuthorityMap[id];
if (oldAuthority) {
if (oldAuthority >= authority)
const newAuthority = newAuthorityMap.get(id);
if (newAuthority) {
if (newAuthority >= authority)
continue;
authorizeInfoList[oldAuthority].insert.delete(id);
authorizeInfoList[oldAuthority].update.delete(id);
authorizeInfoList[newAuthority].insert.delete(id);
authorizeInfoList[newAuthority].update.delete(id);
}
userAuthorityMap[id] = authority;
const user = users.find(u => u.id === id);
if (!user) {
newAuthorityMap.set(id, authority);
const oldAuthority = oldAuthorityMap.get(id);
if (!oldAuthority) {
info.insert.add(id);
}
else if (user.authority !== authority) {
else if (oldAuthority < authority) {
info.update.add(id);

@@ -57,47 +65,66 @@ }

app.receiver.once('ready', async () => {
await Promise.all([
...Object.keys(inversedUserMap).map(key => updateAuthorizeInfo(+key, inversedUserMap[+key])),
...Object.entries(authorizeGroup).map(async ([key, value]) => {
const groupId = +key;
const config = typeof value === 'number' ? { member: value } : value;
const ctx = app.group(groupId);
if (!('member' in config))
config.member = 1;
if (!('admin' in config))
config.admin = config.member;
if (!('owner' in config))
config.owner = config.admin;
await database.getGroup(groupId, app.selfId);
const memberList = await ctx.sender.getGroupMemberList(groupId);
for (const role of ['member', 'admin', 'owner']) {
const authority = config[role];
const memberIds = memberList.filter(m => m.role === role).map(m => m.userId);
await updateAuthorizeInfo(authority, memberIds);
const tasks = [];
tasks.push(...Object.keys(inversedUserMap).map(async (key) => {
const id = +key;
await updateAuthorizeInfo(id, inversedUserMap[id]);
}));
tasks.push(...Object.entries(authorizeGroup).map(async ([key, value]) => {
const id = +key;
const ctx = app.group(id);
const config = typeof value === 'number' ? { member: value } : value;
if (!('member' in config))
config.member = 1;
if (!('admin' in config))
config.admin = config.member;
if (!('owner' in config))
config.owner = config.admin;
await database.getGroup(id, app.selfId);
const memberList = await ctx.sender.getGroupMemberList(id);
for (const role of ['member', 'admin', 'owner']) {
const authority = config[role];
const memberIds = memberList.filter(m => m.role === role).map(m => m.userId);
await updateAuthorizeInfo(authority, memberIds);
}
async function handleUpdate(userId, authority) {
const user = await database.getUser(userId, authority);
if (user.authority < authority) {
return database.setUser(userId, { authority });
}
async function handleUpdate(userId, authority) {
const user = await database.getUser(userId, authority);
if (user.authority < authority) {
return database.setUser(userId, { authority });
}
}
ctx.receiver.on('group-increase', ({ userId }) => {
return handleUpdate(userId, config.member);
});
ctx.receiver.on('group-admin/set', ({ userId }) => {
return handleUpdate(userId, config.admin);
});
}),
]);
}
ctx.receiver.on('group-increase', ({ userId }) => {
return handleUpdate(userId, config.member);
});
ctx.receiver.on('group-admin/set', ({ userId }) => {
return handleUpdate(userId, config.admin);
});
}));
await Promise.all(tasks.map(task => task.catch(logger.warn)));
let insertTotal = 0, updateTotal = 0;
for (const key in authorizeInfoList) {
const authority = +key;
const { insert, update } = authorizeInfoList[key];
insertTotal += insert.size;
updateTotal += update.size;
for (const id of insert) {
await database.getUser(id, authority);
logger.debug(`inserted ${id} with authority ${authority}`);
}
for (const id of update) {
await database.setUser(id, { authority });
logger.debug(`update ${id}'s authority: ${oldAuthorityMap.get(id)} -> ${authority}`);
}
}
const output = [];
if (insertTotal)
output.push(`inserted ${insertTotal} user${insertTotal > 1 ? 's' : ''}`);
if (updateTotal)
output.push(`updated ${updateTotal} user${updateTotal > 1 ? 's' : ''}`);
if (!output.length) {
logger.info('all users are up to date');
}
else {
logger.info(output.join(' and '));
}
});
}
exports.default = apply;

@@ -111,5 +111,5 @@ "use strict";

}
if (command._options.length) {
const options = command._options.filter(option => !option.hidden);
if (options.some(o => o.authority)) {
const _options = command._options.filter(option => !option.hidden);
if (_options.length) {
if (_options.some(o => o.authority)) {
output.push('可用的选项有(括号内为额外要求的权限等级):');

@@ -120,3 +120,3 @@ }

}
command._options.filter(option => !option.hidden).forEach((option) => {
_options.forEach((option) => {
const authority = option.authority ? `(${option.authority}) ` : '';

@@ -123,0 +123,0 @@ let line = ` ${authority}${option.rawName} ${option.description}`;

{
"name": "koishi-plugin-common",
"description": "Common plugins for Koishi",
"version": "2.1.0",
"version": "2.1.1",
"main": "dist/index.js",

@@ -31,9 +31,9 @@ "typings": "dist/index.d.ts",

"devDependencies": {
"koishi-database-memory": "^1.0.2",
"koishi-test-utils": "^3.0.0"
"koishi-database-memory": "^1.1.0",
"koishi-test-utils": "^3.0.1"
},
"dependencies": {
"koishi-core": "^1.7.0",
"koishi-core": "^1.8.0",
"koishi-utils": "^1.0.2"
}
}

@@ -81,3 +81,3 @@ import { isInteger, difference, Observed, paramCase } from 'koishi-utils'

const { usage } = user
if (!commands.length) commands = Object.keys(usage)
if (!commands.length) commands = Object.keys(usage).filter(k => !k.startsWith('_'))
if (!commands.length) return meta.$send('用户今日没有调用过指令。')

@@ -84,0 +84,0 @@ return meta.$send([

@@ -16,2 +16,3 @@ import { Context, GroupRole } from 'koishi-core'

const { authorizeUser = {}, authorizeGroup = {} } = config
const logger = ctx.logger('authorize')

@@ -24,8 +25,14 @@ /**

/**
* a map of users' authority (buffered)
* a map of users' new authority
* to make sure every user gets maximum possible authority
*/
const userAuthorityMap: Record<number, number> = {}
const newAuthorityMap = new Map<number, number>()
/**
* a map of users' old authority
* to prevent from duplicate data fetching
*/
const oldAuthorityMap = new Map<number, number>()
/**
* inversion of `config.authorizeUser`

@@ -45,3 +52,6 @@ */

async function updateAuthorizeInfo (authority: number, ids: number[]) {
const users = await database.getUsers(ids, ['id', 'authority'])
const idsToFetch = ids.filter(id => !oldAuthorityMap.has(id))
const users = await database.getUsers(idsToFetch, ['id', 'authority'])
users.forEach((user) => oldAuthorityMap.set(user.id, user.authority))
const info = authorizeInfoList[authority] || (authorizeInfoList[authority] = {

@@ -51,14 +61,16 @@ insert: new Set(),

})
for (const id of ids) {
const oldAuthority = userAuthorityMap[id]
if (oldAuthority) {
if (oldAuthority >= authority) continue
authorizeInfoList[oldAuthority].insert.delete(id)
authorizeInfoList[oldAuthority].update.delete(id)
const newAuthority = newAuthorityMap.get(id)
if (newAuthority) {
if (newAuthority >= authority) continue
authorizeInfoList[newAuthority].insert.delete(id)
authorizeInfoList[newAuthority].update.delete(id)
}
userAuthorityMap[id] = authority
const user = users.find(u => u.id === id)
if (!user) {
newAuthorityMap.set(id, authority)
const oldAuthority = oldAuthorityMap.get(id)
if (!oldAuthority) {
info.insert.add(id)
} else if (user.authority !== authority) {
} else if (oldAuthority < authority) {
info.update.add(id)

@@ -70,49 +82,69 @@ }

app.receiver.once('ready', async () => {
await Promise.all([
...Object.keys(inversedUserMap).map(key => updateAuthorizeInfo(+key, inversedUserMap[+key])),
...Object.entries(authorizeGroup).map(async ([key, value]) => {
const groupId = +key
const config = typeof value === 'number' ? { member: value } : value
const ctx = app.group(groupId)
const tasks: Promise<void>[] = []
if (!('member' in config)) config.member = 1
if (!('admin' in config)) config.admin = config.member
if (!('owner' in config)) config.owner = config.admin
tasks.push(...Object.keys(inversedUserMap).map(async (key) => {
const id = +key
await updateAuthorizeInfo(id, inversedUserMap[id])
}))
await database.getGroup(groupId, app.selfId)
const memberList = await ctx.sender.getGroupMemberList(groupId)
for (const role of ['member', 'admin', 'owner'] as GroupRole[]) {
const authority = config[role]
const memberIds = memberList.filter(m => m.role === role).map(m => m.userId)
await updateAuthorizeInfo(authority, memberIds)
}
tasks.push(...Object.entries(authorizeGroup).map(async ([key, value]) => {
const id = +key
const ctx = app.group(id)
const config = typeof value === 'number' ? { member: value } : value
async function handleUpdate (userId: number, authority: number) {
const user = await database.getUser(userId, authority)
if (user.authority < authority) {
return database.setUser(userId, { authority })
}
if (!('member' in config)) config.member = 1
if (!('admin' in config)) config.admin = config.member
if (!('owner' in config)) config.owner = config.admin
await database.getGroup(id, app.selfId)
const memberList = await ctx.sender.getGroupMemberList(id)
for (const role of ['member', 'admin', 'owner'] as GroupRole[]) {
const authority = config[role]
const memberIds = memberList.filter(m => m.role === role).map(m => m.userId)
await updateAuthorizeInfo(authority, memberIds)
}
async function handleUpdate (userId: number, authority: number) {
const user = await database.getUser(userId, authority)
if (user.authority < authority) {
return database.setUser(userId, { authority })
}
}
ctx.receiver.on('group-increase', ({ userId }) => {
return handleUpdate(userId, config.member)
})
ctx.receiver.on('group-increase', ({ userId }) => {
return handleUpdate(userId, config.member)
})
ctx.receiver.on('group-admin/set', ({ userId }) => {
return handleUpdate(userId, config.admin)
})
}),
])
ctx.receiver.on('group-admin/set', ({ userId }) => {
return handleUpdate(userId, config.admin)
})
}))
await Promise.all(tasks.map(task => task.catch(logger.warn)))
let insertTotal = 0, updateTotal = 0
for (const key in authorizeInfoList) {
const authority = +key
const { insert, update } = authorizeInfoList[key]
insertTotal += insert.size
updateTotal += update.size
for (const id of insert) {
await database.getUser(id, authority)
logger.debug(`inserted ${id} with authority ${authority}`)
}
for (const id of update) {
await database.setUser(id, { authority })
logger.debug(`update ${id}'s authority: ${oldAuthorityMap.get(id)} -> ${authority}`)
}
}
const output: string[] = []
if (insertTotal) output.push(`inserted ${insertTotal} user${insertTotal > 1 ? 's' : ''}`)
if (updateTotal) output.push(`updated ${updateTotal} user${updateTotal > 1 ? 's' : ''}`)
if (!output.length) {
logger.info('all users are up to date')
} else {
logger.info(output.join(' and '))
}
})
}

@@ -116,5 +116,5 @@ import { Context, Command, UserData, Meta, getUsage } from 'koishi-core'

if (command._options.length) {
const options = command._options.filter(option => !option.hidden)
if (options.some(o => o.authority)) {
const _options = command._options.filter(option => !option.hidden)
if (_options.length) {
if (_options.some(o => o.authority)) {
output.push('可用的选项有(括号内为额外要求的权限等级):')

@@ -125,3 +125,3 @@ } else {

command._options.filter(option => !option.hidden).forEach((option) => {
_options.forEach((option) => {
const authority = option.authority ? `(${option.authority}) ` : ''

@@ -128,0 +128,0 @@ let line = ` ${authority}${option.rawName} ${option.description}`

@@ -1,94 +0,133 @@

import { MockedApp } from 'koishi-test-utils'
import { App } from 'koishi-test-utils'
import { sleep } from 'koishi-utils'
import { createUser, Meta } from 'koishi-core'
import { createUser } from 'koishi-core'
import { authorize, AuthorizeOptions } from '../src'
import 'koishi-database-memory'
const app = new MockedApp({ database: { memory: {} } })
let counter = 0
// make coverage happy
app.plugin(authorize)
app.plugin<AuthorizeOptions>(authorize, {
authorizeUser: {
123: 2,
231: 2,
312: 2,
},
authorizeGroup: {
123: 1,
231: {
admin: 2,
owner: 3,
function createApp () {
return new App({ database: { memory: { identifier: ++counter } } })
}
test('authorize user', async () => {
const app = createApp()
// make coverage happy
app.plugin(authorize)
app.plugin<AuthorizeOptions>(authorize, {
authorizeUser: {
123: 2,
231: 2,
312: 2,
},
312: 3,
},
})
})
// mock group
app.setResponse('get_group_member_list', (params) => {
let data = []
if (params.group_id === 123) {
data = [
{ user_id: 564, role: 'member' },
]
} else if (params.group_id === 231) {
data = [
{ user_id: 123, role: 'member' },
{ user_id: 564, role: 'admin' },
{ user_id: 645, role: 'owner' },
]
}
return { data }
})
app.receiver.on('connect', () => {
app.database.memory.store.user[231] = createUser(231, 3)
app.database.memory.store.user[312] = createUser(312, 1)
})
app.receiver.on('connect', () => {
app.database.memory.store.user[231] = createUser(231, 3)
app.database.memory.store.user[312] = createUser(312, 2)
await app.start()
await sleep(0)
await expect(app.database.getUser(123)).resolves.toHaveProperty('authority', 2)
await expect(app.database.getUser(231)).resolves.toHaveProperty('authority', 3)
await expect(app.database.getUser(312)).resolves.toHaveProperty('authority', 2)
})
beforeAll(async () => {
test('authorize group 1', async () => {
const app = createApp()
app.plugin<AuthorizeOptions>(authorize, {
authorizeGroup: {
456: 2,
},
})
app.receiver.on('connect', () => {
app.database.memory.store.user[231] = createUser(231, 3)
app.database.memory.store.user[312] = createUser(312, 1)
})
app.setResponse('get_group_member_list', [
{ userId: 123, role: 'member' },
{ userId: 231, role: 'member' },
{ userId: 312, role: 'member' },
])
await app.start()
await sleep(0)
})
test('basic support', async () => {
await expect(app.database.getGroup(456)).resolves.toHaveProperty('assignee', app.selfId)
await expect(app.database.getUser(123)).resolves.toHaveProperty('authority', 2)
await expect(app.database.getUser(231)).resolves.toHaveProperty('authority', 2)
await expect(app.database.getUser(231)).resolves.toHaveProperty('authority', 3)
await expect(app.database.getUser(312)).resolves.toHaveProperty('authority', 2)
await expect(app.database.getGroup(123)).resolves.toHaveProperty('assignee', app.selfId)
await expect(app.database.getGroup(231)).resolves.toHaveProperty('assignee', app.selfId)
await expect(app.database.getGroup(312)).resolves.toHaveProperty('assignee', app.selfId)
await expect(app.database.getUser(564)).resolves.toHaveProperty('authority', 2)
await expect(app.database.getUser(645)).resolves.toHaveProperty('authority', 3)
})
const createGroupIncrease = (userId: number, groupId: number): Meta => ({
postType: 'notice',
noticeType: 'group_increase',
subType: 'invite',
userId,
groupId,
test('authorize group 2', async () => {
const app = createApp()
app.plugin<AuthorizeOptions>(authorize, {
authorizeGroup: {
456: { admin: 2, owner: 3 },
},
})
app.setResponse('get_group_member_list', [
{ userId: 123, role: 'member' },
{ userId: 231, role: 'admin' },
{ userId: 312, role: 'owner' },
])
await app.start()
await sleep(0)
await expect(app.database.getGroup(456)).resolves.toHaveProperty('assignee', app.selfId)
await expect(app.database.getUser(123)).resolves.toHaveProperty('authority', 1)
await expect(app.database.getUser(231)).resolves.toHaveProperty('authority', 2)
await expect(app.database.getUser(312)).resolves.toHaveProperty('authority', 3)
})
describe('handle group_increase', () => {
describe('handle group increase', () => {
const app = createApp()
app.plugin<AuthorizeOptions>(authorize, {
authorizeGroup: {
456: 2,
},
})
app.receiver.on('connect', () => {
app.database.memory.store.user[231] = createUser(231, 3)
app.database.memory.store.user[312] = createUser(312, 1)
})
app.setResponse('get_group_member_list', [])
beforeAll(async () => {
await app.start()
await sleep(0)
})
test('create new user', async () => {
app.receive(createGroupIncrease(456, 231))
app.receiveGroupIncrease('approve', 123, 456)
await sleep(0)
await expect(app.database.getUser(456)).resolves.toHaveProperty('authority', 1)
await expect(app.database.getUser(123)).resolves.toHaveProperty('authority', 2)
})
test('not affect higher authority', async () => {
app.receive(createGroupIncrease(312, 231))
app.receiveGroupIncrease('approve', 231, 456)
await sleep(0)
await expect(app.database.getUser(312)).resolves.toHaveProperty('authority', 2)
await expect(app.database.getUser(231)).resolves.toHaveProperty('authority', 3)
})
test('overwrite lower authority', async () => {
app.receive(createGroupIncrease(564, 312))
app.receiveGroupIncrease('approve', 312, 456)
await sleep(0)
await expect(app.database.getUser(564)).resolves.toHaveProperty('authority', 3)
await expect(app.database.getUser(312)).resolves.toHaveProperty('authority', 2)
})
test('skip unregistered groups', async () => {
app.receive(createGroupIncrease(789, 789))
app.receiveGroupIncrease('approve', 789, 789)
await sleep(0)

@@ -99,13 +138,75 @@ await expect(app.database.getUser(789)).resolves.toHaveProperty('authority', 0)

test('handle group-admin/set', async () => {
app.receive({
postType: 'notice',
noticeType: 'group_admin',
subType: 'set',
userId: 456,
groupId: 231,
describe('handle group admin set', () => {
const app = createApp()
app.plugin<AuthorizeOptions>(authorize, {
authorizeGroup: {
456: { admin: 2 },
},
})
app.receiver.on('connect', () => {
app.database.memory.store.user[231] = createUser(231, 3)
app.database.memory.store.user[312] = createUser(312, 1)
})
app.setResponse('get_group_member_list', [
{ userId: 123, role: 'member' },
{ userId: 231, role: 'member' },
])
beforeAll(async () => {
await app.start()
await sleep(0)
})
test('not affect higher authority', async () => {
app.receiveGroupAdmin('set', 231, 456)
await sleep(0)
await expect(app.database.getUser(231)).resolves.toHaveProperty('authority', 3)
})
test('overwrite lower authority', async () => {
app.receiveGroupAdmin('set', 123, 456)
await sleep(0)
await expect(app.database.getUser(123)).resolves.toHaveProperty('authority', 2)
})
test('skip unregistered groups', async () => {
app.receiveGroupAdmin('set', 312, 789)
await sleep(0)
await expect(app.database.getUser(312)).resolves.toHaveProperty('authority', 1)
})
})
test('mixed usage', async () => {
const app = createApp()
app.plugin<AuthorizeOptions>(authorize, {
authorizeUser: {
123: 2,
},
authorizeGroup: {
456: 1,
564: 3,
},
})
app.receiver.on('connect', () => {
app.database.memory.store.user[231] = createUser(231, 2)
app.database.memory.store.user[312] = createUser(312, 1)
})
app.setResponse('get_group_member_list', [
{ userId: 123, role: 'member' },
{ userId: 231, role: 'member' },
{ userId: 312, role: 'member' },
])
await app.start()
await sleep(0)
await expect(app.database.getUser(456)).resolves.toHaveProperty('authority', 2)
await expect(app.database.getUser(123)).resolves.toHaveProperty('authority', 3)
await expect(app.database.getUser(231)).resolves.toHaveProperty('authority', 3)
await expect(app.database.getUser(312)).resolves.toHaveProperty('authority', 3)
})

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc