Skip to content

Commit 30cb0ba

Browse files
committed
chore: Refator/fix workspace directory permission issues
1 parent 1b6ef60 commit 30cb0ba

18 files changed

Lines changed: 87 additions & 504 deletions

File tree

server-core/src/main/java/io/onedev/server/CoreModule.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,6 @@
422422
import io.onedev.server.web.websocket.WorkspaceEventBroadcaster;
423423
import io.onedev.server.workspace.DefaultWorkspaceQueryPersonalizationService;
424424
import io.onedev.server.workspace.DefaultWorkspaceService;
425-
import io.onedev.server.workspace.WorkspacePostCommitCallback;
426425
import io.onedev.server.workspace.WorkspaceQueryPersonalizationService;
427426
import io.onedev.server.workspace.WorkspaceService;
428427
import io.onedev.server.xodus.CommitInfoService;
@@ -580,7 +579,6 @@ public boolean isCascadable(Object traversableObject, Node traversableProperty,
580579
bind(DashboardGroupShareService.class).to(DefaultDashboardGroupShareService.class);
581580
bind(DashboardVisitService.class).to(DefaultDashboardVisitService.class);
582581
bind(WorkspaceService.class).to(DefaultWorkspaceService.class);
583-
bind(WorkspacePostCommitCallback.class);
584582
bind(LabelSpecService.class).to(DefaultLabelSpecService.class);
585583
bind(ProjectLabelService.class).to(DefaultProjectLabelService.class);
586584
bind(BuildLabelService.class).to(DefaultBuildLabelService.class);

server-core/src/main/java/io/onedev/server/git/GitFilter.java

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22

33
import static io.onedev.server.model.Project.decodeFullRepoNameAsPath;
44
import static io.onedev.server.util.IOUtils.BUFFER_SIZE;
5-
import static io.onedev.server.workspace.WorkspaceService.GIT_PREFIX;
65
import static org.apache.commons.lang3.StringUtils.strip;
76

87
import java.io.File;
98
import java.io.FilterInputStream;
109
import java.io.IOException;
1110
import java.io.InputStream;
1211
import java.io.OutputStream;
13-
import java.util.Collections;
1412
import java.util.Set;
1513
import java.util.concurrent.ExecutionException;
1614

@@ -41,7 +39,6 @@
4139
import org.eclipse.jgit.http.server.ServletUtils;
4240
import org.eclipse.jgit.transport.PacketLineOut;
4341
import org.glassfish.jersey.client.ClientProperties;
44-
import org.jspecify.annotations.Nullable;
4542

4643
import io.onedev.commons.utils.ExplicitException;
4744
import io.onedev.k8shelper.KubernetesHelper;
@@ -52,7 +49,6 @@
5249
import io.onedev.server.git.command.AdvertiseUploadRefsCommand;
5350
import io.onedev.server.git.hook.HookUtils;
5451
import io.onedev.server.model.Project;
55-
import io.onedev.server.model.Workspace;
5652
import io.onedev.server.persistence.SessionService;
5753
import io.onedev.server.security.CodePullAuthorizationSource;
5854
import io.onedev.server.security.CodePushAuthorizationSource;
@@ -128,25 +124,6 @@ private void doNotCache(HttpServletResponse response) {
128124
response.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate");
129125
}
130126

131-
@Nullable
132-
private File getWorkspaceGitDir(String projectInfo) {
133-
projectInfo = strip(projectInfo, "/");
134-
int idx = projectInfo.indexOf(GIT_PREFIX);
135-
if (idx < 0)
136-
return null;
137-
String projectPath = strip(projectInfo.substring(0, idx), "/");
138-
String numberStr = projectInfo.substring(idx + GIT_PREFIX.length());
139-
numberStr = strip(numberStr, "/");
140-
var facade = projectService.findFacadeByPath(projectPath);
141-
if (facade == null)
142-
throw new EntityNotFoundException("Project not found: " + projectPath);
143-
long workspaceNumber = Long.parseLong(numberStr);
144-
File gitDir = new File(Workspace.getWorkDir(facade.getId(), workspaceNumber), ".git");
145-
if (!gitDir.exists())
146-
throw new ExplicitException("Workspace git directory not found");
147-
return gitDir;
148-
}
149-
150127
protected void processPack(final HttpServletRequest request, final HttpServletResponse response)
151128
throws IOException, InterruptedException, ExecutionException {
152129
boolean upload = GitSmartHttpTools.isUploadPack(request);
@@ -158,31 +135,6 @@ protected void processPack(final HttpServletRequest request, final HttpServletRe
158135
String principal = (String) SecurityUtils.getSubject().getPrincipal();
159136
boolean clusterAccess = SecurityUtils.isSystem(principal);
160137

161-
File workspaceGitDir = getWorkspaceGitDir(projectInfo);
162-
if (workspaceGitDir != null) {
163-
if (!clusterAccess)
164-
throw new UnauthorizedException("Cluster credential required to access workspace git");
165-
if (!upload)
166-
throw new ExplicitException("Push to workspace git is not supported");
167-
168-
doNotCache(response);
169-
response.setHeader("Content-Type", "application/x-" + service + "-result");
170-
171-
InputStream stdin = new FilterInputStream(ServletUtils.getInputStream(request)) {
172-
@Override
173-
public void close() {
174-
}
175-
};
176-
OutputStream stdout = new OutputStreamWrapper(response.getOutputStream()) {
177-
@Override
178-
public void close() {
179-
}
180-
};
181-
182-
String protocol = request.getHeader("Git-Protocol");
183-
CommandUtils.uploadPack(workspaceGitDir, Collections.emptyMap(), protocol, stdin, stdout);
184-
return;
185-
}
186138
var projectPath = decodeFullRepoNameAsPath(strip(projectInfo, "/"));
187139
Long projectId = getProjectId(projectPath, clusterAccess, upload);
188140

@@ -363,25 +315,6 @@ protected void processRefs(HttpServletRequest request, HttpServletResponse respo
363315
String projectInfo = pathInfo.substring(0, pathInfo.length() - INFO_REFS.length());
364316

365317
boolean clusterAccess = SecurityUtils.isSystem();
366-
File workspaceGitDir = getWorkspaceGitDir(projectInfo);
367-
if (workspaceGitDir != null) {
368-
if (!clusterAccess)
369-
throw new UnauthorizedException("Cluster credential required to access workspace git");
370-
if (!upload)
371-
throw new ExplicitException("Push to workspace git is not supported");
372-
373-
writeInitial(response, service);
374-
375-
OutputStream output = new OutputStreamWrapper(response.getOutputStream()) {
376-
@Override
377-
public void close() throws IOException {
378-
}
379-
};
380-
381-
String protocol = request.getHeader("Git-Protocol");
382-
new AdvertiseUploadRefsCommand(workspaceGitDir, output).protocol(protocol).run();
383-
return;
384-
}
385318
var projectPath = decodeFullRepoNameAsPath(strip(projectInfo, "/"));
386319
Long projectId = getProjectId(projectPath, clusterAccess, upload);
387320

server-core/src/main/java/io/onedev/server/git/GitLfsFilter.java

Lines changed: 1 addition & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import static io.onedev.server.model.Project.decodeFullRepoNameAsPath;
66
import static io.onedev.server.util.CollectionUtils.newHashMap;
77
import static io.onedev.server.util.IOUtils.BUFFER_SIZE;
8-
import static io.onedev.server.workspace.WorkspaceService.GIT_PREFIX;
98
import static javax.servlet.http.HttpServletResponse.SC_CONFLICT;
109
import static javax.servlet.http.HttpServletResponse.SC_CREATED;
1110
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
@@ -16,7 +15,6 @@
1615
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
1716
import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION;
1817
import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
19-
import static org.apache.commons.lang3.StringUtils.strip;
2018
import static org.apache.commons.lang3.StringUtils.substringBeforeLast;
2119
import static org.apache.tika.mime.MimeTypes.OCTET_STREAM;
2220
import static org.glassfish.jersey.client.ClientProperties.REQUEST_ENTITY_PROCESSING;
@@ -69,7 +67,6 @@
6967
import io.onedev.server.cluster.ClusterService;
7068
import io.onedev.server.model.GitLfsLock;
7169
import io.onedev.server.model.Project;
72-
import io.onedev.server.model.Workspace;
7370
import io.onedev.server.persistence.SessionService;
7471
import io.onedev.server.persistence.dao.EntityCriteria;
7572
import io.onedev.server.security.CodePullAuthorizationSource;
@@ -167,46 +164,6 @@ private boolean canAccessProject(HttpServletRequest request, Project project) {
167164
}
168165
}
169166

170-
private boolean isWorkspacePath(String pathInfo) {
171-
return pathInfo.contains(GIT_PREFIX);
172-
}
173-
174-
@Nullable
175-
private long[] parseWorkspaceInfo(String pathInfo) {
176-
int idx = pathInfo.indexOf(GIT_PREFIX);
177-
if (idx < 0)
178-
return null;
179-
String projectPath = strip(pathInfo.substring(0, idx), "/");
180-
String afterWorkspaces = pathInfo.substring(idx + GIT_PREFIX.length());
181-
String numberStr;
182-
int dotGitIdx = afterWorkspaces.indexOf(".git/");
183-
if (dotGitIdx >= 0) {
184-
numberStr = afterWorkspaces.substring(0, dotGitIdx);
185-
} else {
186-
int slashIdx = afterWorkspaces.indexOf('/');
187-
numberStr = slashIdx >= 0 ? afterWorkspaces.substring(0, slashIdx) : afterWorkspaces;
188-
}
189-
var facade = projectService.findFacadeByPath(projectPath);
190-
if (facade == null)
191-
throw new ExplicitException("Project not found: " + projectPath);
192-
long workspaceNumber = Long.parseLong(numberStr);
193-
return new long[]{facade.getId(), workspaceNumber};
194-
}
195-
196-
private File getWorkspaceLfsFile(long projectId, long workspaceNumber, String objectId) {
197-
File workDir = Workspace.getWorkDir(projectId, workspaceNumber);
198-
return new File(workDir, ".git/lfs/objects/"
199-
+ objectId.substring(0, 2) + "/"
200-
+ objectId.substring(2, 4) + "/" + objectId);
201-
}
202-
203-
private String getWorkspaceObjectUrl(long projectId, long workspaceNumber, String objectId) {
204-
var serverUrl = clusterService.getServerUrl(clusterService.getLocalServerAddress());
205-
var projectPath = projectService.findFacadeById(projectId).getPath();
206-
return String.format("%s/%s/%s%d.git/lfs/objects/%s?lfs-objects=true",
207-
serverUrl, projectPath, GIT_PREFIX, workspaceNumber, objectId);
208-
}
209-
210167
private String getObjectUrl(HttpServletRequest request, String projectPath,
211168
String objectId, boolean clusterAccess) {
212169
var serverUrl = clusterAccess ? clusterService.getServerUrl(clusterService.getLocalServerAddress()) : settingService.getSystemSetting().getServerUrl();
@@ -241,32 +198,6 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
241198
boolean clusterAccess = SecurityUtils.isSystem();
242199

243200
if ("true".equals(httpRequest.getParameter("lfs-objects"))) {
244-
if (isWorkspacePath(pathInfo)) {
245-
if (!clusterAccess) {
246-
sendBatchError(httpResponse, SC_UNAUTHORIZED,
247-
"Cluster credential required to access workspace LFS");
248-
return;
249-
}
250-
if (!httpRequest.getMethod().equals("GET")) {
251-
sendBatchError(httpResponse, SC_FORBIDDEN,
252-
"Upload to workspace LFS is not supported");
253-
return;
254-
}
255-
long[] workspaceInfo = parseWorkspaceInfo(pathInfo);
256-
String objectId = StringUtils.substringAfterLast(pathInfo, "/");
257-
File lfsFile = getWorkspaceLfsFile(workspaceInfo[0], workspaceInfo[1], objectId);
258-
if (lfsFile.exists()) {
259-
httpResponse.setContentType(OCTET_STREAM);
260-
try (InputStream is = new FileInputStream(lfsFile);
261-
OutputStream os = httpResponse.getOutputStream()) {
262-
IOUtils.copy(is, os, BUFFER_SIZE);
263-
}
264-
} else {
265-
httpResponse.setStatus(SC_NOT_FOUND);
266-
}
267-
return;
268-
}
269-
270201
String projectPath = getProjectPath(pathInfo);
271202
String objectId = StringUtils.substringAfterLast(pathInfo, "/");
272203

@@ -394,23 +325,7 @@ else if (canWriteCode(httpRequest, project))
394325
&& httpRequest.getContentType().startsWith(CONTENT_TYPE)
395326
|| httpRequest.getHeader("Accept") != null
396327
&& httpRequest.getHeader("Accept").startsWith(CONTENT_TYPE)) {
397-
if (isWorkspacePath(pathInfo)) {
398-
if (!clusterAccess) {
399-
sendBatchError(httpResponse, SC_UNAUTHORIZED,
400-
"Cluster credential required to access workspace LFS");
401-
return;
402-
}
403-
httpResponse.setContentType(CONTENT_TYPE);
404-
if (pathInfo.endsWith("/batch")) {
405-
long[] workspaceInfo = parseWorkspaceInfo(pathInfo);
406-
processWorkspaceBatch(httpRequest, httpResponse, workspaceInfo[0], workspaceInfo[1]);
407-
} else {
408-
sendBatchError(httpResponse, SC_NOT_IMPLEMENTED,
409-
"Locks are not supported for workspace LFS");
410-
}
411-
return;
412-
}
413-
String projectPath = getProjectPath(pathInfo);
328+
String projectPath = getProjectPath(pathInfo);
414329
if (clusterAccess) {
415330
ProjectFacade project = projectService.findFacadeByPath(projectPath);
416331
if (project == null) {
@@ -677,46 +592,6 @@ private void processBatch(HttpServletRequest httpRequest, HttpServletResponse ht
677592
writeTo(httpResponse, batchResponse);
678593
}
679594
}
680-
681-
private void processWorkspaceBatch(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
682-
long projectId, long workspaceNumber) {
683-
JsonNode batchRequestNode = parseAndValidateBatchRequest(httpRequest, httpResponse);
684-
if (batchRequestNode == null)
685-
return;
686-
687-
boolean upload = batchRequestNode.get("operation").asText().equals("upload");
688-
if (upload) {
689-
sendBatchError(httpResponse, SC_FORBIDDEN,
690-
"Upload to workspace LFS is not supported");
691-
return;
692-
}
693-
694-
List<Map<String, Object>> objectsResponse = new ArrayList<>();
695-
for (JsonNode objectNode : batchRequestNode.get("objects")) {
696-
String objectId = objectNode.get("oid").asText();
697-
long objectSize = objectNode.get("size").asLong();
698-
Map<String, Object> objectResponse = new HashMap<>();
699-
objectResponse.put("oid", objectId);
700-
objectResponse.put("size", objectSize);
701-
File lfsFile = getWorkspaceLfsFile(projectId, workspaceNumber, objectId);
702-
if (lfsFile.exists()) {
703-
Map<Object, Object> actionResponse = newHashMap(
704-
"href", getWorkspaceObjectUrl(projectId, workspaceNumber, objectId));
705-
actionResponse.put("header", newHashMap(
706-
"Authorization", BEARER + " " + clusterService.getCredential()));
707-
objectResponse.put("actions", newHashMap("download", actionResponse));
708-
} else {
709-
objectResponse.put("error", newHashMap(
710-
"code", SC_NOT_FOUND,
711-
"message", "Object not found"));
712-
}
713-
objectsResponse.add(objectResponse);
714-
}
715-
716-
Map<String, Object> batchResponse = new HashMap<>();
717-
batchResponse.put("objects", objectsResponse);
718-
writeTo(httpResponse, batchResponse);
719-
}
720595

721596
private void sendAuthorizationError(HttpServletResponse response) {
722597
if (SecurityUtils.getUser() != null) {

server-core/src/main/java/io/onedev/server/git/hook/HookUtils.java

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,19 @@ public class HookUtils {
2222

2323
private static final String gitReceiveHook;
2424

25-
private static final String gitWorkspacePostCommitHook;
26-
2725
static {
2826
try (InputStream is = HookUtils.class.getClassLoader().getResourceAsStream("git-receive-hook")) {
2927
Preconditions.checkNotNull(is);
3028
gitReceiveHook = StringUtils.join(IOUtils.readLines(is, Charset.defaultCharset()), "\n");
3129
} catch (IOException e) {
3230
throw new RuntimeException(e);
3331
}
34-
try (InputStream is = HookUtils.class.getClassLoader().getResourceAsStream("git-workspace-postcommit-hook")) {
35-
Preconditions.checkNotNull(is);
36-
gitWorkspacePostCommitHook = StringUtils.join(IOUtils.readLines(is, Charset.defaultCharset()), "\n");
37-
} catch (IOException e) {
38-
throw new RuntimeException(e);
39-
}
4032
}
4133

42-
public static Map<String, String> getCommonHookEnvs() {
34+
public static Map<String, String> getCommonHookEnvs(String host) {
4335
ServerConfig serverConfig = OneDev.getInstance(ServerConfig.class);
4436
SettingService settingService = OneDev.getInstance(SettingService.class);
45-
String hookUrl = "http://localhost:" + serverConfig.getHttpPort();
37+
String hookUrl = "http://" + host + "/" + serverConfig.getHttpPort();
4638
String curl = settingService.getSystemSetting().getCurlLocation().getExecutable();
4739

4840
Map<String, String> envs = new HashMap<>();
@@ -54,7 +46,15 @@ public static Map<String, String> getCommonHookEnvs() {
5446
}
5547

5648
public static Map<String, String> getReceiveHookEnvs(Long projectId, String principal) {
57-
var envs = getCommonHookEnvs();
49+
var envs = new HashMap<String, String>();
50+
ServerConfig serverConfig = OneDev.getInstance(ServerConfig.class);
51+
SettingService settingService = OneDev.getInstance(SettingService.class);
52+
String hookUrl = "http://localhost:" + serverConfig.getHttpPort();
53+
String curl = settingService.getSystemSetting().getCurlLocation().getExecutable();
54+
55+
envs.put("ONEDEV_CURL", curl);
56+
envs.put("ONEDEV_URL", hookUrl);
57+
5858
envs.put("ONEDEV_HOOK_TOKEN", RECEIVE_HOOK_TOKEN);
5959
envs.put("ONEDEV_USER_ID", principal);
6060
envs.put("ONEDEV_REPOSITORY_ID", projectId.toString());
@@ -79,28 +79,6 @@ public static boolean isReceiveHookValid(File gitDir, String hookName) {
7979

8080
return true;
8181
}
82-
83-
public static Map<String, String> getWorkspacePostCommitHookEnvs(String workspaceToken) {
84-
var envs = getCommonHookEnvs();
85-
envs.put("ONEDEV_HOOK_TOKEN", workspaceToken);
86-
return envs;
87-
}
88-
89-
public static void setupWorkspacePostCommitHook(File gitDir, boolean lfsEnabled) {
90-
File hooksDir = new File(gitDir, "hooks");
91-
FileUtils.createDir(hooksDir);
92-
File postCommitHookFile = new File(hooksDir, "post-commit");
93-
94-
String lfsAwareHook;
95-
if (lfsEnabled) {
96-
lfsAwareHook = String.format(gitWorkspacePostCommitHook, "git lfs post-commit \"$@\"");
97-
} else {
98-
lfsAwareHook = String.format(gitWorkspacePostCommitHook, "");
99-
}
100-
101-
FileUtils.writeFile(postCommitHookFile, lfsAwareHook);
102-
postCommitHookFile.setExecutable(true);
103-
}
10482

10583
public static void checkReceiveHooks(File gitDir) {
10684
if (!isReceiveHookValid(gitDir, "pre-receive") || !isReceiveHookValid(gitDir, "post-receive")) {

0 commit comments

Comments
 (0)