feat(server): enhance user permissions and access control
Some checks failed
Deploy skills-market-server / deploy (push) Has been cancelled
Some checks failed
Deploy skills-market-server / deploy (push) Has been cancelled
- Introduced root admin checks in various functions to streamline permission handling for users. - Updated skill and agent management routes to simplify access control by removing redundant role checks. - Added favicon links to HTML files for improved branding in the admin and updates sections.
This commit is contained in:
parent
f86cace07d
commit
48e999149c
@ -4,6 +4,9 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>权限管理平台</title>
|
||||
<link rel="icon" type="image/png" href="https://oss.xintiao85.com/images/20260312_110209_2a7c6d79c7469d640f64cb663d6983b1.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="https://oss.xintiao85.com/images/20260312_110209_2a7c6d79c7469d640f64cb663d6983b1.png" />
|
||||
<link rel="apple-touch-icon" href="https://oss.xintiao85.com/images/20260312_110209_2a7c6d79c7469d640f64cb663d6983b1.png" />
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f8fafc;
|
||||
|
||||
@ -98,6 +98,7 @@ function sanitizeUserForClient(userDoc) {
|
||||
}
|
||||
|
||||
function canAccessFeature(user, permissionKey) {
|
||||
if (user?.is_root_admin) return true
|
||||
const perms = sanitizePermissions(user.permissions)
|
||||
return !!perms[permissionKey]
|
||||
}
|
||||
|
||||
39
server.js
39
server.js
@ -157,7 +157,12 @@ function normalizeTagList(tags) {
|
||||
return out
|
||||
}
|
||||
|
||||
const ROOT_MODE_TAGS = ['clarify', 'cowork', 'create', 'video', 'code']
|
||||
|
||||
function getAllowedModeTagsFromUser(user) {
|
||||
if (user?.is_root_admin) {
|
||||
return normalizeTagList(ROOT_MODE_TAGS)
|
||||
}
|
||||
const modes = Array.isArray(user?.permissions?.allowedModes) ? user.permissions.allowedModes : []
|
||||
return normalizeTagList(modes)
|
||||
}
|
||||
@ -167,24 +172,12 @@ function buildModeIntersectionFilter(user, requestedTags = []) {
|
||||
const requested = normalizeTagList(requestedTags)
|
||||
const isRootAdmin = !!user?.is_root_admin
|
||||
const isManagementList = requested.length === 0
|
||||
if (isRootAdmin && isManagementList) return {}
|
||||
const effective =
|
||||
requested.length > 0
|
||||
? requested.filter((tag) => allowedTags.includes(tag))
|
||||
: allowedTags
|
||||
|
||||
if (isRootAdmin && isManagementList) {
|
||||
if (effective.length === 0) {
|
||||
return { $or: [{ tags: { $exists: false } }, { tags: { $size: 0 } }] }
|
||||
}
|
||||
return {
|
||||
$or: [
|
||||
{ tags: { $in: effective } },
|
||||
{ tags: { $exists: false } },
|
||||
{ tags: { $size: 0 } }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (effective.length === 0) {
|
||||
return { _id: { $exists: false } }
|
||||
}
|
||||
@ -192,10 +185,10 @@ function buildModeIntersectionFilter(user, requestedTags = []) {
|
||||
}
|
||||
|
||||
function canUserAccessTaggedResource(user, resourceTags) {
|
||||
if (user?.is_root_admin) return true
|
||||
const allowedTags = getAllowedModeTagsFromUser(user)
|
||||
const tags = normalizeTagList(resourceTags)
|
||||
const isRootAdmin = !!user?.is_root_admin
|
||||
if (tags.length === 0) return isRootAdmin
|
||||
if (tags.length === 0) return false
|
||||
if (allowedTags.length === 0) return false
|
||||
return tags.some((tag) => allowedTags.includes(tag))
|
||||
}
|
||||
@ -495,7 +488,7 @@ app.get('/api/skills/:name/files/*', async (req, res) => {
|
||||
app.post('/api/skills/:name/lock', async (req, res) => {
|
||||
authRoutes.verifyToken(req, res, async () => {
|
||||
try {
|
||||
if (req.user.role !== 'admin' && !authRoutes.hasPermission(req.user, 'canViewSkillsPage')) {
|
||||
if (!authRoutes.hasPermission(req.user, 'canViewSkillsPage')) {
|
||||
return res.status(403).json({ success: false, error: '无权编辑技能' })
|
||||
}
|
||||
const skill = await skillsCollection.findOne({ name: req.params.name })
|
||||
@ -520,7 +513,7 @@ app.post('/api/skills/:name/lock', async (req, res) => {
|
||||
app.delete('/api/skills/:name/lock', async (req, res) => {
|
||||
authRoutes.verifyToken(req, res, async () => {
|
||||
try {
|
||||
if (req.user.role !== 'admin' && !authRoutes.hasPermission(req.user, 'canViewSkillsPage')) {
|
||||
if (!authRoutes.hasPermission(req.user, 'canViewSkillsPage')) {
|
||||
return res.status(403).json({ success: false, error: '无权编辑技能' })
|
||||
}
|
||||
const skill = await skillsCollection.findOne({ name: req.params.name })
|
||||
@ -590,7 +583,7 @@ app.get('/api/skills/mine', async (req, res, next) => {
|
||||
app.patch('/api/skills/:name/tags', async (req, res) => {
|
||||
authRoutes.verifyToken(req, res, async () => {
|
||||
try {
|
||||
if (req.user.role !== 'admin' && !authRoutes.hasPermission(req.user, 'canViewSkillsPage')) {
|
||||
if (!authRoutes.hasPermission(req.user, 'canViewSkillsPage')) {
|
||||
return res.status(403).json({ success: false, error: '无权修改技能标签' })
|
||||
}
|
||||
const allowedModeTags = getAllowedModeTagsFromUser(req.user)
|
||||
@ -636,7 +629,7 @@ app.patch('/api/skills/:name/tags', async (req, res) => {
|
||||
app.post('/api/skills/:name/publish', async (req, res) => {
|
||||
authRoutes.verifyToken(req, res, async () => {
|
||||
try {
|
||||
if (req.user.role !== 'admin' && !authRoutes.hasPermission(req.user, 'canViewSkillsPage')) {
|
||||
if (!authRoutes.hasPermission(req.user, 'canViewSkillsPage')) {
|
||||
return res.status(403).json({ success: false, error: '无权发布或修改技能' })
|
||||
}
|
||||
|
||||
@ -965,7 +958,7 @@ app.get('/api/agents/:name', async (req, res) => {
|
||||
app.post('/api/agents/:name/publish', async (req, res) => {
|
||||
authRoutes.verifyToken(req, res, async () => {
|
||||
try {
|
||||
if (req.user.role !== 'admin' && !authRoutes.hasPermission(req.user, 'canViewAgentsPage')) {
|
||||
if (!authRoutes.hasPermission(req.user, 'canViewAgentsPage')) {
|
||||
return res.status(403).json({ success: false, error: '无权发布或修改智能体' })
|
||||
}
|
||||
const { content, description, tags, localModifiedAt } = req.body
|
||||
@ -1045,7 +1038,7 @@ app.post('/api/agents/:name/publish', async (req, res) => {
|
||||
app.patch('/api/agents/:name/tags', async (req, res) => {
|
||||
authRoutes.verifyToken(req, res, async () => {
|
||||
try {
|
||||
if (req.user.role !== 'admin' && !authRoutes.hasPermission(req.user, 'canViewAgentsPage')) {
|
||||
if (!authRoutes.hasPermission(req.user, 'canViewAgentsPage')) {
|
||||
return res.status(403).json({ success: false, error: '无权修改智能体标签' })
|
||||
}
|
||||
const allowedModeTags = getAllowedModeTagsFromUser(req.user)
|
||||
@ -1087,7 +1080,7 @@ app.delete('/api/agents/:name', requireAdmin(async (req, res) => {
|
||||
app.post('/api/agents/:name/lock', async (req, res, next) => {
|
||||
authRoutes.verifyToken(req, res, async () => {
|
||||
try {
|
||||
if (req.user.role !== 'admin' && !authRoutes.hasPermission(req.user, 'canViewAgentsPage')) {
|
||||
if (!authRoutes.hasPermission(req.user, 'canViewAgentsPage')) {
|
||||
return res.status(403).json({ success: false, error: '无权编辑智能体' })
|
||||
}
|
||||
const agent = await agentsCollection.findOne({ name: req.params.name })
|
||||
@ -1107,7 +1100,7 @@ app.post('/api/agents/:name/lock', async (req, res, next) => {
|
||||
app.delete('/api/agents/:name/lock', async (req, res, next) => {
|
||||
authRoutes.verifyToken(req, res, async () => {
|
||||
try {
|
||||
if (req.user.role !== 'admin' && !authRoutes.hasPermission(req.user, 'canViewAgentsPage')) {
|
||||
if (!authRoutes.hasPermission(req.user, 'canViewAgentsPage')) {
|
||||
return res.status(403).json({ success: false, error: '无权编辑智能体' })
|
||||
}
|
||||
const agent = await agentsCollection.findOne({ name: req.params.name })
|
||||
|
||||
@ -4,6 +4,9 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LikeCowork 安装指南</title>
|
||||
<link rel="icon" type="image/png" href="https://oss.xintiao85.com/images/20260312_110209_2a7c6d79c7469d640f64cb663d6983b1.png">
|
||||
<link rel="shortcut icon" type="image/png" href="https://oss.xintiao85.com/images/20260312_110209_2a7c6d79c7469d640f64cb663d6983b1.png">
|
||||
<link rel="apple-touch-icon" href="https://oss.xintiao85.com/images/20260312_110209_2a7c6d79c7469d640f64cb663d6983b1.png">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
version: 1.2.1
|
||||
files:
|
||||
- url: likecowork-1.2.1-x64-mac.zip
|
||||
sha512: QIOFv41c9MYOPPKaxz4QunYHZJoobVSXhQYXQFgFJUm89Hf3AEC8PtHx3N8e7A99Nun7UuYwO16EaS9YmMJu7w==
|
||||
size: 978479730
|
||||
- url: likecowork-1.2.1-arm64-mac.zip
|
||||
sha512: L6CFKjmxD0Aep4gXkX2ojPuhPnwphHwoEVZXcI45WXmMzQRZfSG3bXY4o+PdZ+nfE7CFYkYbGl9g9yTbc/fPKQ==
|
||||
size: 973708487
|
||||
path: likecowork-1.2.1-x64-mac.zip
|
||||
sha512: QIOFv41c9MYOPPKaxz4QunYHZJoobVSXhQYXQFgFJUm89Hf3AEC8PtHx3N8e7A99Nun7UuYwO16EaS9YmMJu7w==
|
||||
releaseDate: '2026-03-27T08:06:20.025Z'
|
||||
@ -1,8 +0,0 @@
|
||||
version: 1.2.1
|
||||
files:
|
||||
- url: likecowork-1.2.1-setup.exe
|
||||
sha512: c3DLm7mfzV5e94GRDSkB0RWkqvSOJO04TVbMBR3FIoVsiRCTtGn/raRXYfs+xTS9mZ5JlpkYTdM+gtS3aQ3UhQ==
|
||||
size: 938877301
|
||||
path: likecowork-1.2.1-setup.exe
|
||||
sha512: c3DLm7mfzV5e94GRDSkB0RWkqvSOJO04TVbMBR3FIoVsiRCTtGn/raRXYfs+xTS9mZ5JlpkYTdM+gtS3aQ3UhQ==
|
||||
releaseDate: '2026-03-27T07:51:13.507Z'
|
||||
Loading…
x
Reference in New Issue
Block a user