Skip to content

Commit

Permalink
Merge pull request #94 from NJUPT-SAST/feat/github
Browse files Browse the repository at this point in the history
Feat/GitHub
  • Loading branch information
Xunop authored Jul 25, 2024
2 parents 99dc434 + ac76a2c commit 7d4664c
Show file tree
Hide file tree
Showing 13 changed files with 318 additions and 163 deletions.
116 changes: 58 additions & 58 deletions .github/workflows/dev-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,76 +10,76 @@ on:

jobs:
build:
if: github.event.pull_request.merged
if: github.event.pull_request.merged
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Build Docker image
run: |
docker buildx build --platform linux/amd64 -t sast/sast-link -f docker/Dockerfile --output type=docker,dest=image.tar .
- name: Build Docker image
run: |
docker buildx build --platform linux/amd64 -t sast/sast-link -f docker/Dockerfile --output type=docker,dest=image.tar .
- name: Copy Docker image to server
uses: easingthemes/ssh-deploy@main
with:
- name: Copy Docker image to server
uses: easingthemes/ssh-deploy@main
with:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
ARGS: "-rlgoDzvc -i --delete"
SOURCE: "./image.tar"
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
TARGET: /tmp/image.tar

- name: Deploy in server
uses: appleboy/[email protected]
env:
WORKINGDIR: ${{ secrets.WORKINGDIR }}
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script_stop: true
envs: WORKINGDIR
script: |
### Notice: run for develop ###
# Stop and remove existing container if it exists
if [ "$(docker ps -aq -f name=sastlink)" ]; then
docker stop sastlink
docker rm sastlink
fi
# Remove existing image if it exists
if [ "$(docker images -q sast/sast-link)" ]; then
docker rmi sast/sast-link
fi
# Load the new image and run it
# It will failed, for test
docker load -i /tmp/image.tar
docker run --restart always -d --name sastlink -p 8080:8080 -v $WORKINGDIR:/sastlink/config sast/sast-link
- name: Deploy in server
uses: appleboy/[email protected]
env:
WORKINGDIR: ${{ secrets.WORKINGDIR }}
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script_stop: true
envs: WORKINGDIR
script: |
### Notice: run for develop ###
# Stop and remove existing container if it exists
if [ "$(docker ps -aq -f name=sastlink)" ]; then
docker stop sastlink
docker rm sastlink
fi
# Remove existing image if it exists
if [ "$(docker images -q sast/sast-link)" ]; then
docker rmi sast/sast-link
fi
# Load the new image and run it
# It will failed, for test
docker load -i /tmp/image.tar
docker run --restart always -d --name sastlink -p 8080:8080 -v $WORKINGDIR:/sastlink/config sast/sast-link
- name: Send Success Message
if: ${{ success() }}
run: |
bash ./scripts/webhook.sh \
-u "${{ github.event.pull_request.html_url }}" \
-w ${{ secrets.WEBHOOK_URL }} \
-s sastlink -c "${{ github.event.pull_request.user.login }}" -f 'success' \
-m "https://github.com/${{ github.repository }}/commit/${{ github.sha }}"
- name: Send Success Message
if: ${{ success() }}
run: |
bash ./scripts/webhook.sh \
-u "${{ github.event.pull_request.html_url }}" \
-w ${{ secrets.WEBHOOK_URL }} \
-s sastlink -c "${{ github.event.pull_request.user.login }}" -f 'success' \
-m "https://github.com/${{ github.repository }}/commit/${{ github.sha }}"
- name: Send Fail Message
if: ${{ failure() }}
run: |
bash ./scripts/webhook.sh \
-u "${{ github.event.pull_request.html_url }}" \
-w ${{ secrets.WEBHOOK_URL }} \
-s sastlink -c "${{ github.event.pull_request.user.login }}" -f 'failure' \
-m "https://github.com/${{ github.repository }}/commit/${{ github.sha }}"
- name: Send Fail Message
if: ${{ failure() }}
run: |
bash ./scripts/webhook.sh \
-u "${{ github.event.pull_request.html_url }}" \
-w ${{ secrets.WEBHOOK_URL }} \
-s sastlink -c "${{ github.event.pull_request.user.login }}" -f 'failure' \
-m "https://github.com/${{ github.repository }}/commit/${{ github.sha }}"
10 changes: 9 additions & 1 deletion sql/ddl.sql
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ ALTER TABLE public.oauth2_clients OWNER TO postgres;
CREATE TABLE public.oauth2_info (
id integer NOT NULL,
client character varying NOT NULL,
info json[],
info jsonb[],
oauth_user_id character varying NOT NULL,
user_id character varying NOT NULL
);
Expand Down Expand Up @@ -509,6 +509,14 @@ ALTER TABLE ONLY public.oauth2_clients
ADD CONSTRAINT oauth2_clients_pkey PRIMARY KEY (id);


--
-- Name: oauth2_info oauth2_info_unique; Type: CONSTRAINT; Schema: public; Owner: postgres
--

ALTER TABLE ONLY public.oauth2_info
ADD CONSTRAINT oauth2_info_unique UNIQUE (client, user_id);


--
-- Name: oauth2_tokens oauth2_tokens_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
Expand Down
10 changes: 9 additions & 1 deletion sql/oauth2_info.sql
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ SET default_table_access_method = heap;
CREATE TABLE public.oauth2_info (
id integer NOT NULL,
client character varying NOT NULL,
info json[],
info jsonb[],
oauth_user_id character varying NOT NULL,
user_id character varying NOT NULL
);
Expand Down Expand Up @@ -85,6 +85,14 @@ ALTER SEQUENCE public.oauth2_info_id_seq OWNED BY public.oauth2_info.id;
ALTER TABLE ONLY public.oauth2_info ALTER COLUMN id SET DEFAULT nextval('public.oauth2_info_id_seq'::regclass);


--
-- Name: oauth2_info oauth2_info_unique; Type: CONSTRAINT; Schema: public; Owner: postgres
--

ALTER TABLE ONLY public.oauth2_info
ADD CONSTRAINT oauth2_info_unique UNIQUE (client, user_id);


--
-- PostgreSQL database dump complete
--
Expand Down
84 changes: 66 additions & 18 deletions src/api/v1/oauth_client_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import (
"fmt"
"io"
"net/http"
"time"

"github.com/NJUPT-SAST/sast-link-backend/config"
"github.com/NJUPT-SAST/sast-link-backend/endpoints"
"github.com/NJUPT-SAST/sast-link-backend/log"
"github.com/NJUPT-SAST/sast-link-backend/model"
"github.com/NJUPT-SAST/sast-link-backend/model/result"
"github.com/NJUPT-SAST/sast-link-backend/service"
"github.com/NJUPT-SAST/sast-link-backend/util"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
"golang.org/x/oauth2"
Expand All @@ -25,25 +28,32 @@ var (
githubConf = oauth2.Config{
ClientID: config.Config.GetString("oauth.client.github.id"),
ClientSecret: config.Config.GetString("oauth.client.github.secret"),
RedirectURL: config.Config.GetString("oauth.client.github.redirect_url"),
RedirectURL: "http://localhost:3000/callback/github",
Scopes: []string{},
Endpoint: endpoints.GitHub,
}
)

func OauthGithubLogin(c *gin.Context) {

redirectURL := c.Query("redirect_url")
githubConf.RedirectURL = redirectURL
// Create oauthState cookie
oauthState := GenerateStateOauthCookie(c.Writer)
url := githubConf.AuthCodeURL(oauthState)

log.Log.Warnf("Visit the URL for the auth dialog: %v\n", url)
// log.Log.Warnf("Visit the URL for the auth dialog: %v\n", url)
log.Debug("Visit the URL for the auth dialog: ", url)
log.Debug("RedirectURL: ", githubConf.RedirectURL)
log.Debug("ClientID: ", githubConf.ClientID)

c.SetCookie("oauthstate", oauthState, 3600, "", "", false, true)
c.Redirect(http.StatusFound, url)
}

func OauthGithubCallback(c *gin.Context) {
oauthState, _ := c.Request.Cookie("oauthstate")
log.Debugf("oauthState: %s", oauthState.Value)

if c.Request.FormValue("state") != oauthState.Value {
log.Log.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthState.Value, c.Request.FormValue("state"))
Expand All @@ -53,56 +63,94 @@ func OauthGithubCallback(c *gin.Context) {

code := c.Query("code")

githubId, err := getUserInfoFromGithub(c.Request.Context(), code)
// githubinfo is the user info from github
githubInfo, err := getUserInfoFromGithub(c.Request.Context(), code)
if err != nil {
c.JSON(http.StatusOK, result.Failed(result.HandleError(err)))
return
}

if githubId == "" {
if githubInfo == "" {
c.JSON(http.StatusOK, result.Failed(result.HandleError(result.RequestParamError)))
return
}

user, err := service.GetUserByGithubId(githubId)
githubID := gjson.Get(githubInfo, "id").String()
// userInfo is the github user info in the database
userInfo, err := service.GetUserByGithubId(githubID)
if err != nil {
log.Errorf("service.GetUserByGithubId ::: %s", err.Error())
c.JSON(http.StatusOK, result.Failed(result.HandleError(err)))
return
}

// Store to redis
model.Rdb.Set(model.RedisCtx, githubID,
githubInfo, time.Duration(model.OAUTH_USER_INFO_EXP))

// User not found, Need to register to bind the github id
if user == nil {
if userInfo == nil {
log.Debugf("User not found, Need to register to bind the github id: %s", githubID)
oauthToken, err := util.GenerateTokenWithExp(c, model.OauthSubKey(githubID, model.OAUTH_GITHUB_SUB), model.OAUTH_TICKET_EXP)

if err != nil {
c.JSON(http.StatusOK, result.Failed(result.GenerateToken))
log.Log.Errorln("util.GenerateTokenWithExp ::: ", err)
return
}
c.JSON(http.StatusOK, result.Response{
Success: false,
ErrCode: result.OauthUserUnbounded.ErrCode,
ErrMsg: result.OauthUserUnbounded.ErrMsg,
Data: gin.H{
"oauthTicket": oauthToken,
},
})
return
} else {
// User already registered and bounded github,
// directly return token
uid := userInfo.UserID
log.Debugf("User already registered and bounded github: %s", uid)
token, err := util.GenerateTokenWithExp(c, model.LoginJWTSubKey(uid), model.LOGIN_TOKEN_EXP)
if err != nil {
c.JSON(http.StatusOK, result.Failed(result.GenerateToken))
return
}
model.Rdb.Set(c, model.LoginTokenKey(uid), token, model.LOGIN_TOKEN_EXP)
c.JSON(http.StatusOK, result.Success(gin.H{
model.LOGIN_TOKEN_SUB: token,
}))
return
}

c.JSON(http.StatusOK, result.Success(githubId))
}

func getUserInfoFromGithub(ctx context.Context, code string) (string, error) {

token, err := githubConf.Exchange(ctx, code)
if err != nil {
log.Log.Errorf("exchange github code error: %s", err.Error())
return "", fmt.Errorf("exchange github code error: %s", err.Error())
// log.Log.Errorf("exchange github code error: %s", err.Error())
log.Errorf("Exchange github code error: %s", err.Error())
return "", fmt.Errorf("Exchange github code error: %s", err.Error())
}
client := &http.Client{}
req, err := http.NewRequest("GET", GithubUserInfoURL, nil)
if err != nil {
log.Log.Errorf("new request error: %s", err.Error())
return "", fmt.Errorf("new request error: %s", err.Error())
// log.Log.Errorf("New request error: %s", err.Error())
log.Errorf("New request error: %s", err.Error())
return "", fmt.Errorf("New request error: %s", err.Error())
}
req.Header.Set("Authorization", "Bearer "+token.AccessToken)
res, err := client.Do(req)
if err != nil {
log.Log.Errorf("failt to getting user info: %s", err.Error())
return "", fmt.Errorf("failt to getting user info: %s", err.Error())
log.Log.Errorf("Failt to getting user info: %s", err.Error())
return "", fmt.Errorf("Failt to getting user info: %s", err.Error())
}
body, err := io.ReadAll(res.Body)
if err != nil {
return "", result.InternalErr
}

// TODO:Now just get the github id
githubId := gjson.Get(string(body), "id").String()
return githubId, nil
log.Debugf("Github user info: %s", gjson.ParseBytes(body).String())

return gjson.ParseBytes(body).String(), nil
}
6 changes: 3 additions & 3 deletions src/api/v1/oauth_client_lark.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,17 @@ func OauthLarkCallback(c *gin.Context) {
// save user info in redis (then retrive in login)
userInfo := gjson.Get(userInfoBody, "data")
model.Rdb.Set(model.RedisCtx, unionId,
userInfo, time.Duration(model.LARK_USER_INFO_EXP))

userInfo, time.Duration(model.OAUTH_USER_INFO_EXP))

// FIXME: Use OauthInfoByUID to get user
user, err := service.UserByLarkUnionID(unionId)
if err != nil {
c.JSON(http.StatusOK, result.Failed(result.InternalErr))
log.Log.Errorln("service.UserByLarkUnionID ::: ", err)
return
} else if user == nil {
// return with oauth lark ticket, which contains "union_id"
oauthToken, err := util.GenerateTokenWithExp(c, model.OauthSubKey(unionId), model.OAUTH_TICKET_EXP)
oauthToken, err := util.GenerateTokenWithExp(c, model.OauthSubKey(unionId, model.OAUTH_LARK_SUB), model.OAUTH_TICKET_EXP)

if err != nil {
c.JSON(http.StatusOK, result.Failed(result.GenerateToken))
Expand Down
Loading

0 comments on commit 7d4664c

Please sign in to comment.