forked from Deuxfleurs/guichet
Compare commits
28 commits
Author | SHA1 | Date | |
---|---|---|---|
3095f1726e | |||
b319421c1f | |||
48526f6aca | |||
492be02f59 | |||
4dfd072385 | |||
08b036b2fb | |||
c1fcc1bbba | |||
97a0d1ed24 | |||
56d78d4a1f | |||
9fef8d855f | |||
a7180549ed | |||
59b8ecf02f | |||
0d3457142e | |||
f8a3714d8c | |||
791f6aa3b8 | |||
8a939391d5 | |||
f53b100752 | |||
057f84e663 | |||
e3512bf3f1 | |||
371c46e0ed | |||
917c10737d | |||
4f3b5d8210 | |||
48df2123cf | |||
6a399249b5 | |||
dd3e1833f7 | |||
34c2ddc29e | |||
|
a0e5c1020b | ||
|
687fbe8b59 |
13 changed files with 155 additions and 116 deletions
19
Makefile
19
Makefile
|
@ -1,19 +0,0 @@
|
|||
BIN=guichet
|
||||
SRC=main.go ssha.go profile.go admin.go invite.go directory.go picture.go
|
||||
DOCKER=lxpz/guichet_amd64
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
$(BIN): $(SRC)
|
||||
go get -d -v
|
||||
go build -v -o $(BIN)
|
||||
|
||||
$(BIN).static: $(SRC)
|
||||
go get -d -v
|
||||
CGO_ENABLED=0 GOOS=linux go build -a -v -o $(BIN).static
|
||||
|
||||
docker: $(BIN).static
|
||||
docker build -t $(DOCKER):$(TAG) .
|
||||
docker push $(DOCKER):$(TAG)
|
||||
docker tag $(DOCKER):$(TAG) $(DOCKER):latest
|
||||
docker push $(DOCKER):latest
|
81
README.md
81
README.md
|
@ -8,10 +8,10 @@ Guichet is a simple LDAP web interface for the following tasks:
|
|||
- administration of the LDAP directory
|
||||
- inviting new users to create accounts
|
||||
|
||||
Guichet works well with the [Bottin](https://bottin.eu) LDAP server.
|
||||
Guichet works well with the [Bottin](https://git.deuxfleurs.fr/deuxfleurs/bottin) LDAP server.
|
||||
Currently, Guichet's templates are only in French as it has been created for
|
||||
the [Deuxfleurs](https://deuxfleurs.fr) collective.
|
||||
We would gladly merge a pull request with an English transaltion !
|
||||
We would gladly merge a pull request with an English translation !
|
||||
|
||||
A Docker image is provided on the [Docker hub](https://hub.docker.com/r/lxpz/guichet_amd64).
|
||||
An example for running Guichet on a Nomad cluster can be found in `guichet.hcl.example`.
|
||||
|
@ -27,9 +27,23 @@ Guichet is licensed under the terms of the GPLv3.
|
|||
|
||||
Guichet requires go 1.13 or later.
|
||||
|
||||
To build Guichet, clone this repository outside of your `$GOPATH`.
|
||||
Then, run `make` in the root of the repo.
|
||||
Development build:
|
||||
|
||||
```
|
||||
go build
|
||||
```
|
||||
|
||||
Production build:
|
||||
|
||||
```
|
||||
nix build
|
||||
```
|
||||
|
||||
Production container:
|
||||
|
||||
```
|
||||
docker run .#docker
|
||||
```
|
||||
|
||||
## Configuration of Guichet
|
||||
|
||||
|
@ -129,3 +143,62 @@ Here is an example of Bottin ACLs that may be used to support Guichet invitation
|
|||
|
||||
Consult [this directory](https://git.deuxfleurs.fr/Deuxfleurs/infrastructure/src/branch/main/app/directory/config)
|
||||
to view the full configuration in use on Deuxfleurs.
|
||||
|
||||
## Contribute & local development
|
||||
|
||||
Guichet needs a few components to work :
|
||||
- A Bottin server
|
||||
- that needs a consul server
|
||||
- And a Garage cluster (of at least one node)
|
||||
A basic consul / bottin stack is available through the docker compose file you can find in `integration` subdirectory:
|
||||
|
||||
```sh
|
||||
cd integration
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
You can then run Guichet locally :
|
||||
```sh
|
||||
# First, copy a sample config file
|
||||
copy config.json.example config.json
|
||||
|
||||
# Run the go development server
|
||||
go run .
|
||||
```
|
||||
|
||||
It will be available on http://localhost:9991.
|
||||
|
||||
### First run
|
||||
|
||||
#### How to get my admin password
|
||||
|
||||
On first Bottin's run, it is displayed in the logs.
|
||||
You can easily find it by reading the container logs :
|
||||
```sh
|
||||
docker compose logs bottin | grep password:
|
||||
```
|
||||
|
||||
- The **username** is provided in the log, and should look like this: `cn=admin,dc=bottin,dc=eu`.
|
||||
- The **password** is right after in the same log line.
|
||||
|
||||
|
||||
#### Garage
|
||||
⚠️ Be aware at this stage that your local Guichet installation is not 100% working, especially the websites features.
|
||||
You need to initialise Garage. It can be done in a few commands, coming from [the official Garage's documentation](https://garagehq.deuxfleurs.fr/documentation/quick-start/):
|
||||
|
||||
```sh
|
||||
# Find your Garage node ID
|
||||
docker compose exec garage /garage
|
||||
|
||||
# Your id is eb820c8da5605f78 in the output below
|
||||
ID Hostname Address Tags Zone Capacity DataAvail
|
||||
eb820c8da5605f78 9bd710b31be0 127.0.0.1:3901 NO ROLE ASSIGNED
|
||||
|
||||
# Then create a cluster layout with this id
|
||||
docker compose exec garage /garage layout assign -z dc1 -c 1G eb820c8da5605f78
|
||||
|
||||
# Finally, apply the layout
|
||||
docker compose exec garage /garage layout apply
|
||||
```
|
||||
|
||||
🎉 You now can go to http://localhost:9991/website without getting 503 errors.
|
||||
|
|
|
@ -47,9 +47,18 @@
|
|||
Entrypoint = "/bin/guichet";
|
||||
};
|
||||
};
|
||||
|
||||
docker = pkgs.writeScriptBin "guichet-docker" ''
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
docker load <$(nix build --print-out-paths .#container)
|
||||
'';
|
||||
|
||||
in {
|
||||
packages.x86_64-linux.guichet = guichet;
|
||||
packages.x86_64-linux.container = container;
|
||||
packages.x86_64-linux.docker = docker;
|
||||
packages.x86_64-linux.default = guichet;
|
||||
|
||||
devShell.x86_64-linux = pkgs.mkShell { nativeBuildInputs = [ pkgs.go pkgs.gomod2nix ]; };
|
||||
|
|
2
go.sum
2
go.sum
|
@ -31,8 +31,6 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
|||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang v0.0.0-20230131081355-c965fe7f7dc9 h1:ERg8KCpIKym98EOKa8Gq0NSBxsasD3sqb/R0gg1wOzU=
|
||||
git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang v0.0.0-20230131081355-c965fe7f7dc9/go.mod h1:TlSL6QVxozmdRaSgP6Akspi0HCJv4HAkkq3Dldru4GM=
|
||||
git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang v0.0.0-20231128153612-8b81fae65e5e h1:h89CAh0qmUcGJykss/utXIw+yRGa3Gr6VyrZ5ZWN0kY=
|
||||
git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang v0.0.0-20231128153612-8b81fae65e5e/go.mod h1:TlSL6QVxozmdRaSgP6Akspi0HCJv4HAkkq3Dldru4GM=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
|
|
|
@ -21,7 +21,7 @@ services:
|
|||
garage:
|
||||
# sync with deuxfleurs/nixcfg/cluster/prod/app/garage/deploy/garage.hcl
|
||||
# to ensure compatibility with prod
|
||||
image: superboum/garage:v1.0.0-rc1-hotfix-red-ftr-wquorum
|
||||
image: dxflrs/garage:v1.99.1-internal
|
||||
ports:
|
||||
- "3900:3900"
|
||||
- "3902:3902"
|
||||
|
|
52
invite.go
52
invite.go
|
@ -1,19 +1,15 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/emersion/go-sasl"
|
||||
"github.com/emersion/go-smtp"
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/gorilla/mux"
|
||||
"golang.org/x/crypto/argon2"
|
||||
|
@ -251,21 +247,11 @@ func handleInviteSendCode(w http.ResponseWriter, r *http.Request) {
|
|||
WebBaseAddress: config.WebAddress,
|
||||
}
|
||||
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
|
||||
choice := strings.Join(r.Form["choice"], "")
|
||||
sendto := strings.Join(r.Form["sendto"], "")
|
||||
|
||||
if choice == "display" || choice == "send" {
|
||||
trySendCode(user, choice, sendto, data)
|
||||
}
|
||||
}
|
||||
|
||||
tryGenerateInvitation(user, data)
|
||||
templateInviteSendCode.Execute(w, data)
|
||||
}
|
||||
|
||||
func trySendCode(user *LoggedUser, choice string, sendto string, data *SendCodeData) {
|
||||
func tryGenerateInvitation(user *LoggedUser, data *SendCodeData) {
|
||||
// Generate code
|
||||
code, code_id, code_pw := genCode()
|
||||
|
||||
|
@ -286,43 +272,9 @@ func trySendCode(user *LoggedUser, choice string, sendto string, data *SendCodeD
|
|||
return
|
||||
}
|
||||
|
||||
// If we want to display it, do so
|
||||
if choice == "display" {
|
||||
data.Success = true
|
||||
data.CodeDisplay = code
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, we are sending a mail
|
||||
if !EMAIL_REGEXP.MatchString(sendto) {
|
||||
data.ErrorInvalidEmail = true
|
||||
return
|
||||
}
|
||||
|
||||
templateMail := template.Must(template.ParseFiles(templatePath + "/invite_mail.txt"))
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
templateMail.Execute(buf, &CodeMailFields{
|
||||
To: sendto,
|
||||
From: config.MailFrom,
|
||||
InviteFrom: user.WelcomeName(),
|
||||
Code: code,
|
||||
WebBaseAddress: config.WebAddress,
|
||||
})
|
||||
|
||||
log.Printf("Sending mail to: %s", sendto)
|
||||
var auth sasl.Client = nil
|
||||
if config.SMTPUsername != "" {
|
||||
auth = sasl.NewPlainClient("", config.SMTPUsername, config.SMTPPassword)
|
||||
}
|
||||
err = smtp.SendMail(config.SMTPServer, auth, config.MailFrom, []string{sendto}, buf)
|
||||
if err != nil {
|
||||
data.ErrorMessage = err.Error()
|
||||
return
|
||||
}
|
||||
log.Printf("Mail sent.")
|
||||
|
||||
data.Success = true
|
||||
data.CodeSentTo = sendto
|
||||
}
|
||||
|
||||
func genCode() (code string, code_id string, code_pw string) {
|
||||
|
|
9
main.go
9
main.go
|
@ -237,8 +237,6 @@ func handleLogout(w http.ResponseWriter, r *http.Request) {
|
|||
// --- Login Controller ---
|
||||
type LoginFormData struct {
|
||||
Username string
|
||||
WrongUser bool
|
||||
WrongPass bool
|
||||
ErrorMessage string
|
||||
}
|
||||
|
||||
|
@ -266,10 +264,9 @@ func handleLogin(w http.ResponseWriter, r *http.Request) {
|
|||
data := &LoginFormData{
|
||||
Username: username,
|
||||
}
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials) {
|
||||
data.WrongPass = true
|
||||
} else if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
data.WrongUser = true
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials) ||
|
||||
ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
data.ErrorMessage = "Le mot de passe et identifiant ne correspondent pas."
|
||||
} else {
|
||||
data.ErrorMessage = err.Error()
|
||||
}
|
||||
|
|
|
@ -15,7 +15,21 @@ paths:
|
|||
operationId: "ListWebsites"
|
||||
summary: "List all websites"
|
||||
description: |
|
||||
List all the user's websites
|
||||
List all the user's websites.
|
||||
|
||||
Also includes information about global quotas for the user, and for each website, bucket names and website URL.
|
||||
|
||||
- `username`: the name of the user making the request.
|
||||
- `quota_website_count` indicates the quota of the number of websites that the user is allowed to create.
|
||||
|
||||
- Website size is set at 100MB by default, and users can increase this quota autonomously up to a certain value defined by `burst_bucket_quota_size`, by default it's set to 200MB but it can be overriden on a per-user basis.
|
||||
|
||||
- Each element of the `vhosts` array describes a website. A website is described by:
|
||||
+ `name`: current main name of the website, which determines the URL it can be accessed from (specified in `domain`). This is also a name of the S3 bucket storing the website.
|
||||
+ `alt_name`: an array of aliases for the website. These can also be used to access the S3 bucket storing the website (a bucket can have several aliased names), but cannot be used in a URL to access the website.
|
||||
+ `expanded`: whether the bucket name already corresponds to a full URL for the website
|
||||
+ `domain`: the URL at which the website can be reached
|
||||
|
||||
responses:
|
||||
'500':
|
||||
description: |
|
||||
|
@ -23,7 +37,6 @@ paths:
|
|||
'200':
|
||||
description: |
|
||||
Returns information about all the user's websites, and user information related to websites.
|
||||
The website quota (`quota_website_count`) indicates a quota in number of websites that the user is allowed to create. Website size is set at 100MB by default, and users can increase this quota autonomously up to a certain value defined by `burst_bucket_quota_size`, by default it's set to 200MB but it can be overriden on a per-user basis.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
|
@ -58,10 +71,13 @@ paths:
|
|||
summary: "Details on a website"
|
||||
description: |
|
||||
Gets the configuration and status for the website `vhost`.
|
||||
This includes information about domains, bucket access keys, and quotas.
|
||||
This includes information about bucket names, domains, bucket access keys, and quotas.
|
||||
|
||||
`quota_size` is given in bytes.
|
||||
`quota_files` indicates a number of files.
|
||||
- `vhost` contains informations about bucket names and the website URL. See the documentation of the response of "List all websites" for more information
|
||||
- `access_key_id`: the S3 access key id for the bucket
|
||||
- `secret_access_key`: the S3 secret access key for the bucket
|
||||
- `quota_size`: the quota for the size of the website, in bytes.
|
||||
- `quota_files`: the quota for the number of files.
|
||||
responses:
|
||||
'500':
|
||||
description: |
|
||||
|
@ -97,7 +113,7 @@ paths:
|
|||
Request forbidden, you have reached your quota of maximum number of websites allowed.
|
||||
'200':
|
||||
description: |
|
||||
Returns information about the website that has been created.
|
||||
Returns information about the website that has been created. (See the documentation of "Details on a website" for more info.)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
|
@ -144,7 +160,7 @@ paths:
|
|||
Website not found
|
||||
'200':
|
||||
description: |
|
||||
Returns updated information about the website
|
||||
Returns updated information about the website. (See the documentation of "Details on a website" for more info.)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
|
|
|
@ -57,9 +57,9 @@
|
|||
</div>
|
||||
<div>
|
||||
<p>Vous devez éditer votre zone DNS, souvent gérée par votre bureau d'enregistrement, comme Gandi, pour la faire pointer vers Deuxfleurs. Si vous utilisez un sous domaine (eg. <code>site.example.com</code>), une entrée <code>CNAME</code> est appropriée :</p>
|
||||
<pre>site CNAME 3600 garage.deuxfleurs.fr.</pre>
|
||||
<pre>site CNAME 3600 global.site.deuxfleurs.fr.</pre>
|
||||
<p>Si vous utilisez la racine de votre nom de domaine (eg. <code>example.com</code>, aussi appelée APEX), la solution dépend de votre fournisseur DNS, il vous faudra au choix une entrée <code>ALIAS</code> ou <code>CNAME</code> en fonction de ce que votre fournisseur supporte :</p>
|
||||
<pre>@ ALIAS 3600 garage.deuxfleurs.fr.</pre>
|
||||
<pre>@ ALIAS 3600 global.site.deuxfleurs.fr.</pre>
|
||||
<p>La première fois que vous chargerez votre site web, une erreur de certificat sera renvoyée. C'est normal, il faudra patienter quelques minutes le temps que le certificat se génère.</p>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
|
|
|
@ -42,7 +42,12 @@
|
|||
</p>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h2>{{ .View.Name.Url }}</h2>
|
||||
<div>
|
||||
<a href="https://{{ .View.Name.Url }}" target="_blank" rel="noreferrer external" class="btn btn-dark">Visiter</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- QUOTAS -->
|
||||
|
||||
|
@ -76,7 +81,10 @@
|
|||
<h5 class="mt-3">Informations de connexion</h5>
|
||||
<ul class="nav nav-tabs" id="proto" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="s3-tab" data-toggle="tab" href="#s3" role="tab" aria-controls="s3" aria-selected="true">S3 (recommandé)</a>
|
||||
<a class="nav-link active" id="dxfl-tab" data-toggle="tab" href="#dxfl" role="tab" aria-controls="dxfl" aria-selected="true">dxfl (recommandé)</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="s3-tab" data-toggle="tab" href="#s3" role="tab" aria-controls="s3" aria-selected="false">S3</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="sftp-tab" data-toggle="tab" href="#sftp" role="tab" aria-controls="sftp" aria-selected="false">SFTP</a>
|
||||
|
@ -86,7 +94,20 @@
|
|||
</li>
|
||||
</ul>
|
||||
<div class="tab-content" id="protocols">
|
||||
<div class="tab-pane fade show active" id="s3" role="tabpanel" aria-labelledby="s3-tab">
|
||||
<div class="tab-pane fade show active" id="dxfl" role="tabpanel" aria-labelledby="dxfl-tab">
|
||||
<p>Première configuration :</p>
|
||||
|
||||
<pre>
|
||||
sudo npm install -g dxfl
|
||||
dxfl login {{ .Describe.Username }}
|
||||
</pre>
|
||||
|
||||
<p>Pour déployer votre site contenu dans le dossier <code>public</code> :</p>
|
||||
<pre>
|
||||
dxfl deploy {{ .View.Name.Pretty }} ./public
|
||||
</pre>
|
||||
</div>
|
||||
<div class="tab-pane fade show" id="s3" role="tabpanel" aria-labelledby="s3-tab">
|
||||
<table class="table mt-4">
|
||||
<tbody>
|
||||
<tr>
|
||||
|
@ -96,8 +117,7 @@
|
|||
<tr>
|
||||
<th scope="row">Clé secrète</th>
|
||||
<td>
|
||||
<a href="#" onclick="document.getElementById('secret_key').style.display='inline'; this.style.display='none'">[Afficher la clé secrète]</a>
|
||||
<span id="secret_key" style="display: none">{{ .View.SecretAccessKey }}</span>
|
||||
<a href="#secret_key" onclick="document.getElementById('secret_key').style.display='inline'; this.style.display='none'">[Afficher la clé secrète]</a><span id="secret_key" style="display: none">{{ .View.SecretAccessKey }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -138,7 +158,7 @@
|
|||
<p>Entrez les informations suivantes quand elles vous sont demandées :</p>
|
||||
<dl>
|
||||
<dt>AWS Access Key ID [None]:</dt><dd>{{ .View.AccessKeyId }}</dd>
|
||||
<dt>AWS Secret Access Key [None]:</dt><dd><a href="#" onclick="document.getElementById('aws_secret_key').style.display='inline'; this.style.display='none'">[Afficher la clé secrète]</a><span id="aws_secret_key" style="display: none">{{ .View.SecretAccessKey }}</span></dd>
|
||||
<dt>AWS Secret Access Key [None]:</dt><dd><a href="#aws_secret_key" onclick="document.getElementById('aws_secret_key').style.display='inline'; this.style.display='none'">[Afficher la clé secrète]</a><span id="aws_secret_key" style="display: none">{{ .View.SecretAccessKey }}</span></dd>
|
||||
<dt>Default region name [None]:</dt> <dd>garage</dd>
|
||||
<dt>Default output format [None]:</dt> <dd>(laissez vide et appuyez sur entrée)</dd>
|
||||
</dl>
|
||||
|
@ -172,7 +192,7 @@ mc alias set \
|
|||
{{ .View.Name.Pretty }} \
|
||||
https://garage.deuxfleurs.fr \
|
||||
{{ .View.AccessKeyId }} \
|
||||
<a href="#" onclick="document.getElementById('minio_secret_key').style.display='inline'; this.style.display='none'">[Afficher la clé secrète]</a><span id="minio_secret_key" style="display: none">{{ .View.SecretAccessKey }}</span> \
|
||||
<a href="#minio_secret_key" onclick="document.getElementById('minio_secret_key').style.display='inline'; this.style.display='none'">[Afficher la clé secrète]</a><span id="minio_secret_key" style="display: none">{{ .View.SecretAccessKey }}</span> \
|
||||
--api S3v4
|
||||
</pre>
|
||||
<p>Et ensuite copiez votre site web avec la sous-commande mirror de Minio CLI :</p>
|
||||
|
@ -196,12 +216,12 @@ mc mirror --overwrite ./public/ {{ .View.Name.Pretty }}/
|
|||
<p>Créez un fichier nommé <code>.deployment.secrets</code> (ne commitez pas ce fichier dans votre dépôt !) :</p>
|
||||
<pre>
|
||||
export AWS_ACCESS_KEY_ID={{ .View.AccessKeyId }}
|
||||
export AWS_SECRET_ACCESS_KEY=<a href="#" onclick="document.getElementById('ugo_secret_key').style.display='inline'; this.style.display='none'">[Afficher la clé secrète]</a><span id="hugo_secret_key" style="display: none">{{ .View.SecretAccessKey }}</span>
|
||||
export AWS_SECRET_ACCESS_KEY=<a href="#hugo_secret_key" onclick="document.getElementById('hugo_secret_key').style.display='inline'; this.style.display='none'">[Afficher la clé secrète]</a><span id="hugo_secret_key" style="display: none">{{ .View.SecretAccessKey }}</span>
|
||||
</pre>
|
||||
<p>Dans votre fichier de configuration Hugo <code>config.toml</code> (que vous pouvez commiter), rajoutez :</p>
|
||||
<pre>
|
||||
[[deployment.targets]]
|
||||
URL = "s3://bucket?endpoint=garage.deuxfleurs.fr&s3ForcePathStyle=true&region=garage"
|
||||
URL = "s3://{{ .View.Name.Pretty }}?endpoint=https://garage.deuxfleurs.fr&awssdk=v2&use_path_style=true&region=garage&disable_https=false
|
||||
</pre>
|
||||
|
||||
<p>Pour déployer, sourcez le fichier de configuration et laissez hugo faire : </p>
|
||||
|
@ -345,7 +365,7 @@ scp -oHostKeyAlgorithms=+ssh-rsa -P2222 -r ./public/ {{ .Describe.Username }}@sf
|
|||
|
||||
{{ if .View.Name.Expanded }}
|
||||
<h5 class="mt-5">Vous ne savez pas comment configurer votre nom de domaine ?</h5>
|
||||
<p> Le nom de domaine {{ .View.Name.Url }} n'est pas géré par Deuxfleurs, il vous revient donc de configurer la zone DNS. Vous devez ajouter une entrée <code>CNAME garage.deuxfleurs.fr</code> ou <code>ALIAS garage.deuxfleurs.fr</code> auprès de votre hébergeur DNS, qui est souvent aussi le bureau d'enregistrement (eg. Gandi, GoDaddy, BookMyName, etc.).</p>
|
||||
<p> Le nom de domaine {{ .View.Name.Url }} n'est pas géré par Deuxfleurs, il vous revient donc de configurer la zone DNS. Vous devez ajouter une entrée <code>CNAME global.site.deuxfleurs.fr</code> ou <code>ALIAS global.site.deuxfleurs.fr</code> auprès de votre hébergeur DNS, qui est souvent aussi le bureau d'enregistrement (eg. Gandi, GoDaddy, BookMyName, etc.).</p>
|
||||
{{ end }}
|
||||
|
||||
|
||||
|
|
|
@ -57,9 +57,9 @@
|
|||
</div>
|
||||
<div>
|
||||
<p>Vous devez éditer votre zone DNS, souvent gérée par votre bureau d'enregistrement, comme Gandi, pour la faire pointer vers Deuxfleurs. Si vous utilisez un sous domaine (eg. <code>site.example.com</code>), une entrée <code>CNAME</code> est appropriée :</p>
|
||||
<pre>site CNAME 3600 garage.deuxfleurs.fr.</pre>
|
||||
<pre>site CNAME 3600 global.site.deuxfleurs.fr.</pre>
|
||||
<p>Si vous utilisez la racine de votre nom de domaine (eg. <code>example.com</code>, aussi appelée APEX), la solution dépend de votre fournisseur DNS, il vous faudra au choix une entrée <code>ALIAS</code> ou <code>CNAME</code> en fonction de ce que votre fournisseur supporte :</p>
|
||||
<pre>@ ALIAS 3600 garage.deuxfleurs.fr.</pre>
|
||||
<pre>@ ALIAS 3600 global.site.deuxfleurs.fr.</pre>
|
||||
<p>La première fois que vous chargerez votre site web, une erreur de certificat sera renvoyée. C'est normal, il faudra patienter quelques minutes le temps que le certificat se génère.</p>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
|
|
|
@ -38,8 +38,7 @@
|
|||
Inviter des gens sur Deuxfleurs
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<a class="list-group-item list-group-item-action" href="/invite/send_code">Envoyer un code d'invitation</a>
|
||||
<a class="list-group-item list-group-item-action" href="/invite/new_account">Créer un nouveau compte directement</a>
|
||||
<a class="list-group-item list-group-item-action" href="/invite/send_code">Générer un code d'invitation</a>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
|
@ -4,15 +4,9 @@
|
|||
<h4>S'identifier</h4>
|
||||
|
||||
<form method="POST">
|
||||
{{if .WrongUser}}
|
||||
<div class="alert alert-danger">Identifiant invalide.</div>
|
||||
{{end}}
|
||||
{{if .WrongPass}}
|
||||
<div class="alert alert-danger">Mot de passe invalide.</div>
|
||||
{{end}}
|
||||
{{if .ErrorMessage}}
|
||||
{{ with .ErrorMessage}}
|
||||
<div class="alert alert-danger">Impossible de se connecter.
|
||||
<div style="font-size: 0.8em">{{ .ErrorMessage }}</div>
|
||||
<div style="font-size: 0.8em">{{ . }}</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="form-group">
|
||||
|
|
Loading…
Add table
Reference in a new issue