1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
/*
* Copyright (c) 2024 Runxi Yu <https://runxiyu.org>
* SPDX-License-Identifier: BSD-2-Clause
*
*/
package main
import (
"bytes"
"context"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/public"
)
func acquireTokenInteractive(app public.Client, username string) (string, error) {
result, err := app.AcquireTokenInteractive(context.TODO(), []string{"User.ReadWrite"}, public.WithLoginHint(username))
if err != nil {
return "", fmt.Errorf("interactive authentication error: %w", err)
}
return result.AccessToken, nil
}
func acquireTokenPassword(app public.Client, username, password string) (string, error) {
result, err := app.AcquireTokenByUsernamePassword(context.TODO(), []string{"User.ReadWrite"}, username, password)
if err != nil {
return "", fmt.Errorf("password authentication error: %w", err)
}
return result.AccessToken, nil
}
func updateProfilePhoto(token, userID, photoPath string) error {
graphEndpoint := "https://graph.microsoft.com/v1.0"
url := fmt.Sprintf("%s/users/%s/photo/$value", graphEndpoint, userID)
photoData, err := os.ReadFile(photoPath)
if err != nil {
return fmt.Errorf("failed reading photo: %w", err)
}
var mimetype string
if strings.HasSuffix(photoPath, ".jpg") || strings.HasSuffix(photoPath, ".jpeg") {
mimetype = "image/jpeg"
} else if strings.HasSuffix(photoPath, ".png") {
mimetype = "image/png"
}
req, err := http.NewRequest("PUT", url, bytes.NewReader(photoData))
if err != nil {
return fmt.Errorf("failed making request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", mimetype)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("failed requesting: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed reading response: %w", err)
}
fmt.Println(resp.StatusCode)
fmt.Printf("%s\n", body)
return nil
}
func main() {
var email, photo, passVar string
flag.StringVar(&email, "email", "", "(required) username@ykpaoschool.cn")
flag.StringVar(&photo, "photo", "", "(required) path to avatar")
flag.StringVar(&passVar, "passvar", "", "environment variable containing the password")
flag.Parse()
if photo == "" || email == "" {
flag.Usage()
return
}
app, err := public.New("14f8346d-98c9-4f12-875f-3b2cabe7110a", public.WithAuthority("https://login.microsoftonline.com/organizations"))
if err != nil {
log.Fatalf("failed creating msal app: %v", err)
}
var token string
if passVar == "" {
token, err = acquireTokenInteractive(app, email)
} else {
password := os.Getenv(passVar)
if password == "" {
log.Fatalf("environment variable %s not found", passVar)
}
token, err = acquireTokenPassword(app, email, password)
}
if err != nil {
log.Fatalf("failed to acquire token: %v", err)
}
err = updateProfilePhoto(token, email, photo)
if err != nil {
log.Fatalf("failed to update profile photo: %v", err)
}
}
|