gitea支持启动时指定clientId和接口地址等
This commit is contained in:
		
							parent
							
								
									95d27a4a0a
								
							
						
					
					
						commit
						21a3e59b5d
					
				@ -15,6 +15,9 @@ wordpressSecret: ""
 | 
				
			|||||||
paypalReceiverEmail: ""
 | 
					paypalReceiverEmail: ""
 | 
				
			||||||
awsAccessKeyId: ""
 | 
					awsAccessKeyId: ""
 | 
				
			||||||
awsSecretAccessKey: ""
 | 
					awsSecretAccessKey: ""
 | 
				
			||||||
 | 
					giteaClientId: ""
 | 
				
			||||||
 | 
					giteaClientSecret: ""
 | 
				
			||||||
 | 
					giteaUrl: ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
replicaCount: 1
 | 
					replicaCount: 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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"',
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
@ -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
									
								
							
							
						
						
									
										41
									
								
								server/gitea.js
									
									
									
									
									
										Normal 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'),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -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);
 | 
				
			||||||
 | 
				
			|||||||
@ -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');
 | 
				
			||||||
 | 
				
			|||||||
@ -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,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user