gitea支持启动时指定clientId和接口地址等

This commit is contained in:
xiaoqi.cxq 2022-10-02 00:20:01 +08:00
parent 95d27a4a0a
commit 21a3e59b5d
7 changed files with 142 additions and 38 deletions

View File

@ -15,6 +15,9 @@ wordpressSecret: ""
paypalReceiverEmail: "" paypalReceiverEmail: ""
awsAccessKeyId: "" awsAccessKeyId: ""
awsSecretAccessKey: "" awsSecretAccessKey: ""
giteaClientId: ""
giteaClientSecret: ""
giteaUrl: ""
replicaCount: 1 replicaCount: 1

View File

@ -9,4 +9,7 @@ module.exports = merge(prodEnv, {
GITEE_CLIENT_ID: '"925ba7c78b85dec984f7877e4aca5cab10ae333c6d68e761bdb0b9dfb8f55672"', GITEE_CLIENT_ID: '"925ba7c78b85dec984f7877e4aca5cab10ae333c6d68e761bdb0b9dfb8f55672"',
GITEE_CLIENT_SECRET: '"f05731066e42d307339dc8ebbb037a103881dafc7207a359a393b87749f1c562"', GITEE_CLIENT_SECRET: '"f05731066e42d307339dc8ebbb037a103881dafc7207a359a393b87749f1c562"',
CLIENT_ID: '"thF3qCGLN39OtafjGnqHyj6n02WwE6xD"', CLIENT_ID: '"thF3qCGLN39OtafjGnqHyj6n02WwE6xD"',
// GITEA_CLIENT_ID: '"fe30f8f9-b1e8-4531-8f72-c1a5d3912805"',
// GITEA_CLIENT_SECRET: '"lus7oMnb3H6M1hsChndphArE20Txr7erwJLf7SDBQWTw"',
// GITEA_URL: '"https://gitea.test.com"',
}) })

View File

@ -13,6 +13,9 @@ const giteeClientSecret = process.env.GITEE_CLIENT_SECRET;
const googleClientId = process.env.GOOGLE_CLIENT_ID; const googleClientId = process.env.GOOGLE_CLIENT_ID;
const googleApiKey = process.env.GOOGLE_API_KEY; const googleApiKey = process.env.GOOGLE_API_KEY;
const wordpressClientId = process.env.WORDPRESS_CLIENT_ID; const wordpressClientId = process.env.WORDPRESS_CLIENT_ID;
const giteaClientId = process.env.GITEA_CLIENT_ID;
const giteaClientSecret = process.env.GITEA_CLIENT_SECRET;
const giteaUrl = process.env.GITEA_URL;
exports.values = { exports.values = {
pandocPath, pandocPath,
@ -29,6 +32,9 @@ exports.values = {
googleClientId, googleClientId,
googleApiKey, googleApiKey,
wordpressClientId, wordpressClientId,
giteaClientId,
giteaClientSecret,
giteaUrl,
}; };
exports.publicValues = { exports.publicValues = {
@ -39,4 +45,6 @@ exports.publicValues = {
googleApiKey, googleApiKey,
wordpressClientId, wordpressClientId,
allowSponsorship: !!paypalReceiverEmail, allowSponsorship: !!paypalReceiverEmail,
giteaClientId,
giteaUrl,
}; };

41
server/gitea.js Normal file
View File

@ -0,0 +1,41 @@
const qs = require('qs');
const request = require('request');
const conf = require('./conf');
function giteaToken(queryParam) {
return new Promise((resolve, reject) => {
request({
method: 'POST',
url: `${conf.values.giteaUrl}/login/oauth/access_token`,
headers: {
'content-type': 'application/json',
},
json: true,
body: {
...queryParam,
client_id: conf.values.giteaClientId,
client_secret: conf.values.giteaClientSecret,
},
}, (err, res, body) => {
if (err) {
reject(err);
}
const token = body.access_token;
if (token) {
resolve(body);
} else {
reject(res.statusCode + ',body:' + JSON.stringify(body));
}
});
});
}
exports.giteaToken = (req, res) => {
giteaToken(req.query)
.then(
tokenBody => res.send(tokenBody),
err => res
.status(400)
.send(err ? err.message || err.toString() : 'bad_code'),
);
};

View File

@ -5,6 +5,7 @@ const path = require('path');
const user = require('./user'); const user = require('./user');
const github = require('./github'); const github = require('./github');
const gitee = require('./gitee'); const gitee = require('./gitee');
const gitea = require('./gitea');
const pdf = require('./pdf'); const pdf = require('./pdf');
const pandoc = require('./pandoc'); const pandoc = require('./pandoc');
const conf = require('./conf'); const conf = require('./conf');
@ -27,6 +28,7 @@ module.exports = (app) => {
app.get('/oauth2/githubToken', github.githubToken); app.get('/oauth2/githubToken', github.githubToken);
app.get('/oauth2/giteeToken', gitee.giteeToken); app.get('/oauth2/giteeToken', gitee.giteeToken);
app.get('/oauth2/giteaToken', gitea.giteaToken);
app.get('/conf', (req, res) => res.send(conf.publicValues)); app.get('/conf', (req, res) => res.send(conf.publicValues));
app.get('/userInfo', user.userInfo); app.get('/userInfo', user.userInfo);
app.post('/pdfExport', pdf.generate); app.post('/pdfExport', pdf.generate);

View File

@ -5,28 +5,30 @@
<icon-provider provider-id="gitea"></icon-provider> <icon-provider provider-id="gitea"></icon-provider>
</div> </div>
<p>将您的<b>Gitea</b>链接到<b>StackEdit中文版</b></p> <p>将您的<b>Gitea</b>链接到<b>StackEdit中文版</b></p>
<form-entry label="Gitea URL" error="serverUrl"> <template v-if="!useServerConf">
<input v-if="config.forceServerUrl" slot="field" class="textfield" type="text" disabled="disabled" v-model="config.forceServerUrl"> <form-entry label="Gitea URL" error="serverUrl">
<input v-else slot="field" class="textfield" type="text" v-model.trim="serverUrl" @keydown.enter="resolve()"> <input v-if="config.forceServerUrl" slot="field" class="textfield" type="text" disabled="disabled" v-model="config.forceServerUrl">
<div class="form-entry__info"> <input v-else slot="field" class="textfield" type="text" v-model.trim="serverUrl" @keydown.enter="resolve()">
<b>例如:</b> https://gitea.example.com/ <div class="form-entry__info">
<span v-if="httpAppUrl"> <b>例如:</b> https://gitea.example.com/
非https的URL请跳转到 <a :href="httpAppUrl" target="_blank">HTTP链接</a> 添加Gitea <span v-if="httpAppUrl">
</span> 非https的URL请跳转到 <a :href="httpAppUrl" target="_blank">HTTP链接</a> 添加Gitea
</div> </span>
</form-entry> </div>
<form-entry label="Application ID" error="applicationId"> </form-entry>
<input slot="field" class="textfield" type="text" v-model.trim="applicationId" @keydown.enter="resolve()"> <form-entry label="Application ID" error="applicationId">
</form-entry> <input slot="field" class="textfield" type="text" v-model.trim="applicationId" @keydown.enter="resolve()">
<form-entry label="Application Secret" error="applicationSecret"> </form-entry>
<input slot="field" class="textfield" type="text" v-model.trim="applicationSecret" @keydown.enter="resolve()"> <form-entry label="Application Secret" error="applicationSecret">
<div class="form-entry__info"> <input slot="field" class="textfield" type="text" v-model.trim="applicationSecret" @keydown.enter="resolve()">
您必须使用重定向url <b>{{redirectUrl}}</b>配置OAuth2应用程序 <div class="form-entry__info">
</div> 您必须使用重定向url <b>{{redirectUrl}}</b>配置OAuth2应用程序
<div class="form-entry__actions"> </div>
<a href="https://docs.gitea.io/en-us/oauth2-provider/" target="_blank">更多信息</a> <div class="form-entry__actions">
</div> <a href="https://docs.gitea.io/en-us/oauth2-provider/" target="_blank">更多信息</a>
</form-entry> </div>
</form-entry>
</template>
</div> </div>
<div class="modal__button-bar"> <div class="modal__button-bar">
<button class="button" @click="config.reject()">取消</button> <button class="button" @click="config.reject()">取消</button>
@ -38,6 +40,7 @@
<script> <script>
import modalTemplate from '../common/modalTemplate'; import modalTemplate from '../common/modalTemplate';
import constants from '../../../data/constants'; import constants from '../../../data/constants';
import store from '../../../store';
export default modalTemplate({ export default modalTemplate({
data: () => ({ data: () => ({
@ -55,9 +58,19 @@ export default modalTemplate({
} }
return null; return null;
}, },
// 使
useServerConf() {
const confClientId = store.getters['data/serverConf'].giteaClientId;
const confServerUrl = store.getters['data/serverConf'].giteaUrl;
return !!confClientId && !!confServerUrl;
},
}, },
methods: { methods: {
resolve() { resolve() {
if (this.useServerConf) {
this.config.resolve({});
return;
}
const serverUrl = this.config.forceServerUrl || this.serverUrl; const serverUrl = this.config.forceServerUrl || this.serverUrl;
if (!serverUrl) { if (!serverUrl) {
this.setError('serverUrl'); this.setError('serverUrl');

View File

@ -57,27 +57,61 @@ export default {
serverUrl, applicationId, applicationSecret, serverUrl, applicationId, applicationSecret,
sub = null, silent = false, refreshToken, sub = null, silent = false, refreshToken,
) { ) {
let apiUrl = serverUrl;
let clientId = applicationId;
let useServerConf = false;
// 获取gitea配置的参数
const confClientId = store.getters['data/serverConf'].giteaClientId;
const confServerUrl = store.getters['data/serverConf'].giteaUrl;
// 存在gitea配置则使用后端配置
if (confClientId && confServerUrl) {
apiUrl = confServerUrl;
clientId = confClientId;
useServerConf = true;
}
let tokenBody; let tokenBody;
if (!silent) { if (!silent) {
// Get an OAuth2 code // Get an OAuth2 code
const { code } = await networkSvc.startOauth2( const { code } = await networkSvc.startOauth2(
`${serverUrl}/login/oauth/authorize`, `${apiUrl}/login/oauth/authorize`,
{ {
client_id: applicationId, client_id: clientId,
response_type: 'code', response_type: 'code',
redirect_uri: constants.oauth2RedirectUri, redirect_uri: constants.oauth2RedirectUri,
}, },
silent, silent,
); );
// Exchange code with token if (useServerConf) {
tokenBody = (await networkSvc.request({
method: 'GET',
url: 'oauth2/giteaToken',
params: {
code,
grant_type: 'authorization_code',
redirect_uri: constants.oauth2RedirectUri,
},
})).body;
} else {
// Exchange code with token
tokenBody = (await networkSvc.request({
method: 'POST',
url: `${apiUrl}/login/oauth/access_token`,
body: {
client_id: clientId,
client_secret: applicationSecret,
code,
grant_type: 'authorization_code',
redirect_uri: constants.oauth2RedirectUri,
},
})).body;
}
} else if (useServerConf) {
tokenBody = (await networkSvc.request({ tokenBody = (await networkSvc.request({
method: 'POST', method: 'GET',
url: `${serverUrl}/login/oauth/access_token`, url: 'oauth2/giteaToken',
body: { params: {
client_id: applicationId, refresh_token: refreshToken,
client_secret: applicationSecret, grant_type: 'refresh_token',
code,
grant_type: 'authorization_code',
redirect_uri: constants.oauth2RedirectUri, redirect_uri: constants.oauth2RedirectUri,
}, },
})).body; })).body;
@ -85,9 +119,9 @@ export default {
// Exchange refreshToken with token // Exchange refreshToken with token
tokenBody = (await networkSvc.request({ tokenBody = (await networkSvc.request({
method: 'POST', method: 'POST',
url: `${serverUrl}/login/oauth/access_token`, url: `${apiUrl}/login/oauth/access_token`,
body: { body: {
client_id: applicationId, client_id: clientId,
client_secret: applicationSecret, client_secret: applicationSecret,
refresh_token: refreshToken, refresh_token: refreshToken,
grant_type: 'refresh_token', grant_type: 'refresh_token',
@ -99,10 +133,10 @@ export default {
const accessToken = tokenBody.access_token; const accessToken = tokenBody.access_token;
// Call the user info endpoint // Call the user info endpoint
const user = await request({ accessToken, serverUrl }, { const user = await request({ accessToken, serverUrl: apiUrl }, {
url: 'user', url: 'user',
}); });
const uniqueSub = `${serverUrl}/${user.username}`; const uniqueSub = `${apiUrl}/${user.username}`;
userSvc.addUserInfo({ userSvc.addUserInfo({
id: `${subPrefix}:${uniqueSub}`, id: `${subPrefix}:${uniqueSub}`,
name: user.username, name: user.username,
@ -119,12 +153,12 @@ export default {
const token = { const token = {
accessToken, accessToken,
name: user.username, name: user.username,
applicationId, applicationId: clientId,
applicationSecret, applicationSecret,
imgStorages: oldToken && oldToken.imgStorages, imgStorages: oldToken && oldToken.imgStorages,
refreshToken: tokenBody.refresh_token, refreshToken: tokenBody.refresh_token,
expiresOn: Date.now() + (tokenBody.expires_in * 1000), expiresOn: Date.now() + (tokenBody.expires_in * 1000),
serverUrl, serverUrl: apiUrl,
sub: uniqueSub, sub: uniqueSub,
}; };