hey-api / openapi-ts

✨ Turn your OpenAPI specification into a beautiful TypeScript client
https://heyapi.vercel.app
MIT License
923 stars 72 forks source link

Localhost Self Signed SSL cert fails to download swagger.json #276

Open warrenbuckley opened 4 months ago

warrenbuckley commented 4 months ago

Description

I have a .NETCore webserver hosting/serving a swagger file that is running on localhost over https with a self signed SSL certificate. But trying to do so I get the following error.

> client@0.0.0 openapi-ts
> openapi-ts --input https://localhost:44312/umbraco/swagger/AccessibilityReporter/swagger.json --output src/Api

{
  stack: 'JSONParserError: Error downloading https://localhost:44312/umbraco/swagger/AccessibilityReporter/swagger.json \n' +
    'fetch failed\n' +
    '    at download (C:\\Code\\Contrib\\umbraco-accessibility-reporter\\src\\AccessibilityReporter\\client\\node_modules\\@apidevtools\\json-schema-ref-parser\\dist\\lib\\resolvers\\http.js:113:15)\n' +
    '    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)',
  code: 'ERESOLVER',
  name: 'ResolverError',
  message: 'Error downloading https://localhost:44312/umbraco/swagger/AccessibilityReporter/swagger.json \n' +  
    'fetch failed',
  source: 'https://localhost:44312/umbraco/swagger/AccessibilityReporter/swagger.json',
  path: null,
  toJSON: [Function: toJSON],
  footprint: 'null+https://localhost:44312/umbraco/swagger/AccessibilityReporter/swagger.json+ERESOLVER+Error downloading https://localhost:44312/umbraco/swagger/AccessibilityReporter/swagger.json \n' +
    'fetch failed',
  toString: [Function: toString]
}

OpenAPI specification (optional)

{
    "openapi": "3.0.1",
    "info": {
        "title": "Accessibility Reporter Package API",
        "version": "1.0"
    },
    "paths": {
        "/umbraco/accessibilityreporter/api/v1/config/current": {
            "get": {
                "tags": [
                    "Config"
                ],
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "oneOf": [
                                            {
                                                "$ref": "#/components/schemas/NodeSummary"
                                            }
                                        ]
                                    }
                                }
                            },
                            "text/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "oneOf": [
                                            {
                                                "$ref": "#/components/schemas/NodeSummary"
                                            }
                                        ]
                                    }
                                }
                            },
                            "text/plain": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "oneOf": [
                                            {
                                                "$ref": "#/components/schemas/NodeSummary"
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "The resource is protected and requires an authentication token"
                    }
                },
                "security": [
                    {
                        "Backoffice User": []
                    }
                ]
            }
        },
        "/umbraco/accessibilityreporter/api/v1/pages": {
            "get": {
                "tags": [
                    "Directory"
                ],
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "oneOf": [
                                            {
                                                "$ref": "#/components/schemas/NodeSummary"
                                            }
                                        ]
                                    }
                                }
                            },
                            "text/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "oneOf": [
                                            {
                                                "$ref": "#/components/schemas/NodeSummary"
                                            }
                                        ]
                                    }
                                }
                            },
                            "text/plain": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "oneOf": [
                                            {
                                                "$ref": "#/components/schemas/NodeSummary"
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "The resource is protected and requires an authentication token"
                    }
                },
                "security": [
                    {
                        "Backoffice User": []
                    }
                ]
            }
        }
    },
    "components": {
        "schemas": {
            "NodeSummary": {
                "required": [
                    "docTypeAlias",
                    "guid",
                    "id",
                    "name",
                    "url"
                ],
                "type": "object",
                "properties": {
                    "guid": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "id": {
                        "type": "integer",
                        "format": "int32",
                        "readOnly": true
                    },
                    "name": {
                        "type": "string",
                        "readOnly": true
                    },
                    "docTypeAlias": {
                        "type": "string",
                        "readOnly": true
                    },
                    "url": {
                        "type": "string"
                    }
                },
                "additionalProperties": false
            }
        },
        "securitySchemes": {
            "Backoffice User": {
                "type": "oauth2",
                "description": "Umbraco Authentication",
                "flows": {
                    "authorizationCode": {
                        "authorizationUrl": "/umbraco/management/api/v1/security/back-office/authorize",
                        "tokenUrl": "/umbraco/management/api/v1/security/back-office/token",
                        "scopes": {}
                    }
                }
            }
        }
    }
}

Configuration

openapi-ts --input https://localhost:44312/umbraco/swagger/AccessibilityReporter/swagger.json --output src/Api

System information (optional)

OS: Windows 11 NPM: 10.2.4 Node: 20.11.0

warrenbuckley commented 4 months ago

Investigating a little myself, it seems you do not do any fetching of the file and are using @apidevtools/json-schema-ref-parser

So if this package can support passing config, flag to support it would be fab

Now to dig down the rabbit hole of that NPM package's repo 😄

warrenbuckley commented 4 months ago

OK seems like can fetch can use rejectUnauthorized: false https://stackoverflow.com/a/72569955

Now to find the fetch or HTTP call to get the JSON/YML from inside this other package

warrenbuckley commented 4 months ago

Bingo found it https://github.com/APIDevTools/json-schema-ref-parser/blob/main/lib/resolvers/http.ts#L120-L125

Leaving my notes here for anyone else reading along, but for now I need sleep.

jordanshatford commented 4 months ago

@warrenbuckley thanks for the bug report. Is this a bug with the underlying json-schema-ref-parser package or ours?

mrlubos commented 4 months ago

Thanks for the thorough investigation @warrenbuckley!

warrenbuckley commented 4 months ago

@jordanshatford and @mrlubos its with the dependant package from what I can tell.

mrlubos commented 4 months ago

@warrenbuckley to help us prioritise, how critical is this? Does it prevent you from using the package altogether?

warrenbuckley commented 4 months ago

@mrlubos its an annoyance, as I think I can try to get it to generate a client from localhost using HTTP and without SSL, but it would be nice if it just worked.

If I manage to do a PR to the other package, would you be happy for me to contribute a fix here as well ?

mrlubos commented 4 months ago

@warrenbuckley you mean JSON schema ref parser? Totally, we spoke about this with Jordan and think it's a reasonable expectation to have this working. We could even fork that package and depend on the fork if they're slow to review changes

Terit commented 4 months ago

As a temporary work around you should be able to use NODE_TLS_REJECT_UNAUTHORIZED=0 openapi-ts.

warrenbuckley commented 4 months ago

@Terit I was not able to get that to work for me.

NPM Script

"openapi-ts": "NODE_TLS_REJECT_UNAUTHORIZED=0 openapi-ts --input https://localhost:44312/umbraco/swagger/AccessibilityReporter/swagger.json --output src/Api"

Error Back from Console

> accessibility-reporter-client@0.0.0 openapi-ts
> NODE_TLS_REJECT_UNAUTHORIZED=0 openapi-ts --input https://localhost:44312/umbraco/swagger/AccessibilityReporter/swagger.json --output src/Api

'NODE_TLS_REJECT_UNAUTHORIZED' is not recognized as an internal or external command,
operable program or batch file.

image

Terit commented 4 months ago

@warrenbuckley Try it with cross-env. It's allowed me to keep my sanity working on Windows with a Linux CI process.

warrenbuckley commented 4 months ago

OK thanks @Terit 🥰

For anyone else reading this issue/thread

Install cross-env if your on Windows npm install --save-dev cross-env

Then updated my script to

"openapi-ts": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 openapi-ts --input https://localhost:44312/umbraco/swagger/AccessibilityReporter/swagger.json --output src/Api"

Sulray commented 3 months ago

As a temporary work around you should be able to use NODE_TLS_REJECT_UNAUTHORIZED=0 openapi-ts.

You saved my day with that @Terit 🙏 Do you know if now there is a way to manage self-signed/company-signed certificate properly ?

Terit commented 3 months ago

@Sulray I think the library would have to add a flag to set a path to your cert. That would allow them to do something like this:

 let opts = {
    method: 'GET',
    hostname: "localhost",
    port: listener.address().port,
    path: '/',
    ca: fs.readFileSync("cacert.pem")
  };

  https.request(opts, (response) => { }).end();

I doubt @mrlubos would prioritize that as the Node flag is a sufficient workaround for most cases.

mrlubos commented 3 months ago

You're spot on @Terit 😀 it doesn't seem to be a huge pain for people right now given the workaround

Kalshu commented 1 month ago

Just to say thanks for this thread !