#0. 준비

무선 랜카드 : AP(공유기) 정보를 모두 수집하기 위해서 필요

칼리 리눅스 : 칼리 리눅스에 이미 설치되어 있는 툴(airmon-ng, airodump-ng, aircrack-ng 등)을 사용

 

#1. WEP 암호화 방식이란

무선랜 구간에서 사용되는 암호화 알고리즘으로, 무선랜 표준을 정의하는 IEEE 802.11(1997년)의 규약 중 하나이다.
WEP은 대칭키 암호 방식 중 하나인 스트림 암호 방식을 사용합니다. 스트임 암호 방식에서 RC4 암호화 알고리즘을 사용하여 데이터를 암호화 시킵니다.
WEP 비밀키(40비트)와 IV(24비트)를 RC4 알고리즘으로 키 스트림을 생성하고, 전달할 데이터와 XOR 해줘서 데이터를 암호화 시켜줍니다.
 
IV(24비트) : 초기에는 비밀키로만 RC4 알고리즘을 사용하여 암호화 시켰지만 사전공격에 취약해서 IV라는 값을 추가(매번 바뀜)
비밀키(40비트) : 사용자가 설정한 패스워드 또는 공유기에서 생성한 키(4개중 하나)
아래 사이트에서 공유기에서 WEP 키 생성 방법 설명
https://withnotebook.tistory.com/2

 

내 공유기 보안설정을 하자. 1 - WEP암호화 -

요즘은 무선 공유기를 통해 노트북으로 무선인터넷을 하는것이 보편화 되어있습니다. 유무선 공유기또한, 상당히 저렴한 가격으로 2대이상의 PC를 가진 집에는 공유기 한대쯤은 모두 가지고 있

withnotebook.tistory.com

 
 

#2. 데이터 암호화 과정 원리

WEP 암호화 과정

1. 40비트 WEP키 와 24비트 IV값을 조합하여 64비트 키를 생성.
2. 64비트 키를 RC4 알고리즘을 통해서 암호화 시켜 RC4 키스트림을 생성.
3. 데이터를 CRC-32 알고리즘을 통해서 ICV 값 생성(무결성 체크를 위한)
4. (데이터+ICV)와 RC4 키스트림을 XOR 함.
5. IV 헤더 : 24비트 IV 키값과 키값(비밀키 4개가 만들어질 경우 어떤 것을 사용할지 번호를 정함)
6. 데이터 와 ICV(암호화) : 4번에서 결과.
7. FCS : ICV 값(데이터 무결성 체크를 위한 값)
 

#3. 해킹 원리

IV값이 재사용 되는 것과 RC4 알고리즘의 취약점으로 인해 키스트림 중복된 값으로 결과가 나온다. 이러한 이유로, 50000개 이상의 패킷들을 수집후(패킷 수집시 IV값이 노출됩니다.) 재사용된 IV를 분석 후 RC4 알고리즘의 취약점을 이용해서 키스트림을 구하여 암호문을 복호화 시킴.
5000개의 패킷을 생성시 50%이상의 확률로 동일한 IV가 생성(생일 문제)
 

#4. 칼리리눅스에서 실습

Airmon-ng: 무선 네트워크 카드를 모니터 모드로 변경하고 관리하는 데 사용되는 도구
Airodump-ng: 무선 네트워크에서 패킷을 캡처하고 정보를 표시하는 도구
Aircrack-ng: WEP 및 WPA/WPA2 PSK(사전 공격) 비밀번호를 해독하기 위한 도구
 

무선랜 검색

1. 모든 패킷을 수집하기 위해서 iwconfig 명령어로 무선랜(wlan0)을 검색해주고, Mode가 Monitor모드인지 확인. 
Managed 모드 : 목적지가 자신의 랜카드로 들어오는 패킷이 아닌 것은 모두 버림
Monitor 모드 : 목적지가 자신의 랜카드로 들어오지 않는 패킷도 모두 수신.(스니핑시 사용)
 

모니터 모드로 변경

2. airmon-ng start wlan0(자신의 무선랜카드 이름) 명령어로 Monitor 모드로 변경. 
 

주변 AP 검색

3. airodump-ng wlan0 명령어로 주변 AP(공유기)를 검색.
 

패킷 캡쳐

4. airodump-ng --bsssid [AP 맥주소] --channel [채널] --write [패킷을 캡쳐한 파일 이름 지정] wlen0(무선랜 이름)
지정한 AP의 패킷을 캡쳐해서 test_wep 이름의 파일로 저장 합니다. #Data(네트워크 트래픽)가 20000~50000 정도 되어야 패킷을 분석해서 IV의 중복값을 찾아낼 수 있음. (Data가 적으면 암호 해독 불가)
 

패킷 정보로 암호 복호화

5. aircrack-ng test_wep-01.cap(패킷 캡쳐 파일). cap파일을 가지고 암호를 해독.
 

복호화 성공

6. 아스키 코드와 16진수로 암호가 해독 되었습니다.
 

#5. 참고 자료

https://blog.naver.com/PostView.naver?blogId=knismaster&logNo=222079535892
http://www.ktword.co.kr/test/view/view.php?m_temp1=2244 
https://n3015m.tistory.com/entry/%EB%AC%B4%EC%84%A0%EB%9E%9C-WEP-%EC%95%94%ED%98%B8%ED%99%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%B7%A8%EC%95%BD%EC%A0%90
https://www.piolink.com/kr/service/Security-Analysis.php?bbsCode=security&vType=view&idx=90 

##프로젝트 사전준비##

https://healer4-13.tistory.com/14

 

Go[golang] Youtube api를 사용하여 비공개 재생목록 가져오기 3편(OAuth 인증 준비)

https://healer4-13.tistory.com/12 Go[golang] Youtube api를 사용하여 공개 재생목록 가져오기 1편(API 키 준비) Youtube api를 사용하기 위해서는 먼저 구글 클라우드 플랫폼에서 프로젝트를 생성해줘야 합니다. ht

healer4-13.tistory.com

1. 위의 url로 접속 후.

7번에서 사용자를 추가하실 때 본인 프로젝트 계정(healer@gmail.com)과 테스트 계정을 추가해 줍니다. 총 2개 계정 추가.

이유 : 본인 계정에는 2차 인증이 설정되어 있을 거고, 그러면 로그인을 자동화할 수가 없음. 1차 인증만 되어 있는 로그인 계정을 등록해서 접근하려는 의도.

 

클라이언트 ID 만들기

2. 9번에서 애플리케이션 유형을 웹 애플리케이션으로 등록, 승인된 리디렉션 URI에 http://localhost:8080/login/callback를 추가 후 만들기.

설명 : 로그인 후 코드를 받을 때 리디렉션 되는 uri를 설정함. 인증 완료 후 localhost:8080/login/callback을 호출함(리디렉션).

 

유튜브 접근 권한 설정

3. 테스트 계정이 비공개 재생목록에 접근해서 데이터를 가져오기 위해서는 권한을 설정해 주어야 합니다.

유튜브 계정에서 설정 -> 채널상태 및 기능 -> 권환 -> 채널에 접근할 수 있는 권한을 주기 위해 계정 초대 -> 이메일(테스트 계정)과 액세스 권한 설정 후 완료.

 사전준비 완료.

 

 

프로젝트 실행 영상

4. 프로젝트를 실행하면 자동으로 로그인 후 리다이렉트 되어 코드를 추출하고 토큰을 얻습니다. 그리고 기존의 재생목록을 저장한 playlistsLocal.txt파일에 재생목록들과 유튜브에서 가져온 재생들을 비교하여 추가된 재생목록을 업데이트해 줍니다.

A5qhZjetvkY, 03년 박효신 X 03년 박화요비 - 그런일은 ♫♪

ID : A5qhZjetvkY

제목 : 03년 박효신 X 03년 박화요비 - 그런일은 ♫♪

이 추가된 모습을 보실 수 있습니다.

 

github 소스코드

https://github.com/jeetkd/golang_youtube_api/tree/main/youtube_playlists_prj

 

이번에는 OAuth 2.0 클라이언트 ID를 사용해서 자신의 계정에 비공개 재생목록을 가져와 보겠습니다.

👇아래 링크에서 OAuth 2.0 클라이언트 ID를 먼저 발급해주세요.

https://healer4-13.tistory.com/14

 

Go[golang] Youtube api를 사용하여 비공개 재생목록 가져오기 3편(OAuth 인증 준비)

https://healer4-13.tistory.com/12 Go[golang] Youtube api를 사용하여 공개 재생목록 가져오기 1편(API 키 준비) Youtube api를 사용하기 위해서는 먼저 구글 클라우드 플랫폼에서 프로젝트를 생성해줘야 합니다. ht

healer4-13.tistory.com

 

Github 코드 : https://github.com/jeetkd/golang_youtube_api/tree/main/private_playlist

 

GitHub - jeetkd/golang_youtube_api: golang youtube api use

golang youtube api use. Contribute to jeetkd/golang_youtube_api development by creating an account on GitHub.

github.com

 

go get "google.golang.org/api/youtube/v3"
go get "golang.org/x/oauth2"

youtube api와 OAuth 2.0 클라이언트 인증을 사용하기 위해서 외부 패키지를 다운로드해주세요.

 

 

package main

import (
	"context"
	"fmt"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/option"
	"google.golang.org/api/youtube/v3"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	//Read json file (json 파일 읽어옴)
	jsonKey, err := ioutil.ReadFile("client.json")
	if err != nil {
		log.Fatalf("Failed to read JSON file: %v", err)
	}

	// Set up the OAuth 2.0 configuration (OAuth 2.0 구성 환경 설정)
	config, err := google.ConfigFromJSON(jsonKey, youtube.YoutubeReadonlyScope)
	if err != nil {
		log.Fatalf("Unable to parse client secret file: %v", err)
	}

	// Create a new OAuth 2.0 client (새로운 OAuth 2.0 클라이언트를 생성 합니다.)
	client := getClient(config)

	// Set up the YouTube API client using the authenticated client (인증된 클라이언트를 사용하여 유튜브 API 클라이언트를 설정)
	service, err := youtube.NewService(context.Background(), option.WithHTTPClient(client))
	if err != nil {
		log.Fatalf("Unable to create YouTube service: %v", err)
	}

	// Retrieve the playlist ID for the private playlist you want to access (접근을 원하는 비공개 재생목록 ID)
	playlistID := "자신의 계정에 비공개 재생목록의 ID를 넣어주세요"

	// Retrieve the playlist items from the private playlist (비공개 재생목록으로부터 재생목록 아이템들을 불러옵니다.)
	playlistItemsCall := service.PlaylistItems.List([]string{"snippet"}).
		PlaylistId(playlistID). // 재생목록 ID 설정
		MaxResults(50)          // Adjust the maximum number of results as per your requirements(가져올 재생목록 item 최대값 설정)

	playlistItemsResponse, err := playlistItemsCall.Do() // "youtube.playlistItems.list" 호출 실행.
	if err != nil {
		log.Fatalf("Unable to retrieve playlist items: %v", err)
	}

	// Process and display the playlist items //가져온 재생목록 아이템들을 제목과 ID 출력
	for _, item := range playlistItemsResponse.Items {
		title := item.Snippet.Title
		videoID := item.Snippet.ResourceId.VideoId
		fmt.Printf("Title: %s, Video ID: %s\n", title, videoID)
	}
}

// getClient retrieves a valid OAuth 2.0 client.(유효한 OAuth 2.0 클라이언트를 불러옵니다.)
// 토큰트로 *http.Client를 생성하고 반환
func getClient(config *oauth2.Config) *http.Client {
	// Retrieve a token, if it exists, or prompts the user to authenticate.
	token := getTokenFromWeb(config)
	return config.Client(context.Background(), token)
}

// getTokenFromWeb uses the provided OAuth 2.0 Config to request a Token. (제공된 Auth 2.0 구성을 사용해서 토큰을 요청)
// It returns the retrieved Token.(유효한 토큰을 반환)
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
	authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
	fmt.Printf("Go to the following link in your browser, then type the "+
		"authorization code: \n%v\n", authURL)

	//토큰 입력
	var code string
	if _, err := fmt.Scan(&code); err != nil {
		log.Fatalf("Unable to read authorization code: %v", err)
	}

	token, err := config.Exchange(context.Background(), code)
	if err != nil {
		log.Fatalf("Unable to retrieve token from web: %v", err)
	}
	return token
}

비공개 재생목록의 아이디와 제목을 가져오는 코드입니다. 하나씩 살펴보겠습니다.

 

config, err := google.ConfigFromJSON(jsonKey, youtube.YoutubeReadonlyScope)

 

- json 파일과 권한 범위를 가지고 *oauth2.Config 구조체를 구성하고 반환함(토큰을 받기 위한 정보가 있음)
jsonKey : 3편에서 다운로드한 json파일
youtube.YoutubeReadonlyScope : 접근 가능한 권한 범위(읽기 전용으로 설정함)

 

service, err := youtube.NewService(context.Background(), option.WithHTTPClient(client))

- Youtube api 사용을 위한 새로운 Service를 생성합니다.
option.WithHTTPClient(client) : 통신을 하기 위해 사용할 HTTP 클라이언트를 지정하는 ClientOption을 리턴.

 

playlistID := "자신의 계정에 비공개 재생목록의 ID를 넣어주세요"

- 접근을 원하는 비공개 재생목록 ID를 넣어주세요.

 

playlistItemsResponse, err := playlistItemsCall.Do()

- "youtube.playlistItems.list"를 실행하고 PlaylistItemListResponse 구조체를 반환합니다.
PlaylistItemListResponse 구조체에 Items에 반환된 재생목록들의 정보가 있습니다.

 

for _, item := range playlistItemsResponse.Items {
		title := item.Snippet.Title
		videoID := item.Snippet.ResourceId.VideoId
		fmt.Printf("Title: %s, Video ID: %s\n", title, videoID)
	}

- resPlaylist.Items를 통해서 반환된 정보를 가져오고 Snippet에서 정보들을 가져옴.
가져온 제목과 비디오 id를 출력합니다.

 

 

1. func getTokenFromWeb(config *oauth2.Config) *oauth2.Token 함수 안에 코드 설명

 

authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)

- 인증코드를 얻기 위한 동의 페이지 url을 반환해 준다. (사용자 인증 후 인증코드 반환)
"state-token" : csrf 방지를 위한 매개변수
oauth2.AccessTypeOffline : 토큰에 관한 설정에 관한 매개변수 (처음에만 인증하고 재인증 필요 없이 리프레쉬 토큰 재발급 가능)

 

token, err := config.Exchange(context.Background(), code)

- 인증코드를 토큰으로 변환해 줍니다.
code : 위에서 발급받고 입력한 인증코드

 

 

2. func getClient(config *oauth2.Config) *http.Client 함수 안에 코드 설명

 

return config.Client(context.Background(), token)

- Client는 제공된 토큰을 사용하여 http 클라이언트를 리턴합니다.
token : 위에서 생성한 토큰

 

실행 화면 설명

 

실행화면 1

1. 빨간색 박스의 url을 복사해서 인터넷 url창에 붙여 넣어서 이동해 주세요.

 

로그인

2. 등록하신 계정으로 로그인해주세요.

 

계속

3. 계속을 눌러주세요.

 

계속

4. 다시 한번 계속을 눌러주세요.

 

토큰 복사

5. 마지막으로 토큰이 발급된 것을 볼 수 있습니다. 빨간색 박스(토큰)를 복사해 주시고 입력해 주시면 돼요.

 

실행 결과

복사하신 토큰을 입력하시면 이렇게 비공개 재생목록의 제목과 ID를 가져옵니다.

6. 파란색 박스 : 토큰

7. 빨간색 박스 : 가져온 제목과 ID

https://healer4-13.tistory.com/12

 

Go[golang] Youtube api를 사용하여 공개 재생목록 가져오기 1편(API 키 준비)

Youtube api를 사용하기 위해서는 먼저 구글 클라우드 플랫폼에서 프로젝트를 생성해줘야 합니다. https://console.cloud.google.com/getting-started 링크로 들어가셔서 구글로 로그인 해주세요. 1. 프로젝트 선

healer4-13.tistory.com

**먼저 위의 과정을 5번까지 진행했다는 가정하에 설명하겠습니다.**

 

자신의 계정에 비공개 재생목록 가져오기 위해서는 OAuth 2.0 클라이언트 ID를 생성해 주어야 합니다.

 

API 및 서비스

1. API 및 서비스에서 사용자 인증 정보를 클릭.

 

동의 화면 구성

2. OAuth 2.0 클라이언트 ID를 만들기 위해서는 동의 화면을 먼저 구성해줘야 합니다. 동의 화면 구성을 클릭.

 

동의 화면 구성 (외부)

3. User Type에서 외부를 선택.

 

앱이름, 이메일 추가

4. 앱 이름(test01)과 사용자 지원 이메일(나의 이메일 선택)을 작성.

 

개발자 연락처 정보 입력

5. 개발자 연락처 정보에 이메일 입력. 저장 후 계속.

 

범위 추가

6. 범위 추가 또는 삭제 클릭 -> 유튜브 비공개 사용자 정보에 접근하기 위해 YouTube Data API v3 관련된 범위를 추가 -> 업데이트 클릭.

 

저장 후 계속

7. 위에 보시면 범위가 추가된 것을 볼 수 있습니다. 저장 후 계속 클릭

 

테스트 사용자 추가

8. ADD USERS를 클릭 후 오른쪽에 정보에 접근할 테스트 사용자(로그인할 구글 계정 추가)를 추가해 줍니다. 저장 후 계속 클릭.

 

사용자 인증 정보 만들기

9. 이제 사용자 인증 정보를 만들 수 있습니다.  설명 2로 돌아가셔서 OAuth 클라이언트 ID를 클릭해 주세요.

 

애플리케이션 유형

 

10. 애플리케이션 유형을 선택. 저는 Goland라는 데스크톱 앱에서 접근하기 때문에 데스크 톱 앱으로 선택.

만들기 클릭.

 

클라이언트 보안 비밀번호 json 다운로드

11. 이제 다시 API 및 서비스에 사용자 인증정보로 가시면 OAuth 2.0 클라이언트 ID가 생긴 것을 확인하실 수 있을 겁니다. 클릭해 주시고 클라이언트 보안 비밀번호를 json으로 다운로드해주시고 사용하시면 됩니다.

**api 키를 발급 받지 않으셨다면, 이쪽을 참고하셔서 먼저 발급 받아주세요.**

https://healer4-13.tistory.com/12

 

Go[golang] Youtube api를 사용하여 플레이리스트 가져오기 1편(API 키 준비)

Youtube api를 사용하기 위해서는 먼저 구글 클라우드 플랫폼에서 프로젝트를 생성해줘야 합니다. https://console.cloud.google.com/getting-started 링크로 들어가셔서 구글로 로그인 해주세요. 1. 프로젝트 선

healer4-13.tistory.com

 

Github 코드 : https://github.com/jeetkd/golang_youtube_api/

 

GitHub - jeetkd/golang_youtube_api: golang youtube api use

golang youtube api use. Contribute to jeetkd/golang_youtube_api development by creating an account on GitHub.

github.com

그 다음 유튜브 api를 사용하기 위해서 go get 해줘야 합니다.
현재 프로젝트로 이동하고, go get google.golang.org/api/youtube/v3 명령어로 패키지를 다운로드 해줍니다.

 

package main

import (
	"context"
	"flag"
	"fmt"
	"google.golang.org/api/option"
	"google.golang.org/api/youtube/v3"
	"log"
)

func main() {
	//Set up API Key and playlistID(API 키와 playlistID 설정)
	apiKey := flag.String("api-key", "Put your api key(자신의 api 키를 넣어주세요)", "YouTube API 키")
	playlistID := flag.String("playlist-id", "Put playlist ID(플레이리스트 ID를 넣어주세요)", "재생목록 ID")
	flag.Parse()

	//Create Service(서비스 생성)
	ctx := context.Background()
	service, err := youtube.NewService(ctx, option.WithAPIKey(*apiKey))
	reqPlaylist := service.PlaylistItems.List([]string{"snippet"}). // Set up snippet option
		PlaylistId(*playlistID). //Set up playlistID
		MaxResults(50) //Set up Max Result

	// Do Excute "youtube.playlistItems.list"(PlaylistItemListResponse를 응답으로 받음)
	resPlaylist, err := reqPlaylist.Do()
	if err != nil {
		log.Fatalf("Error fetching playlist items: %v", err.Error())
	}

	// Get playlist Items(재생 목록과 비디오 ID를 가져옴)
	for _, playlistItem := range resPlaylist.Items {
		title := playlistItem.Snippet.Title
		videoId := playlistItem.Snippet.ResourceId.VideoId
		fmt.Printf("%v, (%v)\r\n", title, videoId)
	}

}

apiKey := flag.String 함수에 두번째 인자(Put your api key)에 자신의 api 키를 넣어주시면 됩니다.

playlistID := flag.String 함수에 두번째 인자(Put playlist ID)에 원하시는 재생목록의 ID를 넣어주세요.

 

재생목록 ID

빨간색 박스가 재생목록 ID 입니다.

이제 재생목록을 가져오기 위해서는 Service를 생성해야 하는데요

 

ctx := context.Background()
service, err := youtube.NewService(ctx, option.WithAPIKey(*apiKey))

youtube.NewService(ctx, option.WithAPIKey(*apiKey)) 함수를 사용해서 생성 합니다.

첫 번째 인자는 Context이고, 두 번째 인자는 구글 API 클라이언트에 대한 clientOption 입니다. WithAPIKey를 사용하여 apiKey에 대한 clientOption을 반환해 줍니다.

 

reqPlaylist := service.PlaylistItems.List([]string{"snippet"}). // Set up snippet option
		PlaylistId(*playlistID). //Set up playlistID
		MaxResults(50) //Set up Max Result

https://developers.google.com/youtube/v3/docs/playlists/list?hl=ko 

 

Playlists: list  |  YouTube Data API  |  Google for Developers

Playlists: list 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. API 요청 매개변수와 일치하는 재생목록의 모음을 반환합니다. 예를 들어 인증된 사용자가 보유

developers.google.com

**위 공식 문서 참조.**

반환된 Service를 통해서 List 메소드를 통해 API 응답 하위 속성("snippet")을 셋팅해 줍니다.

PlaylistId(*playlistID) : 재생목록의 리스트를 반환하는 재생목록의 ID를 설정

MaxResults(50) : 반환하는 항목의 수를 설정(0이상 50이하)

 

resPlaylist, err := reqPlaylist.Do()

reqPlaylist.Do() : "youtube.playlistItems.list"를 실행하고 PlaylistItemListResponse 구조체를 반환합니다.

PlaylistItemListResponse 구조체에 Items에 반환된 재생목록들의 정보가 있습니다.

 

for _, playlistItem := range resPlaylist.Items {
		title := playlistItem.Snippet.Title
		videoId := playlistItem.Snippet.ResourceId.VideoId
		fmt.Printf("%v, (%v)\r\n", title, videoId)
	}

resPlaylist.Items를 통해서 반환된 정보를 가져오고 Snippet에서 정보들을 가져옴.

제목과 비디오id를 출력 합니다.

 

결과 화면

 

Youtube api를 사용하기 위해서는 먼저 구글 클라우드 플랫폼에서 프로젝트를 생성해줘야 합니다.

https://console.cloud.google.com/getting-started 링크로 들어가셔서 구글로 로그인 해주세요.

 

프로젝트 선택

1. 프로젝트 선택을 눌러주세요.

 

새 프로젝트

2. 새 프로젝트를 눌러주세요.

 

새 프로젝트 만들기

3. 프로젝트 이름(Test01)을 입력하고, 만들기를 눌러주세요.

 

YouTube Data API v3 검색

4. 파란색 박스를 보시면 프로젝트(Test01)가 생성된 걸 볼 수 있습니다.  Youtube api를 사용하기 위해서 "youtube data api"를 검색하시고 아래 빨간색 박스 YouTube Data API v3를 선택해주세요.

 

YouTube Data API v3 사용

5. YouTube Data API v3를 사용하기 위해서  "사용"을 눌러주세요.

 

사용자 인증 정보 만들기

6. API 키를 얻기 위해서 이제 사용자 인증 정보를 만들기를 눌러주세요.

 

사용자 인증 정보 유형

7. 공개 데이터(공개적인 데이터에 접근하기 위해서)를 선택해 주시고 다음을 눌러주세요.

추가 설명 : 사용자 데이터를 선택하시면 OAuth 인증 방식을 사용해야 하고, 사용자의 데이터에 접근한다(ex : 내 비공개 플레이 리스트).

 

내 사용자 인증 정보(API 키)

8. 이제 API 키가 발급된 걸 볼 수 있습니다. API 키를 복사하시고 완료를 눌러주세요.

 

API 키 확인

9. 사용자 인증 정보를 누르시면 API 키가 1개 생성된 걸 확인할 수 있습니다. API 키 1개를 클릭하시면 키 정보를 확인할 수 있습니다.

go에있는 빌트인 함수인 append를 공식문서에서 찾아봤습니다.
https://go.dev/doc/effective_go#append

 

Effective Go - The Go Programming Language

Documentation Effective Go Effective Go Introduction Go is a new language. Although it borrows ideas from existing languages, it has unusual properties that make effective Go programs different in character from programs written in its relatives. A straigh

go.dev

 

 

Now we have the missing piece we needed to explain the design of the append built-in function. The signature of append is different from our custom Append function above. Schematically, it's like this:

이제 우리는 append 내장 함수의 디자인을 설명하기 위해서 우리가 필요했던 잃어버린 조각(위에서 부족한 설명에 대한 답)을 가지고 있다. append의 특징은 위에서 본 우리의 커스텀 Append 함수(https://go.dev/doc/effective_go#slices)와 다르다. 개략적으로 이것은 다음과 같다:

 

func append(slice []T, elements ...T) []T

where T is a placeholder for any given type. You can't actually write a function in Go where the type T is determined by the caller. That's why append is built in: it needs support from the compiler.

여기에서 T는 어떤 주어진 타입에 대한 placeholder(제네릭, 일시적으로 값을 대체하거나 나중에 채워질 것으로 예상되는 위치 )이다. Go에서는 타입 T가 호출자에 의해 결정되는 함수를 작성할 수 없다. 이것이 append가 내장함수인 이유이고: 컴파일러의 지원이 필요하다.

 

위의 문장에서 보충설명 : 제네릭 T를 사용할 때 타입을 명시해줘야 된다. 안그러면 오류가 난다. 하지만 위에 append 함수는 호출하는 쪽에서 타입을 정할수 있다. 컴파일러의 지원덕분에 가능. 내장함수 append는 a := append([]int{}, 1, 2, 3)처럼 호출하는 쪽에서 []int로 정할수 있다. 하지만 커스텀 함수에서 제네릭은 이렇게 타입을 명시해줘야함. 여기서는 any로 해줌.

 

func Print[T any](a T) {
   fmt.Println(a)
}

What append does is append the elements to the end of the slice and return the result. The result needs to be returned because, as with our hand-written Append, the underlying array may change. This simple example

append가 하는 것은 요소들을 slice끝에 삽입하고, 결과를 리턴하는 것이다. 우리의 직접 작성된 Append(https://go.dev/doc/effective_go#slices) 와 같이 실제 배열(슬라이스 안에 배열을 가리키는 포인터)은 바뀔수도 있기 때문에, 결과는 반환되어야할 필요가 있다. 이 간단한 예제는

 

x := []int{1,2,3}
x = append(x, 4, 5, 6)
fmt.Println(x)

prints [1 2 3 4 5 6]. So append works a little like Printf, collecting an arbitrary number of arguments.

[1 2 3 4 5 6]을 출력한다. 그래서 append는 약간 Printf처럼 동작하고, 임의의 인자들의 수를 수집한다.

 

But what if we wanted to do what our Append does and append a slice to a slice? Easy: use ... at the call site, just as we did in the call to Output above. This snippet produces identical output to the one above.

그러나 우리의 Append가 하는 것을 하길 원하고, 슬라이스에 슬라이스를 추가하고 싶다면 어떻게 할까? 쉽다: call site(함수 인자에)...을 사용해라, 위에서(https://go.dev/doc/effective_go#Printing) Output(std.Output 함수) 호출에서 했던 것처럼. 아래 snippet(작은 예제)은 위 예제와 동일한 출력을 만든다.

 

위의 문장에서 보충설명 : 위의 custom 함수 Append와 같은 기능을 하고 슬라이스에 슬라이스를 추가하고 싶을 때를 설명하고 있다. 위에 func Println(v ...interface{}) { std.Output(2, fmt.Sprintln(v...))  // Output takes parameters (int, string) } 함수에서 했던 것처럼 ...을 사용 하라는 의미인것으로 보인다.

 

x := []int{1,2,3}
y := []int{4,5,6}
x = append(x, y...)
fmt.Println(x)

Without that ..., it wouldn't compile because the types would be wrong; y is not of type int.

...없이, 위의 예제는 타입들이 틀리기 때문에 컴파일되지 않을 것이다; 예시 : y는 int 타입이 아니다.

https://go.dev/blog/intro-generics

type Ordered interface {
    Integer|Float|~string
}


The expression ~string means the set of all types whose underlying type is string.
~string 표현식은 실제 타입이 string인 모든 타입의 집합을 의미한다.

This includes the type string itself as well as all types declared with definitions such as type MyString string.
이것은 type MyString string와 같은 정의와 함께 선언된 모든 타입들 뿐만 아니라 string타입 자신을 포함합니다.


해석 : type키워드를 사용해서 string을 MyString(Named Type)으로 선언하였다. string과 MyString은 서로 다르다.

 

s1을 string 타입처럼 사용할 수 없다.

 

하지만 ~string을 사용하면 string자신뿐만 아니라 type MyString string로 선언된 타입까지 사용할 수 있다는 뜻이다.

제네릭으로 예제를 만들어보면,

 

제네릭

Integer 인터페이스에 int앞에 tilde(~)를 안 넣어주니 오류가 나온다. MyInt는 Integer를 구현하지 않았다고 나오고 가로 안에 아마 Integer안에 int 앞에 ~를 잃어 버렸다고 한다. Integer 인터페이스 안에 int 앞에 tilde(~) 를 넣어주면 올바르게 작동할 것이다. 이렇게 Integer안에 정의한 자료형들을 underlying type도 허용하고 싶으면 앞에 tilde(~)를 넣어주면 된다.

+ Recent posts