diff --git a/backend/app/service/website_ca.go b/backend/app/service/website_ca.go
index 3a52dbbd5..6ba841fe9 100644
--- a/backend/app/service/website_ca.go
+++ b/backend/app/service/website_ca.go
@@ -381,6 +381,9 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
logger.Println(i18n.GetMsgByKey("ExecShellSuccess"))
}
}
+
+ reloadSystemSSL(websiteSSL, logger)
+
return websiteSSL, nil
}
diff --git a/backend/app/service/website_ssl.go b/backend/app/service/website_ssl.go
index 0cd752770..91eb47167 100644
--- a/backend/app/service/website_ssl.go
+++ b/backend/app/service/website_ssl.go
@@ -3,6 +3,7 @@ package service
import (
"context"
"crypto"
+ "crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
@@ -188,6 +189,31 @@ func printSSLLog(logger *log.Logger, msgKey string, params map[string]interface{
logger.Println(i18n.GetMsgWithMap(msgKey, params))
}
+func reloadSystemSSL(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
+ systemSSLEnable, sslID := GetSystemSSL()
+ if systemSSLEnable && sslID == websiteSSL.ID {
+ fileOp := files.NewFileOp()
+ certPath := path.Join(global.CONF.System.BaseDir, "1panel/secret/server.crt")
+ keyPath := path.Join(global.CONF.System.BaseDir, "1panel/secret/server.key")
+ printSSLLog(logger, "StartUpdateSystemSSL", nil, logger == nil)
+ if err := fileOp.WriteFile(certPath, strings.NewReader(websiteSSL.Pem), 0600); err != nil {
+ logger.Printf("Failed to update the SSL certificate File for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
+ return
+ }
+ if err := fileOp.WriteFile(keyPath, strings.NewReader(websiteSSL.PrivateKey), 0600); err != nil {
+ logger.Printf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
+ return
+ }
+ newCert, err := tls.X509KeyPair([]byte(websiteSSL.Pem), []byte(websiteSSL.PrivateKey))
+ if err != nil {
+ logger.Printf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
+ return
+ }
+ printSSLLog(logger, "UpdateSystemSSLSuccess", nil, logger == nil)
+ constant.CertStore.Store(&newCert)
+ }
+}
+
func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
var (
err error
@@ -344,6 +370,8 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
}
printSSLLog(logger, "ApplyWebSiteSSLSuccess", nil, apply.DisableLog)
}
+
+ reloadSystemSSL(websiteSSL, logger)
}()
return nil
diff --git a/backend/app/service/website_utils.go b/backend/app/service/website_utils.go
index e6380678a..88e256273 100644
--- a/backend/app/service/website_utils.go
+++ b/backend/app/service/website_utils.go
@@ -1002,23 +1002,22 @@ func saveCertificateFile(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
}
}
-func GetSystemSSL() (bool, bool, uint) {
+func GetSystemSSL() (bool, uint) {
sslSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
if err != nil {
global.LOG.Errorf("load service ssl from setting failed, err: %v", err)
- return false, false, 0
+ return false, 0
}
if sslSetting.Value == "enable" {
sslID, _ := settingRepo.Get(settingRepo.WithByKey("SSLID"))
idValue, _ := strconv.Atoi(sslID.Value)
if idValue <= 0 {
- return false, false, 0
+ return false, 0
}
- auto, _ := settingRepo.Get(settingRepo.WithByKey("AutoRestart"))
- return true, auto.Value == "enable", uint(idValue)
+ return true, uint(idValue)
}
- return false, false, 0
+ return false, 0
}
func UpdateSSLConfig(websiteSSL model.WebsiteSSL) error {
@@ -1037,22 +1036,7 @@ func UpdateSSLConfig(websiteSSL model.WebsiteSSL) error {
return buserr.WithErr(constant.ErrSSLApply, err)
}
}
- enable, auto, sslID := GetSystemSSL()
- if enable && sslID == websiteSSL.ID {
- fileOp := files.NewFileOp()
- secretDir := path.Join(global.CONF.System.BaseDir, "1panel/secret")
- if err := fileOp.WriteFile(path.Join(secretDir, "server.crt"), strings.NewReader(websiteSSL.Pem), 0600); err != nil {
- global.LOG.Errorf("Failed to update the SSL certificate File for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
- return err
- }
- if err := fileOp.WriteFile(path.Join(secretDir, "server.key"), strings.NewReader(websiteSSL.PrivateKey), 0600); err != nil {
- global.LOG.Errorf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
- return err
- }
- if auto {
- _, _ = cmd.Exec("systemctl restart 1panel.service")
- }
- }
+ reloadSystemSSL(&websiteSSL, nil)
return nil
}
diff --git a/backend/constant/common.go b/backend/constant/common.go
index 0864b633d..f9f0b33aa 100644
--- a/backend/constant/common.go
+++ b/backend/constant/common.go
@@ -1,5 +1,7 @@
package constant
+import "sync/atomic"
+
type DBContext string
const (
@@ -123,3 +125,5 @@ var DynamicRoutes = []string{
`^/databases/postgresql/setting/[^/]+/[^/]+$`,
`^/websites/[^/]+/config/[^/]+$`,
}
+
+var CertStore atomic.Value
diff --git a/backend/cron/job/ssl.go b/backend/cron/job/ssl.go
index f6f906516..685333dd9 100644
--- a/backend/cron/job/ssl.go
+++ b/backend/cron/job/ssl.go
@@ -1,8 +1,6 @@
package job
import (
- "path"
- "strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
@@ -10,9 +8,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/service"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
- "github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
- "github.com/1Panel-dev/1Panel/backend/utils/files"
)
type ssl struct {
@@ -23,7 +19,6 @@ func NewSSLJob() *ssl {
}
func (ssl *ssl) Run() {
- systemSSLEnable, auto, sslID := service.GetSystemSSL()
sslRepo := repo.NewISSLRepo()
sslService := service.NewIWebsiteSSLService()
sslList, _ := sslRepo.List()
@@ -59,22 +54,6 @@ func (ssl *ssl) Run() {
continue
}
}
- if systemSSLEnable && sslID == s.ID {
- websiteSSL, _ := sslRepo.GetFirst(repo.NewCommonRepo().WithByID(s.ID))
- fileOp := files.NewFileOp()
- secretDir := path.Join(global.CONF.System.BaseDir, "1panel/secret")
- if err := fileOp.WriteFile(path.Join(secretDir, "server.crt"), strings.NewReader(websiteSSL.Pem), 0600); err != nil {
- global.LOG.Errorf("Failed to update the SSL certificate File for 1Panel System domain [%s] , err:%s", s.PrimaryDomain, err.Error())
- continue
- }
- if err := fileOp.WriteFile(path.Join(secretDir, "server.key"), strings.NewReader(websiteSSL.PrivateKey), 0600); err != nil {
- global.LOG.Errorf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", s.PrimaryDomain, err.Error())
- continue
- }
- if auto {
- _, _ = cmd.Exec("systemctl restart 1panel.service")
- }
- }
global.LOG.Infof("The SSL certificate for the [%s] domain has been successfully updated", s.PrimaryDomain)
}
}
diff --git a/backend/i18n/lang/en.yaml b/backend/i18n/lang/en.yaml
index b62076f3b..9e123a8a7 100644
--- a/backend/i18n/lang/en.yaml
+++ b/backend/i18n/lang/en.yaml
@@ -127,6 +127,8 @@ ErrDefaultCA: "The default organization cannot be deleted"
ApplyWebSiteSSLLog: "Start updating {{ .name }} website certificate"
ErrUpdateWebsiteSSL: "{{ .name }} website failed to update certificate: {{ .err }}"
ApplyWebSiteSSLSuccess: "Update website certificate successfully"
+StartUpdateSystemSSL: "Start updating system certificate"
+UpdateSystemSSLSuccess: "Update system certificate successfully"
#mysql
ErrUserIsExist: "The current user already exists. Please enter a new user"
diff --git a/backend/i18n/lang/zh-Hant.yaml b/backend/i18n/lang/zh-Hant.yaml
index c5f10ead6..6b42011e0 100644
--- a/backend/i18n/lang/zh-Hant.yaml
+++ b/backend/i18n/lang/zh-Hant.yaml
@@ -126,6 +126,8 @@ ErrDefaultCA: "默認機構不能刪除"
ApplyWebSiteSSLLog: "開始更新 {{ .name }} 網站憑證"
ErrUpdateWebsiteSSL: "{{ .name }} 網站更新憑證失敗: {{ .err }}"
ApplyWebSiteSSLSuccess: "更新網站憑證成功"
+StartUpdateSystemSSL: "開始更新系統證書"
+UpdateSystemSSLSuccess: "更新系統證書成功"
#mysql
diff --git a/backend/i18n/lang/zh.yaml b/backend/i18n/lang/zh.yaml
index 4880df5f6..145c7e587 100644
--- a/backend/i18n/lang/zh.yaml
+++ b/backend/i18n/lang/zh.yaml
@@ -130,6 +130,8 @@ ApplyWebSiteSSLSuccess: "更新网站证书成功"
ErrExecShell: "执行脚本失败 {{ .err }}"
ExecShellStart: "开始执行脚本"
ExecShellSuccess: "脚本执行成功"
+StartUpdateSystemSSL: "开始更新系统证书"
+UpdateSystemSSLSuccess: "更新系统证书成功"
#mysql
ErrUserIsExist: "当前用户已存在,请重新输入"
diff --git a/backend/server/server.go b/backend/server/server.go
index a8d468690..eb5a4973b 100644
--- a/backend/server/server.go
+++ b/backend/server/server.go
@@ -4,13 +4,13 @@ import (
"crypto/tls"
"encoding/gob"
"fmt"
+ "github.com/1Panel-dev/1Panel/backend/constant"
+ "github.com/1Panel-dev/1Panel/backend/i18n"
"net"
"net/http"
"os"
"path"
- "github.com/1Panel-dev/1Panel/backend/i18n"
-
"github.com/1Panel-dev/1Panel/backend/init/app"
"github.com/1Panel-dev/1Panel/backend/init/business"
@@ -81,12 +81,16 @@ func Start() {
if err != nil {
panic(err)
}
+ constant.CertStore.Store(&cert)
+
server.TLSConfig = &tls.Config{
- Certificates: []tls.Certificate{cert},
+ GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return constant.CertStore.Load().(*tls.Certificate), nil
+ },
}
global.LOG.Infof("listen at https://%s:%s [%s]", global.CONF.System.BindAddress, global.CONF.System.Port, tcpItem)
- if err := server.ServeTLS(tcpKeepAliveListener{ln.(*net.TCPListener)}, certPath, keyPath); err != nil {
+ if err := server.ServeTLS(tcpKeepAliveListener{ln.(*net.TCPListener)}, "", ""); err != nil {
panic(err)
}
} else {
diff --git a/frontend/src/api/interface/setting.ts b/frontend/src/api/interface/setting.ts
index d908d586a..88ad99539 100644
--- a/frontend/src/api/interface/setting.ts
+++ b/frontend/src/api/interface/setting.ts
@@ -29,7 +29,6 @@ export namespace Setting {
bindAddress: string;
ssl: string;
sslType: string;
- autoRestart: string;
allowIPs: string;
bindDomain: string;
securityEntrance: string;
diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts
index 56064f84c..2de099497 100644
--- a/frontend/src/lang/modules/en.ts
+++ b/frontend/src/lang/modules/en.ts
@@ -1551,11 +1551,6 @@ const message = {
bindDomain: 'Bind Domain',
unBindDomain: 'Unbind domain',
panelSSL: 'Panel SSL',
- sslAutoRestart: 'Restart 1Panel service after certificate auto-renewal',
- sslChangeHelper1:
- 'Currently, automatic restart of 1Panel service is not selected. The certificate auto-renewal will not take effect immediately and will still require a manual restart of 1Panel.',
- sslChangeHelper2:
- 'The 1Panel service will automatically restart after setting the panel SSL. Do you want to continue?',
unBindDomainHelper:
'The action of unbinding a domain name may cause system insecurity. Do you want to continue?',
bindDomainHelper:
diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts
index 484e6b216..71fe21f8d 100644
--- a/frontend/src/lang/modules/tw.ts
+++ b/frontend/src/lang/modules/tw.ts
@@ -1494,9 +1494,6 @@ const message = {
bindDomain: '域名綁定',
unBindDomain: '域名解綁',
panelSSL: '面板 SSL',
- sslAutoRestart: '證書自動續期後重啟 1Panel 服務',
- sslChangeHelper1: '當前未勾選自動重啟 1Panel 服務,證書自動續期後不會立即生效,仍需手動重啟 1Panel。',
- sslChangeHelper2: '設置面板 SSL 後將自動重啟 1Panel 服務,是否繼續?',
unBindDomainHelper: '解除域名綁定可能造成系統不安全,是否繼續?',
bindDomainHelper: '設置域名綁定後,僅能通過設置中域名訪問 1Panel 服務',
bindDomainHelper1: '綁定域名為空時,則取消域名綁定',
diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts
index 6e7b7c3cd..d8538ddf0 100644
--- a/frontend/src/lang/modules/zh.ts
+++ b/frontend/src/lang/modules/zh.ts
@@ -1496,9 +1496,6 @@ const message = {
bindDomain: '域名绑定',
unBindDomain: '域名解绑',
panelSSL: '面板 SSL',
- sslAutoRestart: '证书自动续期后重启 1Panel 服务',
- sslChangeHelper1: '当前未勾选自动重启 1Panel 服务,证书自动续期后不会立即生效,仍需手动重启 1Panel。',
- sslChangeHelper2: '设置面板 SSL 后将自动重启 1Panel 服务,是否继续?',
unBindDomainHelper: '解除域名绑定可能造成系统不安全,是否继续?',
bindDomainHelper: '设置域名绑定后,仅能通过设置中域名访问 1Panel 服务',
bindDomainHelper1: '绑定域名为空时,则取消域名绑定',
diff --git a/frontend/src/routers/modules/setting.ts b/frontend/src/routers/modules/setting.ts
index 99e6def22..d0f8984f2 100644
--- a/frontend/src/routers/modules/setting.ts
+++ b/frontend/src/routers/modules/setting.ts
@@ -34,7 +34,7 @@ const settingRouter = {
hidden: true,
meta: {
requiresAuth: true,
- activeMenu: 'Setting',
+ activeMenu: '/settings',
},
},
{
@@ -44,7 +44,7 @@ const settingRouter = {
hidden: true,
meta: {
requiresAuth: true,
- activeMenu: 'Setting',
+ activeMenu: '/settings',
},
},
{
@@ -54,7 +54,7 @@ const settingRouter = {
hidden: true,
meta: {
requiresAuth: true,
- activeMenu: 'Setting',
+ activeMenu: '/settings',
},
},
{
@@ -64,7 +64,7 @@ const settingRouter = {
hidden: true,
meta: {
requiresAuth: true,
- activeMenu: 'Setting',
+ activeMenu: '/settings',
},
},
{
@@ -74,7 +74,7 @@ const settingRouter = {
component: () => import('@/views/setting/snapshot/index.vue'),
meta: {
requiresAuth: true,
- activeMenu: 'Setting',
+ activeMenu: '/settings',
},
},
{
@@ -84,7 +84,7 @@ const settingRouter = {
component: () => import('@/views/setting/expired.vue'),
meta: {
requiresAuth: true,
- activeMenu: 'Expired',
+ activeMenu: '/settings',
},
},
],
diff --git a/frontend/src/views/setting/safe/index.vue b/frontend/src/views/setting/safe/index.vue
index a9c959ff7..b37f66116 100644
--- a/frontend/src/views/setting/safe/index.vue
+++ b/frontend/src/views/setting/safe/index.vue
@@ -225,7 +225,6 @@ const form = reactive({
bindAddress: '',
ssl: 'disable',
sslType: 'self',
- autoRestart: 'disable',
securityEntrance: '',
expirationDays: 0,
expirationTime: '',
@@ -250,7 +249,6 @@ const search = async () => {
if (form.ssl === 'enable') {
loadInfo();
}
- form.autoRestart = res.data.autoRestart;
form.securityEntrance = res.data.securityEntrance;
form.expirationDays = Number(res.data.expirationDays);
form.expirationTime = res.data.expirationTime;
@@ -330,7 +328,6 @@ const handleSSL = async () => {
ssl: form.ssl,
sslType: form.sslType,
sslInfo: sslInfo.value,
- autoRestart: form.autoRestart,
};
sslRef.value!.acceptParams(params);
return;
diff --git a/frontend/src/views/setting/safe/ssl/index.vue b/frontend/src/views/setting/safe/ssl/index.vue
index c4c9119d8..5ae485d4e 100644
--- a/frontend/src/views/setting/safe/ssl/index.vue
+++ b/frontend/src/views/setting/safe/ssl/index.vue
@@ -112,14 +112,6 @@
-
-
- {{ $t('setting.sslAutoRestart') }}
-
-
- {{ $t('setting.sslChangeHelper1') }}
-
-
@@ -143,7 +135,7 @@ import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { downloadSSL, updateSSL } from '@/api/modules/setting';
import { Rules } from '@/global/form-rules';
-import { ElMessageBox, FormInstance } from 'element-plus';
+import { FormInstance } from 'element-plus';
import { Setting } from '@/api/interface/setting';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { GlobalStore } from '@/store';
@@ -162,7 +154,6 @@ const form = reactive({
key: '',
rootPath: '',
timeout: '',
- autoRestart: 'disable',
});
const rules = reactive({
@@ -179,7 +170,6 @@ const itemSSL = ref();
interface DialogProps {
sslType: string;
sslInfo?: Setting.SSLInfo;
- autoRestart: string;
}
const acceptParams = async (params: DialogProps): Promise => {
if (params.sslType.indexOf('-') !== -1) {
@@ -202,7 +192,6 @@ const acceptParams = async (params: DialogProps): Promise => {
} else {
loadSSLs();
}
- form.autoRestart = params.autoRestart;
drawerVisible.value = true;
};
const emit = defineEmits<{ (e: 'search'): void }>();
@@ -243,41 +232,31 @@ const onSaveSSL = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
- let msg = !form.autoRestart
- ? i18n.global.t('setting.sslChangeHelper1') + '\n\n\n' + 'qwdqwdqwd'
- : i18n.global.t('setting.sslChangeHelper2');
- ElMessageBox.confirm(msg, i18n.global.t('setting.panelSSL'), {
- confirmButtonText: i18n.global.t('commons.button.confirm'),
- cancelButtonText: i18n.global.t('commons.button.cancel'),
- type: 'info',
- }).then(async () => {
- let itemType = form.sslType;
- if (form.sslType === 'import') {
- itemType = form.itemSSLType === 'paste' ? 'import-paste' : 'import-local';
- }
- let param = {
- ssl: 'enable',
- sslType: itemType,
- domain: '',
- sslID: form.sslID,
- cert: form.cert,
- key: form.key,
- autoRestart: form.autoRestart,
- };
+ let itemType = form.sslType;
+ if (form.sslType === 'import') {
+ itemType = form.itemSSLType === 'paste' ? 'import-paste' : 'import-local';
+ }
+ let param = {
+ ssl: 'enable',
+ sslType: itemType,
+ domain: '',
+ sslID: form.sslID,
+ cert: form.cert,
+ key: form.key,
+ };
+ let href = window.location.href;
+ param.domain = href.split('//')[1].split(':')[0];
+ await updateSSL(param).then(() => {
+ MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
let href = window.location.href;
- param.domain = href.split('//')[1].split(':')[0];
- await updateSSL(param).then(() => {
- MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
- let href = window.location.href;
- globalStore.isLogin = false;
- let address = href.split('://')[1];
- if (globalStore.entrance) {
- address = address.replaceAll('settings/safe', globalStore.entrance);
- } else {
- address = address.replaceAll('settings/safe', 'login');
- }
- window.open(`https://${address}`, '_self');
- });
+ globalStore.isLogin = false;
+ let address = href.split('://')[1];
+ if (globalStore.entrance) {
+ address = address.replaceAll('settings/safe', globalStore.entrance);
+ } else {
+ address = address.replaceAll('settings/safe', 'login');
+ }
+ window.open(`https://${address}`, '_self');
});
});
};
diff --git a/go.mod b/go.mod
index 59bcc4a92..b41be18ae 100644
--- a/go.mod
+++ b/go.mod
@@ -15,7 +15,7 @@ require (
github.com/gin-contrib/gzip v0.0.6
github.com/gin-gonic/gin v1.9.1
github.com/glebarez/sqlite v1.10.0
- github.com/go-acme/lego/v4 v4.20.2
+ github.com/go-acme/lego/v4 v4.20.4
github.com/go-gormigrate/gormigrate/v2 v2.1.1
github.com/go-playground/validator/v10 v10.18.0
github.com/go-redis/redis v6.15.9+incompatible
diff --git a/go.sum b/go.sum
index 38bd1cd3f..b3703193a 100644
--- a/go.sum
+++ b/go.sum
@@ -318,8 +318,8 @@ github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc=
github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA=
-github.com/go-acme/lego/v4 v4.20.2 h1:ZwO3oLZb8fL6up1OZVJP3yHuvqhozzlEmyqKmhrPchQ=
-github.com/go-acme/lego/v4 v4.20.2/go.mod h1:foauPlhnhoq8WUphaWx5U04uDc+JGhk4ZZtPz/Vqsjg=
+github.com/go-acme/lego/v4 v4.20.4 h1:yCQGBX9jOfMbriEQUocdYm7EBapdTp8nLXYG8k6SqSU=
+github.com/go-acme/lego/v4 v4.20.4/go.mod h1:foauPlhnhoq8WUphaWx5U04uDc+JGhk4ZZtPz/Vqsjg=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=