move request stuff here
This commit is contained in:
		
							parent
							
								
									d29fabfa52
								
							
						
					
					
						commit
						b10bdd756a
					
				
							
								
								
									
										4
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								TODO
									
									
									
									
									
								
							@ -1,2 +1,4 @@
 | 
				
			|||||||
- [ ] admin check for a user struct
 | 
					- [x] admin check for a user struct
 | 
				
			||||||
 | 
					- [x] gitea requesting
 | 
				
			||||||
 | 
					- [x] gemini requesting
 | 
				
			||||||
- [ ] get user stats/info
 | 
					- [ ] get user stats/info
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										69
									
								
								request/gemini.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								request/gemini.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						email "git.tilde.town/tildetown/town/email"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const geminiHomeDocBase = "/home/gemini/users"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func processGemini(requestRootPath string) error {
 | 
				
			||||||
 | 
						rp := filepath.Join(requestRootPath, "gemini")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						files, err := ioutil.ReadDir(rp)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("failed to list directory %s: %w", rp, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usernames := []string{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, file := range files {
 | 
				
			||||||
 | 
							usernames = append(usernames, file.Name())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(usernames) == 0 {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, username := range usernames {
 | 
				
			||||||
 | 
							err := linkGemini(username)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								fmt.Fprintf(os.Stderr, "failed to process gemini request for %s: %s\n", username, err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							os.Remove(filepath.Join(rp, username))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func linkGemini(username string) error {
 | 
				
			||||||
 | 
						pgPath := filepath.Join("/home", username, "public_gemini")
 | 
				
			||||||
 | 
						if !pathExists(pgPath) {
 | 
				
			||||||
 | 
							return fmt.Errorf("public_gemini missing for %s", username)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						geminiPath := filepath.Join(geminiHomeDocBase, username)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !pathExists(geminiPath) {
 | 
				
			||||||
 | 
							err := os.Symlink(pgPath, geminiPath)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("failed to link public_gemini for %s: %w", username, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						body := fmt.Sprintf(`hi %s!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					you requested a gemini space on the town. this space has been activated and anything you do in your public_gemini directory should now be reflected by the server.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if you did _not_ request this, please let an admin know.`, username)
 | 
				
			||||||
 | 
						return email.SendLocalEmail(username, "gemini", body)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func pathExists(path string) bool {
 | 
				
			||||||
 | 
						_, err := os.Stat(path)
 | 
				
			||||||
 | 
						return err == nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										179
									
								
								request/gitea.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								request/gitea.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,179 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"math/rand"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						email "git.tilde.town/tildetown/town/email"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const pwLetters = "!@#$%^&*() []{}:;,.<>/?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func processGitea(rp string) error {
 | 
				
			||||||
 | 
						apiToken := os.Getenv("GITEA_TOKEN")
 | 
				
			||||||
 | 
						if apiToken == "" {
 | 
				
			||||||
 | 
							return errors.New("need GITEA_TOKEN")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gtPath := filepath.Join(requestPath, "gitea")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						files, err := ioutil.ReadDir(gtPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usernames := []string{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, file := range files {
 | 
				
			||||||
 | 
							usernames = append(usernames, file.Name())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(usernames) == 0 {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, username := range usernames {
 | 
				
			||||||
 | 
							exists, err := giteaUserExists(apiToken, username)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								fmt.Fprintf(os.Stderr, "unable to check for existing account for %s: %s\n", username, err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if !exists {
 | 
				
			||||||
 | 
								password, err := createGiteaUser(apiToken, username)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									fmt.Fprintf(os.Stderr, "unable to create account for %s: %s\n", username, err)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								err = sendGiteaEmail(username, password)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									fmt.Fprintf(os.Stderr, "failed to send email to %s; reach out manually: %s\n", username, err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							os.Remove(filepath.Join(gtPath, username))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func createGiteaUser(apiToken, username string) (string, error) {
 | 
				
			||||||
 | 
						client := &http.Client{}
 | 
				
			||||||
 | 
						password := genGiteaPassword()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO using local email sucks for obvious reasons but it'll have to do for now. ideally password
 | 
				
			||||||
 | 
						// resets can be set local to the server, so the thing to change is not the local email but the
 | 
				
			||||||
 | 
						// ability for gitea to send mail internally.
 | 
				
			||||||
 | 
						createPayload := struct {
 | 
				
			||||||
 | 
							Email              string
 | 
				
			||||||
 | 
							FullName           string `json:"full_name"`
 | 
				
			||||||
 | 
							Login              string `json:"login_name"`
 | 
				
			||||||
 | 
							MustChangePassword bool   `json:"must_change_password"`
 | 
				
			||||||
 | 
							Password           string
 | 
				
			||||||
 | 
							SendNotify         bool `json:"send_notify"`
 | 
				
			||||||
 | 
							Username           string
 | 
				
			||||||
 | 
							SourceId           int `json:"source_id"`
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							Email:              fmt.Sprintf("%s@tilde.town", username),
 | 
				
			||||||
 | 
							FullName:           username,
 | 
				
			||||||
 | 
							Login:              username,
 | 
				
			||||||
 | 
							MustChangePassword: true,
 | 
				
			||||||
 | 
							Password:           password,
 | 
				
			||||||
 | 
							SendNotify:         false,
 | 
				
			||||||
 | 
							Username:           username,
 | 
				
			||||||
 | 
							SourceId:           0,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						body, err := json.Marshal(createPayload)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req, err := giteaAPIReq(apiToken, "POST", "admin/users", bytes.NewBuffer(body))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := client.Do(req)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.StatusCode != 201 {
 | 
				
			||||||
 | 
							lol, _ := ioutil.ReadAll(resp.Body)
 | 
				
			||||||
 | 
							fmt.Printf("DBG %#v\n", string(lol))
 | 
				
			||||||
 | 
							return "", fmt.Errorf("failed to create user for %s; error code %d", username, resp.StatusCode)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return password, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func giteaUserExists(apiToken, username string) (bool, error) {
 | 
				
			||||||
 | 
						client := &http.Client{}
 | 
				
			||||||
 | 
						req, err := giteaAPIReq(apiToken, "GET", "users/"+username, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := client.Do(req)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.StatusCode == 200 {
 | 
				
			||||||
 | 
							return true, nil
 | 
				
			||||||
 | 
						} else if resp.StatusCode == 404 {
 | 
				
			||||||
 | 
							return false, nil
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return false, fmt.Errorf("unexpected response code: %d", resp.StatusCode)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func giteaAPIReq(apiToken, method, path string, body *bytes.Buffer) (*http.Request, error) {
 | 
				
			||||||
 | 
						if body == nil {
 | 
				
			||||||
 | 
							body = bytes.NewBufferString("")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						basePath := "https://git.tilde.town/api/v1/"
 | 
				
			||||||
 | 
						req, err := http.NewRequest(method, basePath+path, body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req.Header.Add("Authorization", fmt.Sprintf("token %s", apiToken))
 | 
				
			||||||
 | 
						req.Header.Add("Content-Type", "application/json")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return req, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func sendGiteaEmail(username, password string) error {
 | 
				
			||||||
 | 
						body := fmt.Sprintf(`hi %s!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					you requested a git.tilde.town account and now you have one~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					please log in with username %s and password %s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					you'll be prompted to change the password.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if you did _not_ request this, please let an admin know.
 | 
				
			||||||
 | 
					`, username, username, password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return email.SendLocalEmail(username, "gitea", body)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func genGiteaPassword() string {
 | 
				
			||||||
 | 
						rand.Seed(time.Now().UnixNano())
 | 
				
			||||||
 | 
						b := make([]byte, 20)
 | 
				
			||||||
 | 
						for i := range b {
 | 
				
			||||||
 | 
							b[i] = pwLetters[rand.Intn(len(pwLetters))]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Bootleg, but hack to ensure we meet complexity requirement
 | 
				
			||||||
 | 
						return string(b) + "!" + "1" + "A"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -3,11 +3,9 @@ package main
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io/ioutil"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/user"
 | 
						"os/user"
 | 
				
			||||||
	"path/filepath"
 | 
					
 | 
				
			||||||
	//email "git.tilde.town/tildetown/town/email"
 | 
					 | 
				
			||||||
	townUser "git.tilde.town/tildetown/town/user"
 | 
						townUser "git.tilde.town/tildetown/town/user"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -28,8 +26,16 @@ func _main(args []string) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	errs := []error{}
 | 
						errs := []error{}
 | 
				
			||||||
	errs = append(errs, processGitea(requestPath))
 | 
					
 | 
				
			||||||
	errs = append(errs, processGemini(requestPath))
 | 
						err = processGitea(requestPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							errs = append(errs, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = processGemini(requestPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							errs = append(errs, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(errs) > 0 {
 | 
						if len(errs) > 0 {
 | 
				
			||||||
		errMsg := "errors encountered during request processing: "
 | 
							errMsg := "errors encountered during request processing: "
 | 
				
			||||||
@ -53,35 +59,3 @@ func main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	os.Exit(retcode)
 | 
						os.Exit(retcode)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func processGitea(rp string) error {
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func processGemini(requestRootPath string) error {
 | 
					 | 
				
			||||||
	rp := filepath.Join(requestRootPath, "gemini")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	files, err := ioutil.ReadDir(rp)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("failed to list directory %s: %w", rp, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	usernames := []string{}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, file := range files {
 | 
					 | 
				
			||||||
		usernames = append(usernames, file.Name())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(usernames) == 0 {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, username := range usernames {
 | 
					 | 
				
			||||||
		// TODO check for public_gemini already in their home dir
 | 
					 | 
				
			||||||
		// TODO create publiC_gemini
 | 
					 | 
				
			||||||
		// TODO check for existing symlink
 | 
					 | 
				
			||||||
		// TODO create symlink
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								request/request
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								request/request
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user