공부일지/Web

웹 개발 공부일지 99쪽 / 내 서비스 만들기(9)

Viewee 2023. 5. 17. 06:56

시작하는 말 :

이번 포스팅은 꽤나 고군분투를 많이 한,

치열함이 묻어나는... 개발일지라서, 매우 길다.

문제 해결을 결국 해냈지만, 아침이 밝아온다.

그래서 너무나도 슬프도다.

다음에 같은 문제로 버벅거리기 싫어서, 실패 과정과 성공 과정을 자세하게 적었다.


Sveltekit & Firebase / 승인버튼 누르면, Storage 이미지를 resize 하기

먼저 오늘 개발할 것을 글로 정리해본다.

1. 내가 유저가 올린 이미지를 승인버튼을 누르면,

2. storage 에 올라와져 있는 유저의 이미지가 사이즈가 변경이되어

3. images/ueserUID/authed 폴더에 저장이 되고

4. 관리자 이미지 승인페이지에서, 이 승인된 이미지를 볼 수 있다.

ㅇㅋ 렛츠고!


1. 내가 유저가 올린 이미지를 승인버튼을 누르면,

이 부분을 어떻게 functions 에서 인식을 시킬까 생각을 해봤는데,

기존에 user db 에서 이미지 가 Authed / nonAuthed 두개로 분류되고

내가 승인 버튼을 누르면, isAuthed 변수가 true 가되고, 해당 이미지 정보가 Authed로 이동하도록 했다.

그러면, Functions 에서 인식을 할 때,

User의 images - authed 가 업데이트 되면, 이미지 리사이즈를 실행시키면 되지 않을까?

그리고 리사이즈된 이미지의 url 을 authed 의 imageURL 에 입력시키면서 마무리.

기존 썸네일 기능은, 파일이 storage 에 업로드 되었을 때!

실행된다.

관련 기능에 대한 정보를 얻기위해, firebase 깃허브 돌아다니다가 우연히 이미지resize 에 대한 예제 발견!

오오?

Sharp 라이브러리 도 가능하겠다만,

여기 페이지에서 , 보면,

Extensions 에서, Resize Image 툴을 확인할 수 있었다.

신기하네

이것도 한번 해본다.

확장프로그램을 설치하는 페이지에 들어왔는데,

변경할 이미지 크기나 저장할 위치, 사용할 이미지의 위치 등을 웹에서 설정할 수 있었다.

Extentions 는 아예 세팅을 하고 들어가는? 느낌?

각 항목에 대해서 ? 에 마우스를 올리면 세부 설명을 볼 수 있어서 좋았다.

근데 굳이 sharp 라이브러리 안쓰고 이걸 써야하나 의문이 들기도했다.

Public(공개) image url 에 대한 보안문제.

근데 보다가 발견한게

Make resized images pubulic 라는 항목이었는데

순간 충격을 받았다.

왜냐면 지금까지 나는 storage 에 저장된 이미지의 url 을

user db 에 저장해 놓고, 그걸 불러와서 웹에서 표시하고 있었는데

이러면 보안에 헛점이 생기는 거였다.

아무나 이 이미지 주소를 퍼가서 자신의 블로그에서 사용한다면,

그때마다 내 storage의 읽기 가 발생하여, 비용이 과다청구 될 수 있기 때문이다.

GPT에게 이 부분에대한 고견을 물어봤다.

하하....

큰일날뻔했네...ㅋㅋㅋ..

인증된 사용자일 경우에만 이미지를 읽을 수 있도록, 구조를 개선해야겠다.

user db 에 imageURL 을 저장하면 안되는거구나;;;

하..ㅋㅋ...

Cache-Control

이런 항목도 있었는데, 뭔지 궁금해서, GPT에게 물어봤다.

아?

와?!!

이런게 있었어??

이걸 쓰면 유저의 브라우저의 캐시에 저장되기 때문에,

다시 이미지를 볼 때마다 굳이 storage 에서 읽기 요청이 발생하지 않는거 아녀?

GPT 굿

Cache-Control 이거 매우 중요한거였구나...ㅇㅎ...

하긴 인증된 유저라도, 새로고침을 무한정 해버리면 그만큼 읽기 요청이 무한정 발생하는거니까..

이부분도 고려를 해야겠다.

할일 목록에 적어놔야지..ㄷㄷ...

.


 

변환된 이미지의 퀄리티도 정할 수 있었다.

 
 
 
 
 
 
 
 
 
 
 

설정값들 캡쳐.

생각보다 설정할 것들이 많아서 놀라웠고

보안 관련된 항목들도 많아서 신기했다.

설치중...

신기하네

funtions 에서는 위의 코드로 바로 extentions이 실행이 되고,

이제 내가 설정했던 폴더에 파일을 저장하면,

리사이징된 이미지가 생성이 된다.

근데 살짝 소름돋았던게,

functions 에 내가 썸네일 만드는 기능을 추가해놨었는데,

이게 파일이 storage 에 추가 되었을 때 실행되는거라서,

extiontions 기능을 통해 썸네일이 생성되었을 때, 그 썸네일의 썸네일을 생성하고 다시 생성된 썸네일의 썸네일을 또 생성하고...

계속 서로 맞물려서

두 함수가 무한루프를 돌 뻔했다.ㄷㄷ...

다행히 3번정도 반복하고 중단되었긴 한데...

왜 중단되었는지는 모르겠다만...

이게 그 테스트는 emulator 를 사용하는 이유인,

무한루프로 인한 요금 과다청구의 위험이었을 거 같다. ㄷㄷㄷ...

ㅎㄷㄷ.. 개소름돋네..


9kB 용량의 작은 이미지 파일 크기 조차도 썸네일에서는 확실히 줄긴하더라.

확장 프로그램의 소개글 읽어봄. 저런 장점을 얘기한다.

음 ... 확실히 extention 을 이용하면, 코드로 설정해줘야하는 부분들을,

하나하나 웹에서 옵션 고르듯이 할 수 있어서, 빠르고 편하겠구나 싶더라.

하.. 근데 나는 워터마크 기능도 필요한데?

리사이즈 확장 프로그램, 설명 페이지 들어가서 읽어보니,

정말 단순히 썸네일 만들어주는 정도의 기능만 가능하더라.

아쉽지만 이건 못쓰겠다 싶음.

다시 Sharp 로 돌아간다.

Sharp 라이브러리가 좀 더 궁금해서, 구글링 하다 발견한 포스팅인데,

너무 정리가 잘되어있어서, 북마크에 추가까지 했다.

//

이 블로그 구경하면서, 블로그가 너무 이쁘더라.

깔끔한 개발자분 성격이 딱 보임.

티스토리는 블로그 디자인이 정말 자유롭구나 하는 생각도 들었다. wow...

그냥 개인홈페이지 수준임.

//

무튼.

sharp 라이브러리에 대한 자세한 사용법들이 한국어로 안내되어있어서, 넘 좋았다.

이거 보고 뚜닥거려봐야지.

sharp 를 쓰면 워터마크까지 가능하더라.

음... 그래서 굳이 extension 을 써야하나 싶었다.

혹시 extension 에 워터마크 되는거도 있나 하고 확장프로그램 마켓을 검색해보는데

아쉽게도 없었다.

검색 바에 텍스트 쳐나갈 때마다 바로바로 밑에 결과값이 보여져서, 너무 편하다는 생각이 들었다.

엔터를 안쳐도 된다는게. 이렇게 편했나?

내 서비스에도 검색바가 들어가야하는데,

이렇게 바로바로 뜨도록해야겠다는 생각이 들었다.

이후 개발할 때 필요한 기능이 있으면,

관련 확장프로그램이 있는지 한번 찾아보고 있으면 활용하면 좋겠다.


위 포스팅은,

이번에 내가 사용하고 있는 Firebase가 서버리스 인데,

서버리스에 대한 개념을 명확히 정리하고싶어서 읽어봤다.

너무 정리가 잘되어 있어서 좋았다.

서버리스는 서버가 없는 것이아닌, 관리할 필요가 없다는 것!

 


이제 다시돌아 와서, 승인을 하면, 이미지를 리사이징 하고, 워터마크 기능을, 넣는 것을 구현해보자.

Firebase Functions - storage 의 내가 지정한 경로에만 파일이 업로드 되었을 때 functions 트리거가 일어나는 방법?

우선 현재 function이 파일이 storage 업로드 되었을때, 실행되는데, 썸네일을 만들때도 storage 에 저장이되는 것이 때문에 이때도 불필요하게 트리거가 발생한다.

이렇게 무분별하게 실행되면, 그만큼 비용이 나가는 것이기 때문에,

특정 경로에 이미지가 업로드 되었을 때만 실행되도록 하고 싶었다.

onObjectFinalized 함수 안에서 해결하면, 의미가 없는게 이미 function에서 호출이 발생한거라서,

함수에서부터, 조건을 넣어서 실행되도록 하고 싶었다.

GPT에게 물어봤다.

라고.. ㅇㅇ.. 없구나

그래서 storage 에 아무경로에나 업로드가 발생하면 트리거는 일어나더라도,

함수안에서, 조건문을 넣어서, 해당 경로에 저장된게 아니라면 썸네일 작업이 진행되지 않도록 했다.

근데 이걸로 마무리는 짓지 못했다.

개발 중간에, 심각한 보안문제를 발견하여,

꼭 해결하고넘어가야 했어서,

이미지 리사이징은 다음 포스팅에서 작업할 예정이다.


[보안 / Firebase] ★★★★★ 심각한 User DB 보안문제 - user 권한 자격 부여 관련

작업을 하다가, 문득 싸늘함을 느꼈다.

유저의 db 구조는 위와 같이 구성되는데,

문제는, 로그인한 유저이기만 하면

자신의 db는 마음껏 읽고 쓸수 있다는 것이다.

이것은 지금 내 db구조에서는 상당한 보안문제를 일으키는데,

바로, 승인된 이미지와, 유저의 권한수준 상태 또한 유저가 조작할 수 있다는 것이었다.

내가 승인하지 않아도 승인된 이미지로 만들어버릴 수 있고,

관리자가 아닌데도 관리자로 만들 수 있었다.

와.. 이거는 너무 심각한 허점이었다.

자바스크립트를 조작해서 DB에 업로드를 하면

누구나 자신의 계정을 관리자 계정으로 만들 수 있는것이다.

그래서, 예민한 정보들은, 유저가 직접 수정할 수 없도록, 따로 분리를 하여 관리할 필요성을 느꼈다.

GPT에게 물어봤다.

아.. 필드 수준에서는 접근제한이 불가능하구나.

그럼...서버함수를 사용한다고 하면, 클라이언트에서 요청을 서버로보낼때,

트리거를 발생시켜서 검사를 하고 통과시키기..랑

서브컬렉션을 사용하는 것.

서브컬렉션을 사용하는 것이 더 직관적이고, 간단하고, 서버를 덜 사용할 것 같았다.

//

그렇게 많은 고난을 거치고 .... 완성.

위와같이 nonSensitive 라는 subcollection 을 구성하였다.

유저의 권한부여 수준과 같은 민감한 정보는 Sensitive 라는 이름의 subcollection 로 저장할거고,

이때 쓰기는 관리자만 할 수 있도록 규칙을 설정할 거다. 유저는 읽기만 허용된다.

그렇게 만든 규칙 모습.

 

그런데 중복되는 코드가 많아서, 너무 지저분하다. 관리도 어렵고.

중복되는 부분은 커스텀 함수를 통해 깔끔하게 정리할 수 있다는걸 알고 있었기에,

이거는 GPT에게 정리해달라고 했다.ㅋㅋㅋ

내가안해 이런거는!

안할거라곢!!!!ㅋㅋㅋㅋㅋㅋ


우선 커스텀 함수 부분이 설명되어있는 공식설명서 페이지.

//

서브콜렉션 데이터에 접근하는 참조주소를 만드는 방법은, 아래와 같다.


어쨌든.

GPT에게 물어보고 답변받음.

굿.

그렇게 정리된 코드 모습

일 잘한다 GPT! 고맙다!

는 개뿔....

근데.. 왜.... 안되는거지...... ...ㅠㅠㅠ

왜안되나 또, 한참. 엄청 찾다가, 문제점 발견함.

//

으아아아

/

GPT 한테 해당부분 따지니까,

이제서야 올바르게된 코드를 내뱉는 GPT...

GPT 이넘이 함수를 만들때, 매개변수를 고려 안 하고 나한테 알려줬더라고..

 

아니;; 야! 첨부터 저렇게 제대로 알려주라고!!

//

GPT는 아직 완벽하지 않다..

//

암튼... 정리된 규칙을 설명하자면,

//

match /users/{uid} 문서 안에 들어있는 SensitivenonSensitive 라는 서브콜렉션에 대한 규칙을 보여준다.

각 서브콜렉션은 읽기 쓰기 권한이 다르게 들어가는데,

- Sensitive : 읽기는 유저만, 쓰기는 관리자만

- nonSensitive : 읽기, 쓰기 모두 유저와 관리자 가능.


이렇게 해서 유저의 민감한 정보는 관라자만 다룰 수 있도록 하는데 성공했다.

이게 user db 구조를 다시 짜는거다보니까, 프론트엔드 단 코드들도 왕창 손봐줘야했다.

하... 아침이 밝아오네.

이하는 작업하다가 막혔던 부분들 해결하고, 정리한거.

...

보안문제가 매우 심각했어서... 이거하다보니...

이미지 리사이징이랑 워터마크 하는거는 내일 해야겠다.

자자... 하..

고생했따. 내 자신.


Sveltekit / svelte 파일에서 참조한 js 파일을 수정할 때 주의할점

Sveltekit 에서 svelte 파일에서 참조한 js 파일은 수정할 때 주의할점은,

npm run dev 를 통해 서버가 구동되고 있는 동안,

js 파일을 수정하고 저장하면, 서버에 반영되지 않는다.

svelte 파일을 수정하고 저장하면, 서버를 다시켜지 않아도 반영된다.

하지만, js 파일은 서버를 끄고 다시 켜줘야 적용된다.

나중에 콘솔에러 분석하다가 알았네..

이것을 몰라가지고 아. 왜 안되지 ? 왜 안되지? 를 108번은 한 거같다 슈바알.

답답해디져서, 108요괴로 변할뻔.

Firestore Rules 규칙 설정할 때 subCollection 규칙관련

여러번 시도하다가 알게되어, 까먹지 않기 위해 적는다. ㅠㅠ

이렇게 상위 collection 에 read 규칙을 사용하면 하위 모든 subCollection 의 문서들을 읽을 수 있을까?

자 읽어보자.

정답은 ?

노!

subCollection 의 데이터를 읽고 싶다면,

이렇게 subCollection 에 정확하게 read 조건을 부여해줘야한다.

GPT가 알려주긴했는데, 하도 거짓부렁을 할 때가 많아,

신뢰를 못하겠어서, 몇번 직접 시도해봄.

Firestore / subCollection이 있는 Collection 문서를 읽을 때 .data() 값 결과

users / userUID / Sensitive / userData / nonSensitive / userData

이렇게 users 콜렉션 안에 Sensitive, nonSensitive 서브콜렉션이 있다고 할 경우,

위와같은 서브콜렉션이 아닌 참조주소 값으로,

data( ) 를 사용해서 값을 불러오면, 그 값은 undefine 이 된다.

이거때매 한 3시간 해멘거같다.

구글링도 해보고 혼자 찝적거리다가 도저히 모르겠어서,

최종적으로 GPT에게 물어봤다가 해결...

ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

그냥 처음부터 GPT한테 물어볼걸...........................................아.....................................................................................................시이이이이바....

서브콜렉션이 있을 때, data() 에 어떨땐 객체들어오고 어떨땐 undefine 나오고 그래서 엄청 헤맸다.


Svelte 의 Store 변수 에 Firestore db값 받아서 넣을 때 주의점.

firestore 에서 유저 정보를 svelte의 store 변수에 저장을 하고, 그걸 페이지에서 로드해서 보여주는 구조인데,

유저 정보를 받는데 시간이 걸린다.

그동안 데이터는 존재하지 않는 상태이기 때문에, 페이지에서 오류가 발생한다.

때문에, 값이 들어오기전에는, 페이지에 해당 데이터값을 사용하면 안된다.

값이 들어오면, 페이지를 표시하도록 위와 같이 if 문을 걸어줘서 해결했다.

그리고

중요한 점은 svelte의 반응성 기능(reactive) $: { } 를 사용해서,

$authUser 라는 스토어 값의 변화를 지속적으로, 구독하고 있는것.

위 짤을 보면,

페이지를 로드할 때,

해당 콘솔 값이 처음에는 undefined로 나오지 않고 있는 것을 볼 수 있다.

나중에 db를 읽고나서, 페이지 내용이 업데이트 된다.

끝!